{"id":20397311,"url":"https://github.com/nielsbasjes/codeowners","last_synced_at":"2025-04-12T13:09:07.086Z","repository":{"id":170698621,"uuid":"646486664","full_name":"nielsbasjes/codeowners","owner":"nielsbasjes","description":"A library to use and verify the CODEOWNERS (both the Github and Gitlab variants) and .gitignore files","archived":false,"fork":false,"pushed_at":"2025-04-11T16:09:51.000Z","size":525,"stargazers_count":5,"open_issues_count":2,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-12T13:08:44.261Z","etag":null,"topics":["codeowners","codeowners-validator","maven-enforcer-plugin"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nielsbasjes.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"codeowners-reader/pom.xml","security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"nielsbasjes","custom":"https://www.paypal.me/nielsbasjes"}},"created_at":"2023-05-28T14:57:42.000Z","updated_at":"2025-04-11T16:09:22.000Z","dependencies_parsed_at":"2023-10-26T11:30:25.929Z","dependency_job_id":"5faf48c7-b915-4f2f-97ab-5ea87ee98fc7","html_url":"https://github.com/nielsbasjes/codeowners","commit_stats":null,"previous_names":["nielsbasjes/codeowners"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nielsbasjes%2Fcodeowners","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nielsbasjes%2Fcodeowners/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nielsbasjes%2Fcodeowners/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nielsbasjes%2Fcodeowners/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nielsbasjes","download_url":"https://codeload.github.com/nielsbasjes/codeowners/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248571888,"owners_count":21126522,"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":["codeowners","codeowners-validator","maven-enforcer-plugin"],"created_at":"2024-11-15T04:13:15.265Z","updated_at":"2025-04-12T13:09:07.080Z","avatar_url":"https://github.com/nielsbasjes.png","language":"Java","funding_links":["https://github.com/sponsors/nielsbasjes","https://www.paypal.me/nielsbasjes"],"categories":[],"sub_categories":[],"readme":"[![Github actions Build status](https://img.shields.io/github/actions/workflow/status/nielsbasjes/codeowners/build.yml?branch=main)](https://github.com/nielsbasjes/codeowners/actions)\n[![Coverage Status](https://img.shields.io/codecov/c/github/nielsbasjes/codeowners)](https://app.codecov.io/gh/nielsbasjes/codeowners)\n[![License](https://img.shields.io/:license-apache-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n[![Maven Central: codeowners-reader](https://img.shields.io/maven-central/v/nl.basjes.codeowners/codeowners-reader.svg?label=codeowners-reader)](https://central.sonatype.com/namespace/nl.basjes.codeowners)\n[![Maven Central: gitignore-reader](https://img.shields.io/maven-central/v/nl.basjes.gitignore/gitignore-reader.svg?label=gitignore-reader)](https://central.sonatype.com/namespace/nl.basjes.gitignore)\n[![Maven Central: codeowners-enforcer-rules](https://img.shields.io/maven-central/v/nl.basjes.maven.enforcer.codeowners/codeowners-enforcer-rules.svg?label=codeowners-enforcer-rules)](https://central.sonatype.com/namespace/nl.basjes.maven.enforcer.codeowners)\n[![GitHub stars](https://img.shields.io/github/stars/nielsbasjes/codeowners?label=GitHub%20stars)](https://github.com/nielsbasjes/codeowners/stargazers)\n[![If this project has business value for you then don't hesitate to support me with a small donation.](https://img.shields.io/badge/Sponsor%20me-via%20Github-red.svg)](https://github.com/sponsors/nielsbasjes)\n[![If this project has business value for you then don't hesitate to support me with a small donation.](https://img.shields.io/badge/Donations-via%20Paypal-red.svg)](https://www.paypal.me/nielsbasjes)\n\n# CodeOwners\nIn several systems (like GitHub and Gitlab) you can have a CODEOWNERS file which is used to ensure all changes are approved by the right people.\n\nReality: The syntax of these files can be tricky, and it is quite easy to write a config that has the effect that not all files are covered.\n\n# What is this\n1) A Java library to read a CODEOWNERS file.\n2) A Java library to read a/all .gitignore file(s) in directory tree.\n3) An extra rule for the Maven Enforcer plugin to check the CODEOWNERS against\n   1) the actual project files. (See Usage below)\n   2) the actual users, groups and roles in Gitlab. (BETA) (See [README-gitlab.md](README-gitlab.md))\n\nThe intended goal is to make the build fail if the codeowners file does not cover all files and directories in the project.\n\n- The libraries for the CODEOWNERS and gitignore files are usable in Java 8 and newer.\n- The Maven Enforcer rule needs Java 11 or newer.\n\n# CodeOwners Enforcer rule\n## Configuration parameters\n\n- **baseDir**\n  - In case you run the plugin from a child module.\n- **codeOwnersFile**\n  - The name of the codeowners file when you are not using a common standard.\n- **allExisingFilesMustHaveCodeOwner**\n  - Check that all existing files have at least one mandatory codeowner.\n  - Gitlab also supports \"Optional\" code owners but that is useless to check for.\n- **allNewlyCreatedFilesMustHaveCodeOwner**\n  - Check that if a new file is created in any of the directories in the project that it would automatically have a mandatory code owner.\n  - Note when a specific filename exception is used in the gitignore rules then this check is not perfect.\n- **allFilesMustHaveCodeOwner**\n  - Do both allExisingFilesMustHaveCodeOwner and allNewlyCreatedFilesMustHaveCodeOwner\n- **verbose**\n    - Make the rule output much more details than you would normally like to see.\n- **showApprovers**\n    - Make the rule output show the approvers for all non-ignored files in the entire project. The intended usage is that with this you can debug the CODEOWNERS result and manually see for every file in your project if you are happy with the resulting approvers.\n\n## Checking against the users present on a Gitlab Instance (BETA)\nIf you have a Gitlab instance with your project then you can get additional checks done.\nThis plugin can also verify if all mentioned users, groups and roles are actually allowed to approve a change.\nThis is important because when Gitlab determines that all the mentioned approvers either do not exist or do not have the appropriate approval level then everyone can merge any change on a file.\n\n___**This is currently a BETA feature.**___\n\nChecking this page for all the information: [README-gitlab.md](README-gitlab.md)\n\n## Example\nIn one of my projects it looks like this:\n\n```xml\n\u003cplugin\u003e\n  \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n  \u003cartifactId\u003emaven-enforcer-plugin\u003c/artifactId\u003e\n  \u003cversion\u003e3.4.1\u003c/version\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003enl.basjes.maven.enforcer.codeowners\u003c/groupId\u003e\n      \u003cartifactId\u003ecodeowners-enforcer-rules\u003c/artifactId\u003e\n      \u003cversion\u003e1.11.3\u003c/version\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n  \u003cexecutions\u003e\n    \u003cexecution\u003e\n      \u003cid\u003eEnsure the CODEOWNERS is correct\u003c/id\u003e\n      \u003cphase\u003everify\u003c/phase\u003e\n      \u003cgoals\u003e\n        \u003cgoal\u003eenforce\u003c/goal\u003e\n      \u003c/goals\u003e\n      \u003cinherited\u003efalse\u003c/inherited\u003e\n      \u003cconfiguration\u003e\n        \u003crules\u003e\n          \u003ccodeOwners\u003e\n            \u003cbaseDir\u003e${maven.multiModuleProjectDirectory}\u003c/baseDir\u003e\n            \u003ccodeOwnersFile\u003e${maven.multiModuleProjectDirectory}/CODEOWNERS\u003c/codeOwnersFile\u003e\n            \u003callFilesMustHaveCodeOwner\u003etrue\u003c/allFilesMustHaveCodeOwner\u003e\n            \u003c!-- \u003cverbose\u003etrue\u003c/verbose\u003e --\u003e\n            \u003c!-- \u003cshowApprovers\u003etrue\u003c/showApprovers\u003e --\u003e\n            \u003cgitlab\u003e\n              \u003caccessToken\u003e\n                \u003cenvironmentVariableName\u003eCHECK_USERS_TOKEN\u003c/environmentVariableName\u003e\n              \u003c/accessToken\u003e\n            \u003c/gitlab\u003e\n          \u003c/codeOwners\u003e\n        \u003c/rules\u003e\n      \u003c/configuration\u003e\n    \u003c/execution\u003e\n  \u003c/executions\u003e\n\u003c/plugin\u003e\n```\n\n# GitIgnore library\n\n## Basic use\nSimply create an instance of the GitIgnoreFileSet and pass the root directory of the project as a parameter\n```java\nGitIgnoreFileSet ignoreFileSet = new GitIgnoreFileSet(new File(\"/home/niels/workspace/project\"));\n```\nYou can then check for each file in the project if it is ignored or not\n```java\nif (ignoreFileSet.ignoreFile(\"/home/niels/workspace/project/something/something/README.md\")) {\n    ...\n}\n```\n\n## Full path or just or a project relative filename\nThe directory name with which you initialize the `GitIgnoreFileSet` is considered to be the directory name of the project root.\nBy default, if you ask for a file if it is ignored or not, this library assumes you are specifying all files within the SAME base directory structure.\n\nSo loading the gitignore files from `workspace/project` then a file in the root of the project must (by default) be specified as `workspace/project/pom.xml` and a file deeper in the project as for example `workspace/project/src/main/java/nl/basjes/Something.java`\n\nSomething like this:\n```java\nGitIgnoreFileSet ignoreFileSet = new GitIgnoreFileSet(new File(\"workspace/project\"));\n\nif (ignoreFileSet.ignoreFile(\"workspace/project/pom.xml\")) {\n    ...\n}\n```\nSo comming from the default situation the `ignoreFileSet.assumeQueriesIncludeProjectBaseDir()` does nothing.\n\n\nYou can **optionally specify** that the files you request are **relative to the project root**.\n\nSo loading the gitignore files from `workspace/project` then a file in the root of the project must be specified as `/pom.xml` and a file deeper in the project as for example `/src/main/java/nl/basjes/Something.java`\n\nSomething like this:\n```java\nGitIgnoreFileSet ignoreFileSet = new GitIgnoreFileSet(new File(\"workspace/project\"));\n\nif (ignoreFileSet.ignoreFile(\"/pom.xml\", true)) {\n    ...\n}\n```\n\nOr you can set it as the default assumption.\n\n```java\nGitIgnoreFileSet ignoreFileSet = new GitIgnoreFileSet(new File(\"workspace/project\"));\nignoreFileSet.assumeQueriesAreProjectRelative();\n\nif (ignoreFileSet.ignoreFile(\"/pom.xml\")) {\n    ...\n}\n```\n\n\n## GitIgnore edge case\nThis [tutorial page](https://www.atlassian.com/git/tutorials/saving-changes/gitignore) documents this edge case that this library also follows.\n\nI see this as unexpected behaviour yet this is really what git does !\n\n**Pattern**\n\n    logs/\n    !logs/important.log\n\n**Matches**\n\n    logs/debug.log\n    logs/important.log\n\n**Explanation**\n\n    Wait a minute! Shouldn't logs/important.log be negated in the example on the left\n    Nope! Due to a performance-related quirk in Git, you can not negate a file that is ignored due to a pattern matching a directory\n\n# Building\nThe maven build must be run under Java 17 or newer (because of plugins) and will use toolchains to actually build the software using JDK 21.\n\n# License\n\n    CodeOwners Tools\n    Copyright (C) 2023-2025 Niels Basjes\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an AS IS BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnielsbasjes%2Fcodeowners","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnielsbasjes%2Fcodeowners","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnielsbasjes%2Fcodeowners/lists"}