@theglitchking/gimme-the-lint 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +4 -3
- package/.claude-plugin/plugin.json +4 -3
- package/CHANGELOG.md +19 -0
- package/README.md +37 -19
- package/lib/adapters/ansible.js +99 -0
- package/lib/adapters/index.js +2 -0
- package/lib/linter-configs.js +1 -0
- package/lib/project-model.js +2 -0
- package/package.json +5 -3
- package/templates/.ansible-lint.template.yml +20 -0
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Official marketplace for gimme-the-lint - polyglot progressive linting with per-app baselines and drift detection",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.2.0"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "gimme-the-lint",
|
|
14
|
-
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, and
|
|
15
|
-
"version": "2.
|
|
14
|
+
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, Terraform, and Ansible.",
|
|
15
|
+
"version": "2.2.0",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "TheGlitchKing"
|
|
18
18
|
},
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"clippy",
|
|
33
33
|
"tflint",
|
|
34
34
|
"terraform",
|
|
35
|
+
"ansible-lint",
|
|
35
36
|
"claude-code"
|
|
36
37
|
],
|
|
37
38
|
"category": "productivity",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gimme-the-lint",
|
|
3
|
-
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, and
|
|
4
|
-
"version": "2.
|
|
3
|
+
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, Terraform, and Ansible.",
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TheGlitchKing",
|
|
7
7
|
"email": "theglitchking@users.noreply.github.com"
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"golangci-lint",
|
|
22
22
|
"clippy",
|
|
23
23
|
"tflint",
|
|
24
|
-
"terraform"
|
|
24
|
+
"terraform",
|
|
25
|
+
"ansible-lint"
|
|
25
26
|
]
|
|
26
27
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.2.0] - 2026-05-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Ansible support** via a new `ansible-lint` adapter. ansible-lint plugs into
|
|
12
|
+
the progressive-lint engine like every other linter: it runs
|
|
13
|
+
`ansible-lint -f codeclimate`, parses the CodeClimate JSON report, and only
|
|
14
|
+
new violations block. Supports `--fix`.
|
|
15
|
+
- **Manifest-based discovery** for Ansible: a directory containing `ansible.cfg`
|
|
16
|
+
or `galaxy.yml` is auto-discovered and bound to `ansible-lint`. Ansible
|
|
17
|
+
playbooks are plain YAML with no manifest, so detection keys off those
|
|
18
|
+
unambiguous markers rather than a file extension (a YAML scan would match
|
|
19
|
+
nearly every repo). An Ansible repo with neither marker needs an explicit
|
|
20
|
+
`apps` entry in `gimme-the-lint.config.js`.
|
|
21
|
+
- **Ansible best-practice config** — `install` seeds `.ansible-lint` with the
|
|
22
|
+
`moderate` profile (the strictness lever; raise to `safety` / `production`).
|
|
23
|
+
- README now documents every supported codebase with a default-rules summary
|
|
24
|
+
and the strictness lever for each; `.documentation/lint-rules-guide.md` adds
|
|
25
|
+
a full Ansible section.
|
|
26
|
+
|
|
8
27
|
## [2.1.0] - 2026-05-17
|
|
9
28
|
|
|
10
29
|
### Added
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ stuff at its own pace; meanwhile no new mess gets in.
|
|
|
19
19
|
**v2.0** generalizes that idea to any linter and any language. It is no longer
|
|
20
20
|
"ESLint + Ruff for webapps" — it is a progressive-lint **engine** with a
|
|
21
21
|
pluggable **linter adapter** for each tool, across **JavaScript/TypeScript, Python,
|
|
22
|
-
Go, Rust, and
|
|
22
|
+
Go, Rust, Terraform, and Ansible**, in **any monorepo shape**.
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -38,10 +38,10 @@ is ever flagged. (In v1 this job was outsourced to the third-party
|
|
|
38
38
|
|
|
39
39
|
Each app is bound to the linters its package manifest implies — `package.json`
|
|
40
40
|
→ ESLint, `pyproject.toml` → Ruff, `go.mod` → golangci-lint, `Cargo.toml` →
|
|
41
|
-
Clippy, `biome.json` → Biome.
|
|
42
|
-
`*.tf` / `*.tofu` files binds to
|
|
43
|
-
app, so a config or linter-version
|
|
44
|
-
of another.
|
|
41
|
+
Clippy, `biome.json` → Biome, `ansible.cfg` / `galaxy.yml` → ansible-lint.
|
|
42
|
+
Terraform has no manifest, so a directory of `*.tf` / `*.tofu` files binds to
|
|
43
|
+
tflint by extension. Drift detection runs per app, so a config or linter-version
|
|
44
|
+
change in one app never churns the baselines of another.
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
@@ -50,7 +50,7 @@ of another.
|
|
|
50
50
|
- **Progressive linting** — only new violations block; existing ones are baselined
|
|
51
51
|
- **In-house diff engine** — line/column-independent fingerprints survive code shifts
|
|
52
52
|
- **Pluggable linter adapters** — the choice of linter is config, not a hardcode
|
|
53
|
-
- **Polyglot** — JavaScript/TypeScript, Python, Go, Rust, Terraform out of the box
|
|
53
|
+
- **Polyglot** — JavaScript/TypeScript, Python, Go, Rust, Terraform, Ansible out of the box
|
|
54
54
|
- **Per-app model** — auto-discovers every package in a monorepo; no `frontend/`
|
|
55
55
|
+ `backend/` assumption
|
|
56
56
|
- **Per-app drift detection** — app add/remove, config change, linter version, age
|
|
@@ -75,21 +75,37 @@ of another.
|
|
|
75
75
|
| Go | `golangci-lint` | `go.mod` |
|
|
76
76
|
| Rust | `clippy` (`cargo clippy`) | `Cargo.toml` |
|
|
77
77
|
| Terraform / OpenTofu | `tflint` | `*.tf` / `*.tofu` files (no manifest) |
|
|
78
|
+
| Ansible | `ansible-lint` | `ansible.cfg`, `galaxy.yml` |
|
|
78
79
|
|
|
79
80
|
## Shipped lint configs
|
|
80
81
|
|
|
81
82
|
`install` seeds every discovered app with a best-practice ("recommended" tier)
|
|
82
|
-
config for its linter —
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
`
|
|
91
|
-
|
|
92
|
-
|
|
83
|
+
config for its linter — **created only if absent**, so your own config is never
|
|
84
|
+
overwritten. Each ships a sensible default rule set and a single **lever** to
|
|
85
|
+
dial strictness up or down:
|
|
86
|
+
|
|
87
|
+
| Codebase | Linter | Default rules (recommended tier) | Strictness lever |
|
|
88
|
+
|----------|--------|----------------------------------|------------------|
|
|
89
|
+
| JS/TS | ESLint | `@eslint/js` + React recommended, import-architecture guards, security plugins, Prettier-compatible | rules block in `eslint.config.js` |
|
|
90
|
+
| JS/TS | Biome | recommended set + full `security` group + console/complexity rules | rule levels in `biome.json` |
|
|
91
|
+
| Python | Ruff | pyflakes / pycodestyle / isort / bugbear / pyupgrade + `S` security + comprehensions / simplify | `select` / `ignore` in `pyproject.toml` |
|
|
92
|
+
| Go | golangci-lint | `standard` set + correctness & quality linters + `gosec` | `linters.enable` in `.golangci.yml` |
|
|
93
|
+
| Rust | Clippy | `pedantic` + `cargo` at `warn`, noisy lints allowed back | `[lints.clippy]` levels in `Cargo.toml` |
|
|
94
|
+
| Terraform | tflint | bundled `terraform` ruleset, `recommended` preset | `preset` in `.tflint.hcl` (`recommended` → `all`) |
|
|
95
|
+
| Ansible | ansible-lint | `moderate` profile | `profile` in `.ansible-lint` (`min` → `production`) |
|
|
96
|
+
| Secrets (all) | gitleaks | default ruleset + key / password rules — **always blocks** | `[allowlist]` in `.gitleaks.toml` |
|
|
97
|
+
|
|
98
|
+
Every shipped config carries a **security layer**. gitleaks scans every file in
|
|
99
|
+
every codebase for secrets (passwords, SSL/private keys, tokens) and always
|
|
100
|
+
blocks — secrets are never baselined. Each linter adds language-specific
|
|
101
|
+
security rules on top (`gosec`, Ruff `S` / flake8-bandit, `eslint-plugin-security`,
|
|
102
|
+
Biome's `security` group), which follow normal progressive baselining.
|
|
103
|
+
|
|
104
|
+
To go stricter, pull the lever in the table above — because violations are
|
|
105
|
+
progressively baselined, raising strictness never blocks existing code, only new
|
|
106
|
+
code is held to the higher bar. Full per-codebase detail — every default rule
|
|
107
|
+
and how to adjust it — is in
|
|
108
|
+
[`.documentation/lint-rules-guide.md`](.documentation/lint-rules-guide.md).
|
|
93
109
|
|
|
94
110
|
---
|
|
95
111
|
|
|
@@ -284,7 +300,8 @@ lib/
|
|
|
284
300
|
├── diff-engine.js pure diff: new vs baselined vs fixed
|
|
285
301
|
├── baseline-store.js one baseline.json format for every linter
|
|
286
302
|
├── adapters/ one adapter per linter (eslint, biome, ruff,
|
|
287
|
-
│ golangci-lint, clippy, tflint)
|
|
303
|
+
│ golangci-lint, clippy, tflint, ansible-lint)
|
|
304
|
+
│ + the base contract
|
|
288
305
|
├── project-model.js discovers apps + binds them to linters
|
|
289
306
|
├── units.js resolves apps → {dir, linters, baseline path}
|
|
290
307
|
├── check.js runCheck: lint → diff → report
|
|
@@ -304,7 +321,8 @@ git hooks, GitHub Action and Claude Code plugin are thin front doors over it.
|
|
|
304
321
|
- **Node.js** >= 20
|
|
305
322
|
- **Git** (for hooks and staged-file detection)
|
|
306
323
|
- A linter for each language you use (`eslint`/`biome`, `ruff`, `golangci-lint`,
|
|
307
|
-
`clippy`, `tflint`) — any language whose linter is absent is
|
|
324
|
+
`clippy`, `tflint`, `ansible-lint`) — any language whose linter is absent is
|
|
325
|
+
simply skipped
|
|
308
326
|
|
|
309
327
|
## License
|
|
310
328
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { LinterAdapter } = require('./adapter');
|
|
4
|
+
const { createViolation, SEVERITY } = require('../violation');
|
|
5
|
+
|
|
6
|
+
// ansible-lint adapter. ansible-lint is the de-facto linter for Ansible
|
|
7
|
+
// playbooks, roles and collections; `-f codeclimate` emits a machine-readable
|
|
8
|
+
// JSON report. Ansible has no manifest file and playbooks are plain YAML, so
|
|
9
|
+
// detection keys off the unambiguous Ansible markers `ansible.cfg` and
|
|
10
|
+
// `galaxy.yml` — a YAML extension scan would match virtually every repo.
|
|
11
|
+
// ansible-lint auto-discovers playbooks/roles from the directory it runs in.
|
|
12
|
+
|
|
13
|
+
const ANSIBLE_CONFIG_FILES = ['.ansible-lint', '.config/ansible-lint.yml'];
|
|
14
|
+
|
|
15
|
+
/** Map an ansible-lint (CodeClimate) severity onto a NormalizedViolation severity. */
|
|
16
|
+
function mapSeverity(severity) {
|
|
17
|
+
switch (String(severity).toLowerCase()) {
|
|
18
|
+
case 'info':
|
|
19
|
+
return SEVERITY.INFO;
|
|
20
|
+
case 'minor':
|
|
21
|
+
return SEVERITY.WARNING;
|
|
22
|
+
case 'major':
|
|
23
|
+
case 'critical':
|
|
24
|
+
case 'blocker':
|
|
25
|
+
return SEVERITY.ERROR;
|
|
26
|
+
default:
|
|
27
|
+
return SEVERITY.WARNING;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class AnsibleLintAdapter extends LinterAdapter {
|
|
32
|
+
get id() {
|
|
33
|
+
return 'ansible-lint';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get languages() {
|
|
37
|
+
return ['ansible'];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get supportsFix() {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get manifestFiles() {
|
|
45
|
+
return ['ansible.cfg', 'galaxy.yml'];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Ansible source is plain YAML — far too broad to scan by extension, so
|
|
49
|
+
// detection is manifest-only (see manifestFiles).
|
|
50
|
+
get sourceExtensions() {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
configFiles() {
|
|
55
|
+
return ANSIBLE_CONFIG_FILES;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
buildCommand(targets, opts = {}) {
|
|
59
|
+
const args = ['-f', 'codeclimate'];
|
|
60
|
+
if (opts.fix && this.supportsFix) args.push('--fix');
|
|
61
|
+
const paths = targets && targets.length ? targets.slice() : ['.'];
|
|
62
|
+
args.push(...paths);
|
|
63
|
+
return { cmd: this.binary, args, cwd: opts.cwd || this.projectRoot };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
parse(stdout) {
|
|
67
|
+
const text = (stdout || '').trim();
|
|
68
|
+
if (!text) return [];
|
|
69
|
+
|
|
70
|
+
let report;
|
|
71
|
+
try {
|
|
72
|
+
report = JSON.parse(text);
|
|
73
|
+
} catch {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
if (!Array.isArray(report)) return [];
|
|
77
|
+
|
|
78
|
+
return report.map((issue) => {
|
|
79
|
+
const loc = issue.location || {};
|
|
80
|
+
const lines = loc.lines || {};
|
|
81
|
+
const begin = (loc.positions && loc.positions.begin) || {};
|
|
82
|
+
// CodeClimate locations come as either { lines: { begin } } or
|
|
83
|
+
// { positions: { begin: { line, column } } }.
|
|
84
|
+
let line = lines.begin != null ? lines.begin : begin.line;
|
|
85
|
+
if (line && typeof line === 'object') line = line.line;
|
|
86
|
+
return createViolation({
|
|
87
|
+
file: this._relativize(loc.path || ''),
|
|
88
|
+
line: Number(line) || 0,
|
|
89
|
+
col: Number(begin.column) || 0,
|
|
90
|
+
ruleId: issue.check_name || 'ansible-lint',
|
|
91
|
+
severity: mapSeverity(issue.severity),
|
|
92
|
+
message: issue.description || '',
|
|
93
|
+
source: 'ansible-lint',
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = AnsibleLintAdapter;
|
package/lib/adapters/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const RuffAdapter = require('./ruff');
|
|
|
7
7
|
const GolangciLintAdapter = require('./golangci-lint');
|
|
8
8
|
const ClippyAdapter = require('./clippy');
|
|
9
9
|
const TflintAdapter = require('./tflint');
|
|
10
|
+
const AnsibleLintAdapter = require('./ansible');
|
|
10
11
|
|
|
11
12
|
// The adapter registry. `tool` strings in gimme-the-lint.config.js resolve to
|
|
12
13
|
// concrete adapters here. Adding a language to gimme-the-lint means adding one
|
|
@@ -19,6 +20,7 @@ const REGISTRY = {
|
|
|
19
20
|
'golangci-lint': GolangciLintAdapter,
|
|
20
21
|
clippy: ClippyAdapter,
|
|
21
22
|
tflint: TflintAdapter,
|
|
23
|
+
'ansible-lint': AnsibleLintAdapter,
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
/** Construct an adapter instance by id. Throws on an unknown id. */
|
package/lib/linter-configs.js
CHANGED
|
@@ -23,6 +23,7 @@ const LINTER_CONFIGS = {
|
|
|
23
23
|
'golangci-lint': { template: '.golangci.template.yml', dest: '.golangci.yml' },
|
|
24
24
|
tflint: { template: '.tflint.template.hcl', dest: '.tflint.hcl' },
|
|
25
25
|
clippy: { template: 'clippy.template.toml', dest: 'clippy.toml' },
|
|
26
|
+
'ansible-lint': { template: '.ansible-lint.template.yml', dest: '.ansible-lint' },
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
/** Copy one template into an app dir, create-if-absent. */
|
package/lib/project-model.js
CHANGED
|
@@ -21,6 +21,8 @@ const MANIFEST_LINTERS = {
|
|
|
21
21
|
'requirements.txt': 'ruff',
|
|
22
22
|
'go.mod': 'golangci-lint',
|
|
23
23
|
'Cargo.toml': 'clippy',
|
|
24
|
+
'ansible.cfg': 'ansible-lint',
|
|
25
|
+
'galaxy.yml': 'ansible-lint',
|
|
24
26
|
};
|
|
25
27
|
|
|
26
28
|
// Terraform / OpenTofu have no manifest file — a directory of *.tf (or *.tofu)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theglitchking/gimme-the-lint",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, and
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Polyglot progressive linting for monorepos — adapter-driven baselines, per-app drift detection, and idempotent skips across JavaScript/TypeScript, Python, Go, Rust, Terraform, and Ansible.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"linting",
|
|
7
7
|
"progressive-linting",
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"rust",
|
|
24
24
|
"tflint",
|
|
25
25
|
"terraform",
|
|
26
|
-
"opentofu"
|
|
26
|
+
"opentofu",
|
|
27
|
+
"ansible-lint",
|
|
28
|
+
"ansible"
|
|
27
29
|
],
|
|
28
30
|
"author": {
|
|
29
31
|
"name": "TheGlitchKing",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Generated by gimme-the-lint — ansible-lint (recommended tier)
|
|
2
|
+
#
|
|
3
|
+
# `profile` is ansible-lint's strictness lever, from least to most strict:
|
|
4
|
+
# min -> basic -> moderate -> safety -> shared -> production
|
|
5
|
+
# "moderate" is the recommended baseline. Raise to "safety" or "production"
|
|
6
|
+
# for stricter enforcement.
|
|
7
|
+
profile: moderate
|
|
8
|
+
|
|
9
|
+
exclude_paths:
|
|
10
|
+
- .cache/
|
|
11
|
+
- .git/
|
|
12
|
+
- molecule/
|
|
13
|
+
|
|
14
|
+
# Downgrade specific rules to non-blocking warnings:
|
|
15
|
+
# warn_list:
|
|
16
|
+
# - experimental
|
|
17
|
+
#
|
|
18
|
+
# Skip specific rules entirely:
|
|
19
|
+
# skip_list:
|
|
20
|
+
# - yaml[line-length]
|