Contributing
Setup
git clone git@github.com:Dxsk/repos-manager.git
cd repos-manager No build step needed - it's pure Bash.
Running tests
# Install bats
sudo pacman -S bats # Arch
brew install bats-core # macOS
# Run all tests
bats tests/*.bats Test coverage
| Module | Tests | What's covered |
|---|---|---|
cli | 8 | Version, help, unknown commands, provider routing |
flags | 11 | All flag parsing combinations |
match | 9 | Patterns, wildcards, .repos-filter, .repos-ignore |
config | 8 | Load/init config.json, tilde expansion, protocol |
providers | 9 | SSH/HTTPS URL extraction for all 5 providers |
status | 5 | Clean, dirty, ahead, multiple repos detection |
sync | 4 | Clone, update, skip dirty, clone failure |
| Total | 60 |
Linting
shellcheck -x repos-manager.sh lib/*.sh sourceme.bash CI pipeline
Every push triggers 4 checks:
| Check | Tool | What it does |
|---|---|---|
| Bash lint | ShellCheck | Static analysis of all .sh files |
| Tests | Bats | Runs the full 60-test suite |
| Links | Lychee | Validates URLs in all markdown files |
| Shell compat | zsh + fish | Syntax checks on sourceme files |
All checks must pass before merging.
Adding a provider
The provider system is modular. Each provider is a single file in lib/ implementing 4 functions:
Step 1 - Create the provider file
Create lib/yourprovider.sh:
#!/usr/bin/env bash
# YourProvider (uses yourcli)
yourprovider_login() {
yourcli auth login
}
yourprovider_list_repos() {
# Must return a JSON array of objects with:
# nameWithOwner, sshUrl, url
yourcli repo list --json ...
}
yourprovider_get_clone_url() {
local repo_json="$1"
if $USE_HTTPS; then
echo "$repo_json" | jq -r '.url'
else
echo "$repo_json" | jq -r '.sshUrl'
fi
}
yourprovider_get_full_name() {
echo "$1" | jq -r '.nameWithOwner'
} Step 2 - Register it
In repos-manager.sh:
- Source it:
source "${REPOS_MANAGER_LIB}/yourprovider.sh" - Add to
VALID_PROVIDERS - Add to
detect_providers() - Add to
cmd_sync()host mapping - Add to
cmd_sync_all()providers array - Add case in
main()
Step 3 - Add tests
In tests/providers.bats:
@test "yourprovider: get ssh clone url" {
USE_HTTPS=false
local json='{"nameWithOwner":"user/repo","sshUrl":"git@host:user/repo.git","url":"https://host/user/repo"}'
local result
result=$(yourprovider_get_clone_url "$json")
[[ "$result" == "git@host:user/repo.git" ]]
} Step 4 - Document
Update readme.md, site/src/docs/providers.md, and the glossary.
Project structure
$ tree repos-manager/
repos-manager/
├── repos-manager.sh # Entry point, CLI routing
├── Makefile # Install/uninstall
├── flake.nix # Nix flake (optional)
├── sourceme.bash # Bash shell integration
├── sourceme.zsh # Zsh shell integration
├── sourceme.fish # Fish shell integration
├── lib/
│ ├── log.sh # Colors, log functions
│ ├── flags.sh # Flag parsing
│ ├── config.sh # Config file, sourceme gen
│ ├── match.sh # Pattern matching, filter/ignore
│ ├── sync.sh # Core sync engine (parallel)
│ ├── status.sh # Status command
│ ├── update.sh # Self-update
│ ├── github.sh # GitHub provider
│ ├── gitlab.sh # GitLab provider
│ ├── forgejo.sh # Forgejo/Gitea provider
│ ├── bitbucket.sh # Bitbucket provider
│ └── radicle.sh # Radicle provider
└── tests/
├── test_helper.bash # Shared test utilities
├── cli.bats # CLI tests
├── flags.bats # Flag parsing tests
├── match.bats # Pattern matching tests
├── config.bats # Config tests
├── providers.bats # Provider URL tests
├── status.bats # Status tests
└── sync.bats # Sync tests Pull requests
| Rule | Details |
|---|---|
| Branch from | develop |
| Scope | One feature per PR |
| Tests | Must pass (bats tests/*.bats) |
| Lint | Must pass (shellcheck -x) |
| Commits | Conventional style (feat:, fix:, docs:, test:) |