{"id":13878422,"url":"https://github.com/rubyatscale/code_ownership","last_synced_at":"2026-01-26T22:19:22.438Z","repository":{"id":37845869,"uuid":"490409122","full_name":"rubyatscale/code_ownership","owner":"rubyatscale","description":"A gem to help engineering teams declare ownership of code","archived":false,"fork":false,"pushed_at":"2025-05-16T20:11:20.000Z","size":7177,"stargazers_count":104,"open_issues_count":2,"forks_count":26,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-06-11T15:14:31.708Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rubyatscale.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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}},"created_at":"2022-05-09T18:57:45.000Z","updated_at":"2025-05-17T13:50:16.000Z","dependencies_parsed_at":"2023-11-08T04:41:02.662Z","dependency_job_id":"2276151f-d27e-4d25-8fea-3216dfec44ef","html_url":"https://github.com/rubyatscale/code_ownership","commit_stats":{"total_commits":37,"total_committers":5,"mean_commits":7.4,"dds":"0.10810810810810811","last_synced_commit":"db898859142feeed09ef88358ae8103e488be5c3"},"previous_names":[],"tags_count":49,"template":false,"template_full_name":null,"purl":"pkg:github/rubyatscale/code_ownership","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubyatscale%2Fcode_ownership","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubyatscale%2Fcode_ownership/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubyatscale%2Fcode_ownership/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubyatscale%2Fcode_ownership/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rubyatscale","download_url":"https://codeload.github.com/rubyatscale/code_ownership/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubyatscale%2Fcode_ownership/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260739051,"owners_count":23055074,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2024-08-06T08:01:49.144Z","updated_at":"2026-01-26T22:19:22.429Z","avatar_url":"https://github.com/rubyatscale.png","language":"Ruby","readme":"# CodeOwnership\n\nThis gem helps engineering teams declare ownership of code. This gem works best in large, usually monolithic code bases where many teams work together.\n\nCheck out [`lib/code_ownership.rb`](https://github.com/rubyatscale/code_ownership/blob/main/lib/code_ownership.rb) to see the public API.\n\nCheck out [`code_ownership_spec.rb`](https://github.com/rubyatscale/code_ownership/blob/main/spec/lib/code_ownership_spec.rb) to see examples of how code ownership is used.\n\nThere is also a [companion VSCode Extension](https://github.com/rubyatscale/code-ownership-vscode) for this gem. Just search `Gusto.code-ownership-vscode` in the VSCode Extension Marketplace.\n\n## Getting started\n\nTo get started there's a few things you should do.\n\n1. Create a `config/code_ownership.yml` file and declare where your files live. Here's a sample to start with:\n\n```yml\nowned_globs:\n  - '{app,components,config,frontend,lib,packs,spec}/**/*.{rb,rake,js,jsx,ts,tsx}'\njs_package_paths: []\nunowned_globs:\n  - db/**/*\n  - app/services/some_file1.rb\n  - app/services/some_file2.rb\n  - frontend/javascripts/**/__generated__/**/*\n```\n\n2. Declare some teams. Here's an example, that would live at `config/teams/operations.yml`:\n\n```yml\nname: Operations\ngithub:\n  team: '@my-org/operations-team'\n```\n\n3. Declare ownership. You can do this at a directory level or at a file level. All of the files within the `owned_globs` you declared in step 1 will need to have an owner assigned (or be opted out via `unowned_globs`). See the next section for more detail.\n4. Run validations when you commit, and/or in CI. If you run validations in CI, ensure that if your `.github/CODEOWNERS` file gets changed, that gets pushed to the PR.\n\n## Usage: Declaring Ownership\n\nThere are five ways to declare code ownership using this gem:\n\n### Directory-Based Ownership\n\nDirectory based ownership allows for all files in that directory and all its sub-directories to be owned by one team. To define this, add a `.codeowner` file inside that directory with the name of the team as the contents of that file.\n\n```\nTeam\n```\n\n### File-Annotation Based Ownership\n\nFile annotations are a last resort if there is no clear home for your code. File annotations go at the top of your file, and look like this:\n\n```ruby\n# @team MyTeam\n```\n\n### Package-Based Ownership\n\nPackage based ownership integrates [`packwerk`](https://github.com/Shopify/packwerk) and has ownership defined per package. To define that all files within a package are owned by one team, configure your `package.yml` like this:\n\n```yml\nenforce_dependency: true\nenforce_privacy: true\nmetadata:\n  owner: Team\n```\n\nYou can also define `owner` as a top-level key, e.g.\n\n```yml\nenforce_dependency: true\nenforce_privacy: true\nowner: Team\n```\n\nTo do this, add `code_ownership` to the `require` key of your `packwerk.yml`. See \u003chttps://github.com/Shopify/packwerk/blob/main/USAGE.md#loading-extensions\u003e for more information.\n\n### Glob-Based Ownership\n\nIn your team's configured YML (see [`code_teams`](https://github.com/rubyatscale/code_teams)), you can set `owned_globs` to be a glob of files your team owns. For example, in `my_team.yml`:\n\n```yml\nname: My Team\nowned_globs:\n  - app/services/stuff_belonging_to_my_team/**/**\n  - app/controllers/other_stuff_belonging_to_my_team/**/**\nunowned_globs:\n  - app/controllers/other_stuff_belonging_to_my_team/that_one_weird_dir_we_dont_own/*\n```\n\n### Javascript Package Ownership\n\nJavascript package based ownership allows you to specify an ownership key in a `package.json`. To use this, configure your `package.json` like this:\n\n```json\n{\n  // other keys\n  \"metadata\": {\n    \"owner\": \"My Team\"\n  }\n  // other keys\n}\n```\n\nYou can also tell `code_ownership` where to find JS packages in the configuration, like this:\n\n```yml\njs_package_paths:\n  - frontend/javascripts/packages/*\n  - frontend/other_location_for_packages/*\n```\n\nThis defaults `**/`, which makes it look for `package.json` files across your application.\n\n\u003e [!NOTE]\n\u003e Javscript package ownership does not respect `unowned_globs`. If you wish to disable usage of this feature you can set `js_package_paths` to an empty list.\n\n```yml\njs_package_paths: []\n```\n\n## Usage: Reading CodeOwnership\n\n### `for_file`\n\n`CodeOwnership.for_file`, given a relative path to a file returns a `CodeTeams::Team` if there is a team that owns the file, `nil` otherwise.\n\n```ruby\nCodeOwnership.for_file('path/to/file/relative/to/application/root.rb')\n```\n\nContributor note: If you are making updates to this method or the methods getting used here, please benchmark the performance of the new implementation against the current for both `for_files` and `for_file` (with 1, 100, 1000 files).\n\nSee `code_ownership_spec.rb` for examples.\n\n### `for_backtrace`\n\n`CodeOwnership.for_backtrace` can be given a backtrace and will either return `nil`, or a `CodeTeams::Team`.\n\n```ruby\nCodeOwnership.for_backtrace(exception.backtrace)\n```\n\nThis will go through the backtrace, and return the first found owner of the files associated with frames within the backtrace.\n\nSee `code_ownership_spec.rb` for an example.\n\n### `for_class`\n\n`CodeOwnership.for_class` can be given a class and will either return `nil`, or a `CodeTeams::Team`.\n\n```ruby\nCodeOwnership.for_class(MyClass)\n```\n\nUnder the hood, this finds the file where the class is defined and returns the owner of that file.\n\nSee `code_ownership_spec.rb` for an example.\n\n### `for_team`\n\n`CodeOwnership.for_team` can be used to generate an ownership report for a team.\n\n```ruby\nCodeOwnership.for_team('My Team')\n```\n\nYou can shovel this into a markdown file for easy viewing using the CLI:\n\n```\ncodeownership for_team 'My Team' \u003e tmp/ownership_report.md\n```\n\n## Usage: Generating a `CODEOWNERS` file\n\nA `CODEOWNERS` file defines who owns specific files or paths in a repository. When you run `codeownership validate`, a `.github/CODEOWNERS` file will automatically be generated and updated.\n\nIf `codeowners_path` is set in `code_ownership.yml` codeowners will use that path to generate the `CODEOWNERS` file. For example, `codeowners_path: docs` will generate `docs/CODEOWNERS`.\n\n## Proper Configuration \u0026 Validation\n\nCodeOwnership comes with a validation function to ensure the following things are true:\n\n1. Only one mechanism is defining file ownership. That is -- you can't have a file annotation on a file owned via package-based or glob-based ownership. This helps make ownership behavior more clear by avoiding concerns about precedence.\n2. All teams referenced as an owner for any file or package is a valid team (i.e. it's in the list of `CodeTeams.all`).\n3. All files have ownership. You can specify in `unowned_globs` to represent a TODO list of files to add ownership to.\n4. The `.github/CODEOWNERS` file is up to date. This is automatically corrected and staged unless specified otherwise with `bin/codeownership validate --skip-autocorrect --skip-stage`. You can turn this validation off by setting `skip_codeowners_validation: true` in `config/code_ownership.yml`.\n\nCodeOwnership also allows you to specify which globs and file extensions should be considered ownable.\n\nHere is an example `config/code_ownership.yml`.\n\n```yml\nowned_globs:\n  - '{app,components,config,frontend,lib,packs,spec}/**/*.{rb,rake,js,jsx,ts,tsx}'\nunowned_globs:\n  - db/**/*\n  - app/services/some_file1.rb\n  - app/services/some_file2.rb\n  - frontend/javascripts/**/__generated__/**/*\n```\n\nYou can call the validation function with the Ruby API\n\n```ruby\nCodeOwnership.validate!\n```\n\nor the CLI\n\n```bash\n# Validate all files\ncodeownership validate\n\n# Validate specific files\ncodeownership validate path/to/file1.rb path/to/file2.rb\n\n# Validate only staged files\ncodeownership validate --diff\n```\n\n## Development\n\nPlease add to `CHANGELOG.md` and this `README.md` when you make make changes.\n\n## Running specs\n\n```sh\nbundle install\nbundle exec rake\n```\n\n## Creating a new release\n\nSimply [create a new release](https://github.com/rubyatscale/code_ownership/releases/new) with github. The release tag must match the gem version\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubyatscale%2Fcode_ownership","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frubyatscale%2Fcode_ownership","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubyatscale%2Fcode_ownership/lists"}