{"id":48684041,"url":"https://github.com/klauern/ownershit","last_synced_at":"2026-04-11T03:47:42.217Z","repository":{"id":41768675,"uuid":"236231038","full_name":"klauern/ownershit","owner":"klauern","description":null,"archived":false,"fork":false,"pushed_at":"2026-01-19T12:56:08.000Z","size":1051,"stargazers_count":0,"open_issues_count":10,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-11T03:47:37.947Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/klauern.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2020-01-25T21:16:40.000Z","updated_at":"2025-10-09T16:04:35.000Z","dependencies_parsed_at":"2024-02-18T01:29:32.132Z","dependency_job_id":"363eb8a2-d41a-49cd-84e2-af9d207845f8","html_url":"https://github.com/klauern/ownershit","commit_stats":{"total_commits":189,"total_committers":7,"mean_commits":27.0,"dds":0.1164021164021164,"last_synced_commit":"fba778f93add4ca0a62db2bacb81f789c87fb75f"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/klauern/ownershit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauern%2Fownershit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauern%2Fownershit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauern%2Fownershit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauern%2Fownershit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/klauern","download_url":"https://codeload.github.com/klauern/ownershit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauern%2Fownershit/sbom","scorecard":{"id":334760,"data":{"date":"2025-08-11","repo":{"name":"github.com/klauern/ownershit","commit":"5e9d73d2c71bb18fd5699f267b6d097ac19b783e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.6,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"17 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/19 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/security.yml:55","Info: jobLevel 'actions' permission set to 'read': .github/workflows/security.yml:56","Warn: no topLevel permission defined: .github/workflows/golang.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: topLevel 'contents' permission set to 'read': .github/workflows/security.yml:13","Warn: topLevel 'security-events' permission set to 'write': .github/workflows/security.yml:14","Info: topLevel 'actions' permission set to 'read': .github/workflows/security.yml:15","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":1,"reason":"dependency not pinned by hash detected -- score normalized to 1","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/golang.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/golang.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/golang.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/golang.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/golang.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/golang.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/golang.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/golang.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/security.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/security.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:63: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/security.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:66: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/security.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/security.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:84: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/security.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:94: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/security.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/security.yml:97: update your workflow using https://app.stepsecurity.io/secureworkflow/klauern/ownershit/security.yml/main?enable=pin","Warn: goCommand not pinned by hash: .github/workflows/golang.yml:38","Warn: goCommand not pinned by hash: .github/workflows/security.yml:79","Warn: goCommand not pinned by hash: .github/workflows/security.yml:33","Warn: goCommand not pinned by hash: .github/workflows/security.yml:36","Info:   0 out of  13 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned","Info:   1 out of   5 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"CII-Best-Practices","score":2,"reason":"badge detected: InProgress","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.6.0 not signed: https://api.github.com/repos/klauern/ownershit/releases/226865232","Warn: release artifact v0.5.3 not signed: https://api.github.com/repos/klauern/ownershit/releases/142479548","Warn: release artifact v0.5.2 not signed: https://api.github.com/repos/klauern/ownershit/releases/142479464","Warn: release artifact v0.5.1 not signed: https://api.github.com/repos/klauern/ownershit/releases/142479398","Warn: release artifact v0.3.4 not signed: https://api.github.com/repos/klauern/ownershit/releases/35709216","Warn: release artifact v0.6.0 does not have provenance: https://api.github.com/repos/klauern/ownershit/releases/226865232","Warn: release artifact v0.5.3 does not have provenance: https://api.github.com/repos/klauern/ownershit/releases/142479548","Warn: release artifact v0.5.2 does not have provenance: https://api.github.com/repos/klauern/ownershit/releases/142479464","Warn: release artifact v0.5.1 does not have provenance: https://api.github.com/repos/klauern/ownershit/releases/142479398","Warn: release artifact v0.3.4 does not have provenance: https://api.github.com/repos/klauern/ownershit/releases/35709216"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":7,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 3 commits out of 19 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T04:27:15.756Z","repository_id":41768675,"created_at":"2025-08-18T04:27:15.756Z","updated_at":"2025-08-18T04:27:15.756Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31668050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"online","status_checked_at":"2026-04-11T02:00:05.776Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-11T03:47:39.653Z","updated_at":"2026-04-11T03:47:42.203Z","avatar_url":"https://github.com/klauern.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ownershit\n\nA comprehensive CLI tool for managing GitHub repository ownership, permissions, and branch protection rules across your organization.\n\n## Features\n\n- **Team Permissions**: Manage admin/push/pull access control for teams across repositories\n- **Branch Protection**: Advanced branch protection rules with status checks, admin enforcement, and push restrictions\n- **Repository Settings**: Configure wiki, issues, and projects settings\n- **Label Management**: Sync default labels across repositories with emoji support\n- **Topic Management**: Mass-assign repository topics/tags additively or by replacement\n- **Repository Archiving**: Find and archive inactive repositories based on configurable criteria\n- **Merge Strategy Control**: Configure allowed merge types (merge commits, squash, rebase)\n\n## Installation\n\n### Using Go Install\n\n```bash\ngo install github.com/klauern/ownershit/cmd/ownershit@latest\n```\n\n### Using Task (Development)\n\n```bash\n# Clone the repository\ngit clone https://github.com/klauern/ownershit.git\ncd ownershit\n\n# Set up development environment\ntask dev\n\n# Build and install locally\ntask install\n```\n\n## Quick Start\n\n1. Create a configuration file:\n\n   ```bash\n   ownershit init\n   ```\n\n1. Edit `repositories.yaml` with your organization details\n\n1. Set up your GitHub token:\n\n   ```bash\n   export GITHUB_TOKEN=your_github_token_here\n   ```\n\n1. Synchronize your repositories:\n\n   ```bash\n   ownershit sync\n   ```\n\n## Generate Configuration from Existing Repositories\n\nIf you already have repositories on GitHub and want to generate a configuration file automatically:\n\n```bash\n# Set your GitHub token\nexport GITHUB_TOKEN=your_github_token_here\n\n# Generate configuration for your user\n./scripts/generate-config.sh klauern\n\n# Or specify a custom output file\n./scripts/generate-config.sh klauern my-repositories.yaml\n```\n\nThis will:\n- Fetch all repositories you own (not forked repos)\n- Analyze settings to determine sensible defaults\n- Generate a complete YAML configuration file\n- Include all repository metadata (descriptions, settings, etc.)\n\nAfter generation, you should:\n1. Review the generated file\n2. Add team permissions (if working with an organization)\n3. Configure branch protection rules\n4. Add default labels and topics\n5. Test with `--dry-run` before applying\n\nFor more details, see [scripts/README.md](scripts/README.md).\n\n## Dry-Run Mode\n\nPreview changes before applying them using the `--dry-run` flag:\n\n```bash\n# Preview all changes that would be made\nownershit sync --config repositories.yaml --dry-run\n\n# With debug output for detailed analysis\nownershit sync --config repositories.yaml --dry-run --debug\n```\n\n### What Dry-Run Shows\n\nDry-run mode displays all planned changes without making any API calls to GitHub:\n\n- Team permissions that would be added to repositories\n- Repository features that would be changed (wiki, issues, projects)\n- Branch protection rules that would be applied\n- Branch merge strategies that would be updated\n- Delete-branch-on-merge settings that would be configured\n\n### Example Output\n\n```text\nINFO DRY RUN MODE - No changes will be applied\nINFO DRY RUN: Analyzing configuration changes...\nINFO Would process repository repository=account_vending_machine\nINFO Would update branch merge strategies repository=account_vending_machine\nINFO Would apply enhanced branch protection rules branch=main repository=account_vending_machine\nINFO Would update repository features issues=false projects=false wiki=false repository=account_vending_machine\nINFO Would update delete_branch_on_merge setting delete_branch_on_merge=true repository=account_vending_machine\n...\nINFO DRY RUN: Complete. No changes were applied.\n```\n\n### Use Cases\n\n- **Safety**: Verify configuration changes before applying them to production repositories\n- **Learning**: Understand what the tool will do without making actual changes\n- **Debugging**: Identify configuration issues or unexpected behavior\n- **CI/CD**: Validate configurations in automated pipelines\n- **Documentation**: Generate reports of planned changes for team review\n\n## Commands\n\n### Core Commands\n\n| Command       | Description                             | Example                                            |\n| ------------- | --------------------------------------- | -------------------------------------------------- |\n| `init`        | Create a stub configuration file          | `ownershit init`                                   |\n| `sync`        | Synchronize all repository settings     | `ownershit sync --config repositories.yaml`\u003cbr\u003e`ownershit sync --dry-run` |\n| `branches`    | Update branch merge strategies          | `ownershit branches`                               |\n| `label`       | Sync default labels across repositories | `ownershit label`                                  |\n| `topics`      | Sync repository topics/tags             | `ownershit topics --additive=true`                 |\n| `import`      | Import repository configuration as YAML  | `ownershit import owner/repo --output config.yaml`  |\n| `permissions` | Show required GitHub token permissions  | `ownershit permissions`                            |\n| `ratelimit`   | Check GitHub API rate limits            | `ownershit ratelimit`                              |\n\n### Archive Commands\n\n| Command           | Description                                 | Example                                                 |\n| ----------------- | ------------------------------------------- | ------------------------------------------------------- |\n| `archive query`   | Find repositories eligible for archiving    | `ownershit archive query --username myuser --days 365`  |\n| `archive execute` | Archive selected repositories interactively | `ownershit archive execute --username myuser --stars 0` |\n\n### Import/Export Commands\n\n| Command      | Description                                    | Example                                                           |\n| ------------ | ---------------------------------------------- | ----------------------------------------------------------------- |\n| `import-csv` | Import multiple repositories and export as CSV | `ownershit import-csv owner/repo1 owner/repo2 --output repos.csv` |\n\n### Global Flags\n\n| Flag          | Description             | Default             | Environment Variable |\n| ------------- | ----------------------- | ------------------- | -------------------- |\n| `--config`    | Configuration file path | `repositories.yaml` | -                    |\n| `--debug, -d` | Enable debug logging    | `false`             | `OWNERSHIT_DEBUG`    |\n\n## Configuration\n\n### Basic Configuration\n\nCreate a `repositories.yaml` file with your organization settings:\n\n```yaml\n# Your GitHub organization name (REQUIRED)\norganization: your-org-name\n\n# Global defaults for repository features (optional)\n# These apply to all repositories unless explicitly overridden\ndefaults:\n  wiki: false                   # Disable wikis by default\n  issues: true                  # Enable issues by default\n  projects: false               # Disable projects by default\n  delete_branch_on_merge: true  # Auto-delete head branches after PR merge\n\n# Team permissions for repositories\nteam:\n  - name: developers\n    level: push\n  - name: maintainers\n    level: admin\n  - name: security-team\n    level: admin\n\n# Repository configurations\nrepositories:\n  - name: my-app\n    wiki: true           # Override: enable wiki for this repo\n    # issues: inherits default (true)\n    # projects: inherits default (false)\n  - name: internal-tool\n    # wiki: inherits default (false)\n    # issues: inherits default (true)\n    projects: true       # Override: enable projects for this repo\n```\n\n### Advanced Branch Protection\n\nConfigure comprehensive branch protection rules:\n\n```yaml\nbranches:\n  # Basic protection\n  require_pull_request_reviews: true\n  require_approving_count: 2\n  require_code_owners: true\n\n  # Merge strategy controls\n  allow_merge_commit: false\n  allow_squash_merge: true\n  allow_rebase_merge: true\n\n  # Status checks\n  require_status_checks: true\n  status_checks:\n    - \"ci/build\"\n    - \"ci/test\"\n    - \"security/scan\"\n  require_up_to_date_branch: true\n\n  # Advanced protection\n  enforce_admins: true\n  restrict_pushes: true\n  push_allowlist:\n    - \"admin-team\"\n    - \"deploy-team\"\n  require_conversation_resolution: true\n  require_linear_history: true\n  allow_force_pushes: false\n  allow_deletions: false\n```\n\n### Label Management\n\nDefine default labels for all repositories:\n\n```yaml\ndefault_labels:\n  - name: \"bug\"\n    color: \"d73a4a\"\n    emoji: \"🐛\"\n    description: \"Something isn't working\"\n  - name: \"enhancement\"\n    color: \"a2eeef\"\n    emoji: \"✨\"\n    description: \"New feature or request\"\n  - name: \"security\"\n    color: \"ff6b6b\"\n    emoji: \"🔒\"\n    description: \"Security-related issue\"\n```\n\n### Topic Management\n\nDefine default topics to apply across repositories:\n\n```yaml\ndefault_topics:\n  - \"golang\"\n  - \"cli\"\n  - \"github-management\"\n  - \"internal-tool\"\n```\n\n### Repository Feature Defaults\n\nConfigure global defaults for repository features. These defaults apply to all repositories unless explicitly overridden at the repository level.\n\n#### Available Default Settings\n\nWithin the `defaults` block, you can configure:\n\n- `wiki` - Enable/disable wikis for all repositories\n- `issues` - Enable/disable issue tracking for all repositories\n- `projects` - Enable/disable GitHub projects for all repositories\n- `delete_branch_on_merge` - Automatically delete head branches after pull request merge\n\n#### How It Works\n\n1. **Global Defaults**: Set default values in the `defaults` block of your configuration\n2. **Per-Repository Overrides**: Specify values at the repository level to override defaults\n3. **Inheritance**: If a repository doesn't specify a value, it inherits from the default\n4. **Nil Behavior**: If no default is set and no repository value is provided, no change is made\n\n#### Example Configuration\n\n```yaml\norganization: my-org\n\n# Set defaults - most repos don't need wikis or projects\ndefaults:\n  wiki: false\n  issues: true\n  projects: false\n  delete_branch_on_merge: true\n\nrepositories:\n  # Inherits all defaults (wiki: false, issues: true, projects: false)\n  - name: simple-tool\n\n  # Override wiki only - enable for documentation\n  - name: main-app\n    wiki: true\n    # issues: inherits default (true)\n    # projects: inherits default (false)\n\n  # Override projects only - needs project board\n  - name: team-planning\n    # wiki: inherits default (false)\n    # issues: inherits default (true)\n    projects: true\n\n  # Override all defaults\n  - name: special-repo\n    wiki: true\n    issues: false\n    projects: true\n```\n\n#### Migration from Explicit Settings\n\nIf you have an existing configuration with explicit settings on every repository, you can migrate to using defaults:\n\n**Before** (explicit settings everywhere):\n```yaml\nrepositories:\n  - name: repo1\n    wiki: false\n    issues: true\n    projects: false\n  - name: repo2\n    wiki: false\n    issues: true\n    projects: false\n  - name: repo3\n    wiki: false\n    issues: true\n    projects: false\n```\n\n**After** (using nested defaults):\n```yaml\ndefaults:\n  wiki: false\n  issues: true\n  projects: false\n  delete_branch_on_merge: true\n\nrepositories:\n  - name: repo1\n  - name: repo2\n  - name: repo3\n```\n\n#### Backward Compatibility\n\nThis feature is fully backward compatible. Old-style `default_*` fields are automatically migrated to the new nested `defaults` block at runtime:\n\n**Old format** (still supported):\n```yaml\ndefault_wiki: false\ndefault_issues: true\ndefault_projects: false\n```\n\n**New format** (recommended):\n```yaml\ndefaults:\n  wiki: false\n  issues: true\n  projects: false\n  delete_branch_on_merge: true\n```\n\nWhen using the old format, you'll see a migration message in the logs, but everything will continue to work seamlessly.\n\n## Development\n\nThis project uses [Task](https://taskfile.dev) for task management.\n\n### Development Setup\n\n```bash\n# Set up development environment\ntask dev\n\n# Install development dependencies\n# - go mod tidy\n# - install mockgen\n# - install govulncheck\n# - install bump tool\n```\n\n### Building and Testing\n\n```bash\n# Build binaries\ntask build\n\n# Run tests with coverage\ntask test\n\n# View test coverage in browser\ntask test-cover\n\n# Run tests with security checks\ntask test-all\n```\n\n### Code Quality\n\n```bash\n# Format code\ntask fmt\n\n# Run linter\ntask lint\n\n# Generate mocks for testing\ntask mocks\n\n# Run security vulnerability check\ntask security\n```\n\n### GraphQL Client Management\n\n```bash\n# Download latest GitHub GraphQL schema\ntask gql:download-schema\n\n# Generate GraphQL client code\ntask gql:generate-client\n```\n\n### Releases\n\n```bash\n# Show release options\ntask release\n\n# Create patch release (v0.6.0 → v0.6.1)\ntask release:patch\n\n# Create minor release (v0.6.0 → v0.7.0)\ntask release:minor\n\n# Create major release (v0.6.0 → v1.0.0)\ntask release:major\n\n# Create release candidate (v0.6.0 → v0.7.0-rc1)\ntask release:rc\n```\n\n## Utilities\n\n### Backfill Repository Features\n\nThe `scripts/backfill-repo-features.py` script helps migrate existing configurations by detecting actual feature usage and updating your YAML file:\n\n```bash\n# Requires uv or Python 3.11+ with PyGithub and PyYAML\nexport GITHUB_TOKEN=your_token\nuv run scripts/backfill-repo-features.py repositories.yaml\n```\n\nThis script:\n- Checks actual wiki/issues/projects usage for each repository\n- Adds explicit settings where they differ from defaults\n- Removes redundant explicit settings that match defaults\n- Creates a `.backup` file before making changes\n\n## Architecture\n\n### Core Components\n\n- **GitHub REST v3 API**: Team permissions, issue labels, merge strategies\n- **GitHub GraphQL v4 API**: Repository settings, branch protection, archiving\n- **Dual API Approach**: Leverages strengths of both APIs for comprehensive coverage\n\n### Configuration Structure\n\n```\nrepositories.yaml\n├── organization: string            # GitHub organization name\n├── defaults: RepositoryDefaults    # Global defaults (optional)\n│   ├── wiki: bool                  # Default wiki setting\n│   ├── issues: bool                # Default issues setting\n│   ├── projects: bool              # Default projects setting\n│   └── delete_branch_on_merge: bool # Default auto-delete branches\n├── branches: BranchPermissions     # Branch protection rules\n├── team: []TeamPermission          # Team access levels\n├── repositories: []Repository      # Repository configurations\n├── default_labels: []Label         # Default labels for all repos\n└── default_topics: []string        # Default topics for all repos\n```\n\n### Key Files\n\n- `cmd/ownershit/main.go` - CLI entry point and commands\n- `config.go` - Configuration parsing and validation\n- `github_v3.go` - REST API client implementation\n- `github_v4.go` - GraphQL API client implementation\n- `branch.go` - Branch protection management\n- `archiving_v4.go` - Repository archiving functionality\n\n## GitHub Token Setup\n\n1. Create a Personal Access Token at: \u003chttps://github.com/settings/tokens\u003e\n\n1. Required scopes:\n\n   - `repo` - Full repository access\n   - `admin:org` - Organization admin access (for team management)\n\n1. Set the token as an environment variable:\n\n   ```bash\n   export GITHUB_TOKEN=your_token_here\n   ```\n\n## Examples\n\n### Complete Organization Setup\n\n```bash\n# Initialize configuration\nownershit init\n\n# Edit repositories.yaml with your settings\n\n# Apply all configurations\nownershit sync --config repositories.yaml --debug\n```\n\n### Archive Inactive Repositories\n\n```bash\n# Find repositories inactive for 365+ days with 0 stars\nownershit archive query --username myuser --days 365 --stars 0\n\n# Interactively select and archive repositories\nownershit archive execute --username myuser --days 365 --stars 0\n```\n\n### Update Branch Protection Only\n\n```bash\n# Apply only branch merge strategy changes\nownershit branches --config repositories.yaml\n```\n\n### Sync Labels Across Repositories\n\n```bash\n# Update labels on all configured repositories\nownershit label --config repositories.yaml\n```\n\n### Sync Topics Across Repositories\n\n```bash\n# Additively merge topics (default) - preserves existing topics\nownershit topics --config repositories.yaml\n\n# Replace all topics with configured ones\nownershit topics --config repositories.yaml --additive=false\n```\n\n### Import Repository Configuration\n\n```bash\n# Import single repository configuration as YAML\nownershit import myorg/myrepo --output repo-config.yaml\n\n# Import repository to stdout and preview settings\nownershit import myorg/myrepo\n```\n\n### Bulk Export Repository Data as CSV\n\n```bash\n# Export multiple repositories to CSV file\nownershit import-csv myorg/repo1 myorg/repo2 myorg/repo3 --output repositories.csv\n\n# Export from batch file with repository list\nownershit import-csv --batch-file repo-list.txt --output export.csv\n\n# Append to existing CSV file\nownershit import-csv myorg/new-repo --output existing-data.csv --append\n```\n\n## Troubleshooting\n\n### Common Issues\n\n**Configuration file not found**\n\n```bash\n# Create a new configuration file\nownershit init\n```\n\n**GitHub API rate limits**\n\n```bash\n# Check current rate limit status\nownershit ratelimit --debug\n```\n\n**Permission errors**\n\n```bash\n# Verify token has required scopes:\n# - repo (full repository access)\n# - admin:org (organization admin access)\n```\n\n**Debug mode**\n\n```bash\n# Enable verbose logging\nownershit sync --debug\n# or\nexport OWNERSHIT_DEBUG=true\nownershit sync\n```\n\n### Getting Help\n\n- Run `ownershit --help` for command help\n- Run `ownershit \u003ccommand\u003e --help` for command-specific help\n- Check the [example configuration](testdata/enhanced-branch-protection-example.yaml) for advanced features\n- Enable debug mode (`--debug`) for detailed logging\n\n## Contributing\n\n1. Fork the repository\n1. Create a feature branch (`git checkout -b feature/amazing-feature`)\n1. Make your changes\n1. Run tests (`task test-all`)\n1. Commit your changes (`git commit -m 'Add amazing feature'`)\n1. Push to the branch (`git push origin feature/amazing-feature`)\n1. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n\n## Authors\n\n- **Nick Klauer** - *Initial work* - [klauern](https://github.com/klauern)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklauern%2Fownershit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fklauern%2Fownershit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklauern%2Fownershit/lists"}