{"id":13561769,"url":"https://github.com/todogroup/repolinter","last_synced_at":"2025-08-15T23:19:00.800Z","repository":{"id":21823868,"uuid":"94138426","full_name":"todogroup/repolinter","owner":"todogroup","description":"Repolinter, The Open Source Repository Linter","archived":false,"fork":false,"pushed_at":"2025-06-07T00:41:27.000Z","size":3339,"stargazers_count":446,"open_issues_count":25,"forks_count":74,"subscribers_count":58,"default_branch":"main","last_synced_at":"2025-07-07T02:45:17.470Z","etag":null,"topics":["github","javascript","linter"],"latest_commit_sha":null,"homepage":"https://todogroup.github.io/repolinter/","language":"JavaScript","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/todogroup.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING","funding":null,"license":"LICENSE","code_of_conduct":"CODE-OF-CONDUCT","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-06-12T20:40:16.000Z","updated_at":"2025-07-05T11:09:48.000Z","dependencies_parsed_at":"2023-01-12T01:30:26.718Z","dependency_job_id":"ca8a9121-be0f-459f-af07-7d8abab5bb7c","html_url":"https://github.com/todogroup/repolinter","commit_stats":{"total_commits":492,"total_committers":51,"mean_commits":9.647058823529411,"dds":0.6707317073170731,"last_synced_commit":"893920a6c8ad12599716da03fc352f1de02db706"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/todogroup/repolinter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todogroup%2Frepolinter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todogroup%2Frepolinter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todogroup%2Frepolinter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todogroup%2Frepolinter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/todogroup","download_url":"https://codeload.github.com/todogroup/repolinter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todogroup%2Frepolinter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270644761,"owners_count":24621332,"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","status":"online","status_checked_at":"2025-08-15T02:00:12.559Z","response_time":110,"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":["github","javascript","linter"],"created_at":"2024-08-01T13:01:00.926Z","updated_at":"2025-08-15T23:19:00.775Z","avatar_url":"https://github.com/todogroup.png","language":"JavaScript","readme":"# ![Repo Linter](https://raw.githubusercontent.com/todogroup/repolinter/master/docs/images/P_RepoLinter01_logo_only.png) ![Build Status](https://github.com/todogroup/repolinter/workflows/Build/badge.svg)\n\nLint open source repositories for common issues.\n\n## Installation\n\nRepolinter requires [Node.JS](https://nodejs.org/en/) \u003e= v12 to function properly. Once Node.JS is installed, you can install Repolinter using `npm`:\n\n```sh\nnpm install -g repolinter\n```\n\n## Linting a Local Repository\n\nOnce installed, run the following to lint a directory:\n\n```sh\nrepolinter lint \u003cdirectory\u003e\n```\n\nThe above command will lint `\u003cdirectory\u003e` with the local `repolinter.json` ruleset or the [default ruleset](./rulesets/default.json) if none is found:\n\n```console\nrepolinter % repolinter lint .\nTarget directory: \u003cdirectory\u003e\nLint:\n✔ license-file-exists: Found file (LICENSE)\n✔ readme-file-exists: Found file (README.md)\n✔ contributing-file-exists: Found file (CONTRIBUTING)\n✔ code-of-conduct-file-exists: Found file (CODE-OF-CONDUCT)\n✔ changelog-file-exists: Found file (CHANGELOG)\n...\nrepolinter % echo $?\n0\n```\n\n## Linting a Remote Repository\n\nRepolinter also supports linting a git repository using the `--git` flag. With this flag enabled, the directory input will be interpreted as a git URL which Repolinter will automatically clone into a temporary directory.\n\n```sh\nrepolinter lint -g https://github.com/todogroup/repolinter.git\n```\n\n## Formatting the Output\n\nThe Repolinter CLI currently supports three output formatting modes:\n\n- Default (also referred to as result)\n- JSON\n- Markdown\n\nYou can switch formatters using the `--format` flag. An example of using the JSON formatter:\n\n```console\nrepolinter % repolinter lint --format json .\n{\"params\":{\"targetDir\":\"/Users/nkoontz/Documents/code/repolinter\",\"filterPaths\":[],...\n```\n\nAn example of using the Markdown formatter:\n\n```console\nrepolinter % repolinter lint --format markdown .\n# Repolinter Report\n\nThis Repolinter run generated the following results:\n| ❗  Error | ❌  Fail | ⚠️  Warn | ✅  Pass | Ignored | Total |\n|---|---|---|---|---|---|\n| 0 | 0 | 0 | 15 | 10 | 25 |\n...\n```\n\n## Limiting Paths\n\nRepolinter supports an allowed list of paths through the `--allowPaths` option to prevent the accidental linting of build artifacts. These paths must still be contained in the target directory/repository.\n\n```sh\nrepolinter lint --allowPaths ./a/path --allowPaths /another/path\n```\n\n## Disabling Modifications\n\nBy default Repolinter will automatically execute fixes as specified by the [ruleset](#rulesets). If this is not desired functionality, you can disable this with the `--dryRun` flag.\n\n## Ruleset Configuration\n\nSimilar to how [eslint](https://eslint.org/) uses an [eslintrc](https://eslint.org/docs/user-guide/configuring) file to determine what validation processes will occur, Repolinter uses a JSON or YAML configuration file (referred to as a _ruleset_) to determine what checks should be run against a repository. Inside a ruleset, there are two main behaviors that can be configured:\n\n- **Rules** - Checks Repolinter should perform against the repository.\n- **Axioms** - External libraries Repolinter should use to conditionally run rules.\n\nThese combined capabilities give you fine-grained control over the checks Repolinter runs.\n\n### Providing a Ruleset\n\nRepolinter will pull its configuration from the following sources in order of priority:\n\n1. A ruleset specified with `--rulesetFile` or `--rulesetUrl`\n2. A `repolint.json`, `repolinter.json`, `repolint.yaml`, or `repolinter.yaml` file at the root of the project being linted\n3. The [default ruleset](./rulesets/default.json)\n\n### Creating a Ruleset\n\nAny ruleset starts with the following base, shown in both JSON and YAML format:\n\n```JSON\n{\n  \"$schema\": \"https://raw.githubusercontent.com/todogroup/repolinter/master/rulesets/schema.json\",\n  \"version\": 2,\n  \"axioms\": {},\n  \"rules\": {}\n}\n```\n\n```YAML\nversion: 2\naxioms: {}\nrules:\n```\n\nWhere:\n\n- **`$schema`**- points to the [JSON schema](./rulesets/schema.json) for all Repolinter rulesets. This schema both validates the ruleset and makes the ruleset creation process a bit easier.\n- **`version`** - specifies the ruleset version Repolinter should expect. Currently there are two versions: omitted for legacy config ([example](https://github.com/todogroup/repolinter/blob/1a66d77e3a744222a049bdb4041437cbcf26a308/rulesets/default.json)) and `2` for all others. Use `2` unless you know what you're doing.\n- **`axiom`** - The axiom functionality, covered in [Axioms](#axioms).\n- **`rules`** - The actual ruleset, covered in [Rules](#rules).\n\n#### Rules\n\nRules are objects of the following format:\n\n```JavaScript\n\"\u003crule-name\u003e\": {\n  \"level\": \"error\" | \"warning\" | \"off\",\n  \"rule\": {\n    \"type\": \"\u003crule-type\u003e\",\n    \"options\": {\n      // \u003crule-options\u003e\n    }\n  },\n  \"where\": [\"condition=*\"],\n  \"fix\": {\n    \"type\": \"\u003cfix-type\u003e\",\n    \"options\": {\n      // \u003cfix-options\u003e\n    }\n  },\n  \"policyInfo\": \"...\",\n  \"policyUrl\": \"...\"\n}\n```\n\n```YAML\n\u003crule-name\u003e:\n  level: error | warning | off\n  rule:\n    type: \u003crule-type\u003e\n    options:\n      \u003crule-options\u003e\n  where: [condition=*]\n  fix:\n    type: \u003cfix-type\u003e\n    options:\n      \u003cfix-options\u003e\n  policyInfo: \u003e-\n    ...\n  policyUrl: \u003e-\n    ...\n```\n\n- **`rule`** - The check to perform. Repolinter can perform any check listed under the [rules documentation](./docs/rules.md). Unlike eslint, Repolinter checks are designed to be reused and specialized: for example, the `file-existence` check can be used in a `README-file-exists` rule and a `LICENSE-file-exists` rule in the same ruleset. This allows a user to write a very specific ruleset from configuring generic checks.\n- **`level`** - The error level to notify if the check fails. `warning` will not change the exit code and `off` will not run the check.\n- **`where`** - Conditionally enable or disable this rule based off of [axioms](#axioms). Strings in this array follow the format of `\u003caxiom\u003e=\u003cvalue\u003e`, where value is either an axiom output or `*` to simply test if the axiom is enabled. If this option is present, this rule will only run if all specified axiom outputs are present. The available axioms in Repolinter can be found in the [axioms documentation](./docs/axioms.md).\n- **`fix`** _(optional)_ - The action to perform if the check performed by `rule` fails. Repolinter can perform any action listed under [fixes documentation](./docs/fixes.md).\n- **`policyInfo`**, **`policyUrl`** _(optional)_ - Information used by the formatter to indicate why the check exists from a policy perspective. Note: `policyInfo` will automatically have a period appended to it for formatting purposes.\n\nA minimal example of a rule that checks for the existence of a `README`:\n\n```JSON\n\"readme-file-exists\" : {\n  \"level\": \"error\",\n  \"rule\": {\n    \"type\": \"file-existence\",\n    \"options\": {\n      \"globsAny\": [\"README*\"]\n    }\n  }\n}\n```\n\n```YAML\nreadme-file-exists:\n  level: error\n  rule:\n    type: file-existence\n    options:\n      globsAny:\n      - README*\n```\n\nChecking that the `README` matches a certain hash, and replacing it if not:\n\n```JSON\n\"readme-file-up-to-date\" : {\n  \"level\": \"error\",\n  \"rule\": {\n    \"type\": \"file-hash\",\n    \"options\": {\n      \"globsAny\": [\"README*\"],\n      \"algorithm\": \"sha256\",\n      \"hash\": \"...\"\n    }\n  },\n  \"fix\": {\n    \"type\": \"file-create\",\n    \"options\": {\n      \"file\": \"README.md\",\n      \"replace\": true,\n      \"text\": { \"url\": \"www.example.com/mytext.txt\" }\n    }\n  },\n  \"policyInfo\": \"Gotta keep that readme up to date\",\n  \"policyUrl\": \"www.example.com/mycompany\"\n}\n```\n\n```YAML\nreadme-file-up-to-date:\n  level: error\n  rule:\n    type: file-hash\n    options:\n      globsAny:\n      - README*\n      algorithm: sha256\n      hash: \"...\"\n  fix:\n    type: file-create\n    options:\n      file: README.md\n      replace: true\n      text:\n        url: www.example.com/mytext.txt\n  policyInfo: Gotta keep that readme up to date\n  policyUrl: www.example.com/mycompany\n\n```\n\n#### Axioms\n\n```JSON\n\"axioms\": {\n  \"\u003caxiom-id\u003e\": \"\u003caxiom-target\u003e\"\n}\n```\n\n```YAML\naxioms:\n  \u003caxiom-id\u003e: axiom-target\n```\n\nEach axiom is configured as a key value pair in the `axioms` object, where `\u003caxiom-id\u003e` specifies the program to run and `\u003caxiom-target\u003e` specifies the target to be used in the `where` conditional. The available axiom IDs can be found in the [axiom documentation](./docs/axioms.md). It should be noted that some axioms require external packages to run.\n\nAn example configuration using an axiom to detect the packaging system for a project:\n\n```JavaScript\n{\n  \"$schema\": \"https://raw.githubusercontent.com/todogroup/repolinter/master/rulesets/schema.json\",\n  \"version\": 2,\n  \"axioms\": {\n    \"packagers\": \"package-type\"\n  },\n  \"rules\": {\n    \"this-only-runs-if-npm\": {\n      \"level\": \"error\",\n      \"where\": [\"package-type=npm\"],\n      \"rule\": { /* ... */ }\n    }\n  }\n}\n```\n\n```YAML\nversion: 2\naxioms:\n  packagers: package-type\nrules:\n  this-only-runs-if-npm:\n    level: error\n    where: [package-type=npm]\n    rule:\n      ...\n```\n\nSome axioms (ex. [`contributor-count`](./docs/axioms.md#contributor-count)) output numerical values instead of strings. For these axioms, numerical comparisons (`\u003c`, `\u003e`, `\u003c=`, `\u003e=`) can be also be specified in the `where` conditional. Note that if a numerical comparison is used for a non-numerical axiom, the comparison will always fail.\n\n```JavaScript\n{\n  \"axioms\": {\n    \"contributor-count\": \"contributors\"\n  },\n  \"rules\": {\n    \"my-rule\": {\n      \"where\": [\"contributors\u003e6\", \"contributors\u003c200\"],\n      // ...\n    }\n  }\n}\n```\n\n```YAML\naxioms:\n  contributor-count: contributors\nrules:\n  my-rule:\n    where:\n    - contributors\u003e6\n    - contributors\u003c200\n    rule:\n      ...\n```\n\n### Extending Rulesets\n\nA ruleset can extend another ruleset, in which case the two files will be\nrecursively merged. Extended rulesets can themselves extend additional rulesets\nup to 20 rulesets deep.\n\nExtend a ruleset by including an \"extends\" top-level key which identifies a URL\nor file path:\n\n```JavaScript\n{\n  \"extends\": \"https://raw.githubusercontent.com/todogroup/repolinter/master/rulesets/default.json\"\n  \"rules\": {\n    # disable CI check\n    \"integrates-with-ci\": {\n      \"level\": \"off\"\n    }\n  }\n}\n```\n\n```YAML\nextends: https://raw.githubusercontent.com/todogroup/repolinter/master/rulesets/default.json\nrules:\n  # disable CI check\n  integrates-with-ci\n    level: off\n    ...\n```\n\nRelative paths are resolved relative to the location used to access the\nextending file.  For example, if repolinter is invoked as:\n\n```\nrepolinter -u http://example.com/custom-rules.yaml\n```\n\nAnd that ruleset includes `extends: \"./default.yaml\"`, the path will be resolved\nrelative to the original URL as `http://example.com/default.yaml`.  If instead\nrepolinter is invoked as:\n\n```\nrepolinter -r /etc/repolinter/custom-rules.yaml\n```\n\nAnd that ruleset includes `extends: \"./default.yaml\"`, the path will be resolved\nrelative to the original file path as `/etc/repolinter/default.yaml`.\n\nYAML and JSON rulesets can be extended from either format.\n\n## API\n\nRepolinter also includes an extensible JavaScript API:\n\n```JavaScript\nconst repolinter = require('repolinter')\nconst result = await repolinter.lint('.')\n```\n\nThis API allows the developer to have complete control over the configuration and formatting Repolinter should use. Documentation for this library can be found under [API Documentation](https://todogroup.github.io/repolinter/#api-reference).\n\n## Going Further\n\n- [Rule Reference](./docs/rules.md)\n- [Fix Reference](./docs/fixes.md)\n- [Axiom Reference](./docs/axioms.md)\n- [API Reference](https://todogroup.github.io/repolinter/#api-reference)\n- [Developer Guide](./docs/development.md)\n\n## License\n\nThis project is licensed under the [Apache 2.0](LICENSE) license.\n","funding_links":[],"categories":["Project Quality","Uncategorized","JavaScript"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftodogroup%2Frepolinter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftodogroup%2Frepolinter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftodogroup%2Frepolinter/lists"}