PowerShell-based dependency management tool that checks out multiple Git repositories to specified versions. Module architecture: RepoHerd.psm1 (functions + Invoke-RepoHerd entry point) + RepoHerd.ps1 (thin wrapper for script-based usage). Version 9.1.0, published on PowerShell Gallery, by LS Instruments AG.
# Via PowerShell Gallery (recommended)
Install-Module RepoHerd
Invoke-RepoHerd # defaults to dependencies.json in CWD
Invoke-RepoHerd -InputFile "path/to/deps.json" # custom config
Invoke-RepoHerd -DryRun # preview without executing
Invoke-RepoHerd -EnableDebug -EnableErrorContext # full debug output
Invoke-RepoHerd -OutputFile result.json # structured JSON output
# Via script (manual download / cloned repo)
.\RepoHerd.ps1 # defaults to dependencies.json in script dir
.\RepoHerd.ps1 -InputFile "path/to/deps.json"Key parameters: -InputFile, -CredentialsFile, -DryRun, -EnableDebug, -DisableRecursion, -MaxDepth (default 5), -ApiCompatibility (Strict|Permissive), -DisablePostCheckoutScripts, -EnableErrorContext, -OutputFile (structured JSON results)
# Install Pester if needed
Install-Module Pester -Force -MinimumVersion 5.0
# Unit tests — fast, no network required
Invoke-Pester ./tests/RepoHerd.Unit.Tests.ps1 -Output Detailed
# Integration tests — requires network access to GitHub test repos
Invoke-Pester ./tests/RepoHerd.Integration.Tests.ps1 -Output DetailedTest configs in tests/ are organized in subdirectories, each containing a dependencies.json:
.\RepoHerd.ps1 -InputFile tests/semver-basic/dependencies.json
.\RepoHerd.ps1 -InputFile tests/agnostic-recursive/dependencies.json
.\RepoHerd.ps1 -InputFile tests/api-incompatibility-agnostic/dependencies.json -ApiCompatibility StrictThere are 17 test cases across 16 test configs covering SemVer, Agnostic, API incompatibility (Permissive + Strict), custom paths, post-checkout scripts, and recursive dependencies. See docs/testing_infrastructure.md for the full test architecture.
Important: Integration tests depend on 5 external GitHub test repos. Modifying those repos will break the tests. See docs/testing_infrastructure.md for details.
- Module:
RepoHerd.psm1— all function definitions (~36 functions) includingInvoke-RepoHerd(main entry point) - Script wrapper:
RepoHerd.ps1— thin wrapper that imports the module and delegates toInvoke-RepoHerd(defaults to script directory for paths) - Manifest:
RepoHerd.psd1— module metadata, exported functions - Two dependency resolution modes: SemVer (recommended, automatic version resolution) and Agnostic (explicit tag-based)
- Configuration: JSON files —
dependencies.jsonfor repos,git_credentials.jsonfor SSH keys - Recursive processing: walks dependency trees with conflict detection, max depth configurable
- SSH: Cross-platform — PuTTY/Pageant on Windows (
.ppk), OpenSSH on macOS/Linux - Post-checkout scripts: optional PowerShell scripts run after successful checkouts
- Structured output:
-OutputFilewrites JSON (schema 1.0.0) with per-repo results, post-checkout script tracking, andrequestedByparent chain
- API compatibility in Agnostic mode: In Permissive mode (default), version/tag conflicts during recursive checkout are resolved silently by picking the best available tag. In Strict mode, any tag mismatch is an error. This is controlled by
-ApiCompatibility(CLI) or"API Compatibility"(per-repo JSON field). - SemVer major version conflicts: SemVer mode always rejects cross-major version incompatibilities regardless of the API compatibility setting, since different major versions imply breaking API changes by SemVer convention.
- SSH transport is platform-specific: On Windows, PuTTY/plink with
.ppkkeys and Pageant is used. On macOS/Linux, OpenSSH is used viaGIT_SSH_COMMAND="ssh -i <key> -o IdentitiesOnly=yes", which specifies keys per-host without requiring~/.ssh/configchanges or a runningssh-agent. Why PuTTY on Windows: We attempted OpenSSH on Windows but hit a specific failure: when a parent repository is cloned via HTTPS and has submodules accessed via SSH, thegit submodule updateprocess on Windows did not reliably inheritGIT_SSH_COMMAND/GIT_SSHenvironment variables, causing SSH submodule fetches to fail silently or hang. PuTTY/plink with Pageant (which manages keys via a system-tray agent process rather than environment variables) was the only reliable workaround. This issue was not reproduced on macOS/Linux, where environment variable inheritance across git subprocess forks works correctly.
- PowerShell 7.6 LTS required (
#Requires -Version 7.6) - Function names: PascalCase Verb-Noun using approved PowerShell verbs (e.g.,
Test-GitInstalled,ConvertTo-VersionPattern,Get-SemVersionIntersection) - Documentation: comment-based help blocks (
.SYNOPSIS,.DESCRIPTION,.PARAMETER) on all functions - Logging: use
Write-Logwith levels: Info, Warning, Error, Debug, Verbose - Error handling: wrap operations in
Invoke-WithErrorContext -Context "description" -ScriptBlock { ... } - Module state:
$script:prefix for module-scoped variables (e.g.,$script:RepositoryDictionary,$script:DryRun) - Initialization:
Initialize-RepoHerdsets module state; called internally byInvoke-RepoHerd - Publishing: before any
Publish-Module, always test the fullInstall-Module->Invoke-RepoHerdround-trip - CHANGELOG: follows Keep a Changelog format with SemVer versioning
RepoHerd.ps1 # Script wrapper (~70 lines), delegates to Invoke-RepoHerd
RepoHerd.psm1 # Module with all functions including Invoke-RepoHerd (~2750 lines)
RepoHerd.psd1 # Module manifest
CHANGELOG.md # Version history
README.md # Comprehensive user documentation
docs/
developer_guide.md # Developer setup, testing, debugging
comparison_guide.md # vs Google Repo Tool
migration_guide.md # Migration strategies
test_repositories_reference.md # Test repo tags and dependency data
testing_infrastructure.md # Test architecture, constraints, and categories
examples/ # 7 example dependency JSON configs
tests/ # Pester test files + 16 test config subdirectories
RepoHerd.Unit.Tests.ps1 # 65 unit tests (no network)
RepoHerd.Integration.Tests.ps1 # 18 integration tests (needs network)
semver-basic/dependencies.json # Test configs in subdirectories
agnostic-recursive/dependencies.json # (16 subdirectories total)
api-incompatibility-*/dependencies.json
tasks/
BACKLOG.md # Planned features, enhancements, bugs
DONE.md # All completed GitHub issues with summaries
- SemVer mode: uses
"Dependency Resolution": "SemVer"and"Version": "x.y.z"fields. Supports floating versions ("2.1.*","2.*") - Agnostic mode: uses
"Tag"and"API Compatible Tags"fields for explicit version control - Repository Dictionary (
$script:RepositoryDictionary): central tracking structure for all repositories being processed across the dependency tree - Immutable config: once a repo's resolution mode is set, it cannot change during processing
Features, bugs, and enhancements are tracked in tasks/BACKLOG.md (planned) and tasks/DONE.md (completed), mirroring GitHub issues.
When the user requests a new feature or reports a bug:
- Draft a properly formatted issue description (title + body in GitHub markdown)
- Ask the user for confirmation before creating
- Create the issue on GitHub using
gh issue create - Update
tasks/BACKLOG.mdwith the issue number and description - When implemented, move the entry from
BACKLOG.mdtoDONE.mdwith a summary
When committing a fix or feature, reference the GitHub issue in the commit message (Fixes #N or Refs #N)