eslint-plugin-traceability 1.0.0 → 1.0.2
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/.github/workflows/ci-cd.yml +42 -5
- package/.voder/history.md +170 -140
- package/.voder/implementation-progress.md +113 -112
- package/.voder/last-action.md +118 -85
- package/.voder/plan.md +7 -10
- package/.voder/progress-chart.png +0 -0
- package/.voder/progress-log-areas.csv +1 -0
- package/.voder/progress-log.csv +1 -0
- package/CHANGELOG.md +10 -3
- package/docs/decisions/004-automated-version-bumping-for-ci-cd.md +165 -0
- package/lib/tests/basic.test.js +1 -1
- package/lib/tests/index.test.js +5 -1
- package/lib/tests/integration/file-validation.test.js +16 -5
- package/lib/tests/integration/plugin-validation.test.js +64 -58
- package/lib/tests/maintenance/detect-isolated.test.js +6 -1
- package/lib/tests/rules/require-branch-annotation.test.js +5 -3
- package/lib/tests/rules/require-story-annotation.test.js +1 -0
- package/package.json +1 -1
- package/tests/basic.test.ts +1 -1
- package/tests/index.test.ts +5 -1
- package/tests/integration/file-validation.test.ts +16 -5
- package/tests/integration/plugin-validation.test.ts +68 -63
- package/tests/maintenance/detect-isolated.test.ts +7 -3
- package/tests/rules/require-branch-annotation.test.ts +5 -3
- package/tests/rules/require-story-annotation.test.ts +1 -0
package/.voder/plan.md
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
## NOW
|
|
2
|
-
|
|
2
|
+
Standardize all test file headers under `tests/` to use JSDoc block comments with proper `@story` and `@req` annotations, replacing any inline comments for traceability.
|
|
3
3
|
|
|
4
4
|
## NEXT
|
|
5
|
-
-
|
|
6
|
-
- Add
|
|
7
|
-
-
|
|
8
|
-
- Replace the separate `ci.yml` and `deploy.yml` workflows with a single `.github/workflows/ci-cd.yml` that on every push to `main` runs build, lint, type-check, test, audit, and then publishes to npm.
|
|
9
|
-
- Remove or disable the old `deploy.yml` and adjust any branch/tag filters so only `ci-cd.yml` handles publishing.
|
|
5
|
+
- Refactor test bodies to adopt explicit GIVEN-WHEN-THEN (Arrange-Act-Assert) structure and eliminate any custom logic (e.g. sorting/flatMap) in expectations.
|
|
6
|
+
- Add a post-deployment smoke-test job to `.github/workflows/ci-cd.yml` that installs the freshly published package in a clean workspace and executes the `cli-integration.js` script.
|
|
7
|
+
- Incorporate `cli-integration.js` into the CI “quality-checks” job so the pipeline mirrors the Husky pre-push behavior.
|
|
10
8
|
|
|
11
9
|
## LATER
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- Introduce a scheduled dependency/vulnerability audit job in CI to catch new advisories early.
|
|
10
|
+
- Write additional edge-case unit tests to cover any uncovered branches in the maintenance utilities.
|
|
11
|
+
- Monitor and optimize test execution times to keep unit tests fast (<100 ms each).
|
|
12
|
+
- Once testing and version-control improvements push both support areas above 90%, perform a full functionality reassessment.
|
|
Binary file
|
package/.voder/progress-log.csv
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -2,17 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [1.0.
|
|
5
|
+
## [1.0.1] - 2025-11-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Detailed API documentation in `user-docs/api-reference.md`
|
|
9
|
+
- New usage examples in `user-docs/examples.md`
|
|
6
10
|
|
|
7
11
|
### Changed
|
|
12
|
+
- Updated `README.md` with advanced usage instructions and migration guide
|
|
13
|
+
- Consolidated CI workflows into a unified GitHub Actions pipeline
|
|
14
|
+
|
|
15
|
+
## [1.0.0] - 2025-11-16
|
|
8
16
|
|
|
17
|
+
### Changed
|
|
9
18
|
- Bumped version to 1.0.0 in package.json.
|
|
10
19
|
- Aligned CHANGELOG with package.json version.
|
|
11
20
|
|
|
12
21
|
## [0.1.0] - 2025-11-16
|
|
13
22
|
|
|
14
23
|
### Added
|
|
15
|
-
|
|
16
24
|
- Initial release of `eslint-plugin-traceability`:
|
|
17
25
|
- `require-story-annotation`
|
|
18
26
|
- `require-req-annotation`
|
|
@@ -27,5 +35,4 @@ All notable changes to this project will be documented in this file.
|
|
|
27
35
|
- Comprehensive tests covering core validation rules.
|
|
28
36
|
|
|
29
37
|
### Fixed
|
|
30
|
-
|
|
31
38
|
- N/A
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
status: "proposed"
|
|
3
|
+
date: 2025-11-17
|
|
4
|
+
decision-makers: [Development Team]
|
|
5
|
+
consulted:
|
|
6
|
+
[
|
|
7
|
+
npm Documentation,
|
|
8
|
+
GitHub Actions Best Practices,
|
|
9
|
+
Semantic Versioning Specification,
|
|
10
|
+
]
|
|
11
|
+
informed: [Project Stakeholders, CI/CD Pipeline Maintainers]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Automated Version Bumping for CI/CD Publishing
|
|
15
|
+
|
|
16
|
+
## Context and Problem Statement
|
|
17
|
+
|
|
18
|
+
The current CI/CD pipeline attempts to publish the package to npm on every push to the main branch, but lacks any mechanism to automatically increment the package version. This causes publish failures when the same version number already exists on npm, as npm does not allow republishing the same version. The pipeline fails with errors like "You cannot publish over the previously published versions" or similar npm publish conflicts.
|
|
19
|
+
|
|
20
|
+
Currently, version bumping requires manual intervention through direct package.json edits, which is error-prone, interrupts the automated delivery flow, and creates a disconnect between the continuous integration process and package publishing. This breaks the principle of continuous delivery and creates friction in the development workflow.
|
|
21
|
+
|
|
22
|
+
## Decision Drivers
|
|
23
|
+
|
|
24
|
+
- Need for reliable automated publishing without manual intervention
|
|
25
|
+
- Prevention of npm publish failures due to version conflicts
|
|
26
|
+
- Alignment with semantic versioning principles for clear change communication
|
|
27
|
+
- Integration with existing CI/CD pipeline and GitHub workflow
|
|
28
|
+
- Maintainability of version history and changelog automation
|
|
29
|
+
- Support for different types of releases (patch, minor, major)
|
|
30
|
+
- Traceability of version changes to specific commits or pull requests
|
|
31
|
+
- Minimal friction for developers while maintaining version discipline
|
|
32
|
+
|
|
33
|
+
## Considered Options
|
|
34
|
+
|
|
35
|
+
- npm version command with automated execution in CI/CD
|
|
36
|
+
- Semantic Release with automated version detection
|
|
37
|
+
- Manual version bumping with CI/CD workflow triggers
|
|
38
|
+
- Version bumping through GitHub Actions with npm version
|
|
39
|
+
|
|
40
|
+
## Decision Outcome
|
|
41
|
+
|
|
42
|
+
Chosen option: "npm version command with automated execution in CI/CD", because it provides direct integration with npm tooling, maintains simplicity in the CI/CD pipeline, allows for both automated and manual control when needed, and follows established npm ecosystem practices without requiring complex semantic analysis tooling.
|
|
43
|
+
|
|
44
|
+
### Implementation Strategy
|
|
45
|
+
|
|
46
|
+
The CI/CD pipeline will be modified to:
|
|
47
|
+
|
|
48
|
+
1. **Pre-publish Version Check**: Before attempting to publish, check if the current package.json version already exists on npm
|
|
49
|
+
2. **Automatic Patch Increment**: If the version exists, automatically increment the patch version using `npm version patch`
|
|
50
|
+
3. **Commit and Tag**: Create a version commit and git tag as part of the pipeline
|
|
51
|
+
4. **Publish with New Version**: Proceed with npm publish using the incremented version
|
|
52
|
+
5. **Changelog Update**: Automatically update CHANGELOG.md with the new version entry
|
|
53
|
+
|
|
54
|
+
### Consequences
|
|
55
|
+
|
|
56
|
+
- Good, because prevents all npm publish failures due to version conflicts
|
|
57
|
+
- Good, because maintains automated delivery without manual intervention
|
|
58
|
+
- Good, because creates proper git tags and version history
|
|
59
|
+
- Good, because uses standard npm tooling that developers understand
|
|
60
|
+
- Good, because allows for emergency manual version bumps when needed
|
|
61
|
+
- Good, because integrates cleanly with existing CI/CD infrastructure
|
|
62
|
+
- Neutral, because requires CI/CD pipeline to have git write access
|
|
63
|
+
- Neutral, because creates additional commits in the main branch for version bumps
|
|
64
|
+
- Bad, because does not automatically determine semantic version type (major/minor/patch)
|
|
65
|
+
- Bad, because may create noise in git history with automated version commits
|
|
66
|
+
|
|
67
|
+
### Confirmation
|
|
68
|
+
|
|
69
|
+
Implementation compliance will be confirmed through:
|
|
70
|
+
|
|
71
|
+
- CI/CD pipeline successfully publishes without version conflicts
|
|
72
|
+
- Git repository contains version tags matching published npm versions
|
|
73
|
+
- CHANGELOG.md automatically updated with version entries
|
|
74
|
+
- No manual intervention required for routine publishing
|
|
75
|
+
- Version bumps traceable through git commit history
|
|
76
|
+
- package.json version always synchronized with published npm version
|
|
77
|
+
|
|
78
|
+
## Pros and Cons of the Options
|
|
79
|
+
|
|
80
|
+
### npm version command with automated execution in CI/CD
|
|
81
|
+
|
|
82
|
+
Standard npm tooling with CI/CD automation provides reliable version management with minimal complexity.
|
|
83
|
+
|
|
84
|
+
- Good, because uses native npm version management tools
|
|
85
|
+
- Good, because creates proper git tags and version commits automatically
|
|
86
|
+
- Good, because simple to understand and maintain in CI/CD
|
|
87
|
+
- Good, because allows manual override for major/minor version bumps
|
|
88
|
+
- Good, because integrates with existing npm publish workflow
|
|
89
|
+
- Good, because provides immediate resolution to publish failures
|
|
90
|
+
- Good, because maintains compatibility with npm ecosystem tools
|
|
91
|
+
- Neutral, because requires configuration of git credentials in CI/CD
|
|
92
|
+
- Neutral, because creates automated commits that may clutter history
|
|
93
|
+
- Bad, because defaults to patch-level increments only
|
|
94
|
+
- Bad, because does not analyze commit messages for semantic versioning
|
|
95
|
+
|
|
96
|
+
### Semantic Release with automated version detection
|
|
97
|
+
|
|
98
|
+
Automated semantic versioning based on commit message analysis and release automation.
|
|
99
|
+
|
|
100
|
+
- Good, because fully automated semantic version determination
|
|
101
|
+
- Good, because analyzes commit messages for version type
|
|
102
|
+
- Good, because comprehensive release note generation
|
|
103
|
+
- Good, because follows semantic versioning specification strictly
|
|
104
|
+
- Good, because popular in open source ecosystem
|
|
105
|
+
- Neutral, because requires standardized commit message format
|
|
106
|
+
- Bad, because adds significant complexity to CI/CD pipeline
|
|
107
|
+
- Bad, because requires team discipline for commit message formatting
|
|
108
|
+
- Bad, because may be overkill for the current project size
|
|
109
|
+
- Bad, because introduces external dependency on semantic-release tool
|
|
110
|
+
- Bad, because harder to override for exceptional cases
|
|
111
|
+
|
|
112
|
+
### Manual version bumping with CI/CD workflow triggers
|
|
113
|
+
|
|
114
|
+
Requiring manual version increments before publishing with workflow validation.
|
|
115
|
+
|
|
116
|
+
- Good, because provides full developer control over versioning
|
|
117
|
+
- Good, because ensures deliberate version decisions
|
|
118
|
+
- Good, because no automated commits or git history noise
|
|
119
|
+
- Good, because simple to understand and implement
|
|
120
|
+
- Neutral, because requires developer discipline for version management
|
|
121
|
+
- Bad, because breaks continuous delivery principle
|
|
122
|
+
- Bad, because requires manual intervention for every release
|
|
123
|
+
- Bad, because prone to human error and forgotten version bumps
|
|
124
|
+
- Bad, because does not solve the original npm publish failure problem
|
|
125
|
+
- Bad, because creates friction in development workflow
|
|
126
|
+
|
|
127
|
+
### Version bumping through GitHub Actions with npm version
|
|
128
|
+
|
|
129
|
+
GitHub Actions-specific tooling for automated version management within the existing platform.
|
|
130
|
+
|
|
131
|
+
- Good, because native integration with GitHub workflow ecosystem
|
|
132
|
+
- Good, because can leverage GitHub-specific features like releases
|
|
133
|
+
- Good, because may provide better integration with pull request workflows
|
|
134
|
+
- Good, because uses familiar GitHub Actions patterns
|
|
135
|
+
- Neutral, because similar capabilities to npm version approach
|
|
136
|
+
- Bad, because locks solution to GitHub Actions platform specifically
|
|
137
|
+
- Bad, because may require additional GitHub Actions marketplace dependencies
|
|
138
|
+
- Bad, because potentially less portable to other CI/CD systems
|
|
139
|
+
- Bad, because npm version command is more universally understood
|
|
140
|
+
|
|
141
|
+
## More Information
|
|
142
|
+
|
|
143
|
+
This decision addresses the immediate CI/CD publish failures while establishing a foundation for reliable automated delivery. The implementation should be flexible enough to support future migration to semantic release if the project grows to require more sophisticated version management.
|
|
144
|
+
|
|
145
|
+
Key implementation considerations:
|
|
146
|
+
|
|
147
|
+
- Configure CI/CD pipeline with appropriate git credentials for version commits
|
|
148
|
+
- Set up git user configuration for automated commits
|
|
149
|
+
- Ensure version tags follow consistent naming convention (v1.0.0 format)
|
|
150
|
+
- Update CHANGELOG.md generation to work with automated version increments
|
|
151
|
+
- Consider branch protection rules that allow CI/CD version commits
|
|
152
|
+
- Document manual override process for major/minor version bumps
|
|
153
|
+
|
|
154
|
+
This decision should be re-evaluated if:
|
|
155
|
+
|
|
156
|
+
- Project adopts semantic versioning discipline across the team
|
|
157
|
+
- Commit message standardization becomes feasible
|
|
158
|
+
- Publishing frequency increases significantly requiring more sophisticated automation
|
|
159
|
+
- The simple patch increment approach becomes insufficient for change communication
|
|
160
|
+
|
|
161
|
+
Related resources:
|
|
162
|
+
|
|
163
|
+
- [npm version command documentation](https://docs.npmjs.com/cli/v9/commands/npm-version)
|
|
164
|
+
- [GitHub Actions CI/CD Best Practices](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments)
|
|
165
|
+
- [Semantic Versioning Specification](https://semver.org/)
|
package/lib/tests/basic.test.js
CHANGED
|
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
/**
|
|
37
|
-
* Tests for
|
|
37
|
+
* Tests for: docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
|
|
38
38
|
* @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
|
|
39
39
|
* @req REQ-PLUGIN-STRUCTURE - plugin exports rules and configs
|
|
40
40
|
*/
|
package/lib/tests/index.test.js
CHANGED
|
@@ -45,6 +45,7 @@ describe("Plugin Default Export and Configs (Story 001.0-DEV-PLUGIN-SETUP)", ()
|
|
|
45
45
|
expect(index_1.default.configs).toBe(index_1.configs);
|
|
46
46
|
});
|
|
47
47
|
it("[REQ-PLUGIN-STRUCTURE] rules object has correct rule names", () => {
|
|
48
|
+
// Arrange: expected rule names in insertion order
|
|
48
49
|
const expected = [
|
|
49
50
|
"require-story-annotation",
|
|
50
51
|
"require-req-annotation",
|
|
@@ -53,7 +54,10 @@ describe("Plugin Default Export and Configs (Story 001.0-DEV-PLUGIN-SETUP)", ()
|
|
|
53
54
|
"valid-story-reference",
|
|
54
55
|
"valid-req-reference",
|
|
55
56
|
];
|
|
56
|
-
|
|
57
|
+
// Act: get actual rule names from plugin
|
|
58
|
+
const actual = Object.keys(index_1.rules);
|
|
59
|
+
// Assert: actual matches expected
|
|
60
|
+
expect(actual).toEqual(expected);
|
|
57
61
|
});
|
|
58
62
|
it("[REQ-RULE-REGISTRY] configs.recommended contains correct rule configuration", () => {
|
|
59
63
|
const recommendedRules = index_1.configs.recommended[0].rules;
|
|
@@ -15,11 +15,10 @@ const eslintBin = path_1.default.resolve(__dirname, "../../node_modules/.bin/esl
|
|
|
15
15
|
const configPath = path_1.default.resolve(__dirname, "../../eslint.config.js");
|
|
16
16
|
describe("File and Req Validation CLI Integration (Story 006.0-DEV-FILE-VALIDATION)", () => {
|
|
17
17
|
function runLint(code, rules) {
|
|
18
|
-
const ruleArgs = [
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
];
|
|
18
|
+
const ruleArgs = ["--rule", "no-unused-vars:off"];
|
|
19
|
+
for (const r of rules) {
|
|
20
|
+
ruleArgs.push("--rule", r);
|
|
21
|
+
}
|
|
23
22
|
return (0, child_process_1.spawnSync)("node", [
|
|
24
23
|
eslintBin,
|
|
25
24
|
"--no-config-lookup",
|
|
@@ -35,26 +34,38 @@ describe("File and Req Validation CLI Integration (Story 006.0-DEV-FILE-VALIDATI
|
|
|
35
34
|
});
|
|
36
35
|
}
|
|
37
36
|
it("[REQ-FILE-EXISTENCE] reports missing story file via CLI", () => {
|
|
37
|
+
// Arrange
|
|
38
38
|
const code = "// @story docs/stories/missing-file.story.md";
|
|
39
|
+
// Act
|
|
39
40
|
const res = runLint(code, ["traceability/valid-story-reference:error"]);
|
|
41
|
+
// Assert
|
|
40
42
|
expect(res.status).toBe(1);
|
|
41
43
|
expect(res.stdout).toContain("Story file");
|
|
42
44
|
});
|
|
43
45
|
it("[REQ-EXTENSION] reports invalid extension via CLI", () => {
|
|
46
|
+
// Arrange
|
|
44
47
|
const code = "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.md";
|
|
48
|
+
// Act
|
|
45
49
|
const res = runLint(code, ["traceability/valid-story-reference:error"]);
|
|
50
|
+
// Assert
|
|
46
51
|
expect(res.status).toBe(1);
|
|
47
52
|
expect(res.stdout).toContain("Invalid story file extension");
|
|
48
53
|
});
|
|
49
54
|
it("[REQ-DEEP-PARSE] reports missing requirement via CLI", () => {
|
|
55
|
+
// Arrange
|
|
50
56
|
const code = "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md\n// @req REQ-UNKNOWN";
|
|
57
|
+
// Act
|
|
51
58
|
const res = runLint(code, ["traceability/valid-req-reference:error"]);
|
|
59
|
+
// Assert
|
|
52
60
|
expect(res.status).toBe(1);
|
|
53
61
|
expect(res.stdout).toContain("Requirement 'REQ-UNKNOWN' not found");
|
|
54
62
|
});
|
|
55
63
|
it("[REQ-DEEP-MATCH] valid story and requirement via CLI", () => {
|
|
64
|
+
// Arrange
|
|
56
65
|
const code = "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md\n// @req REQ-PLUGIN-STRUCTURE";
|
|
66
|
+
// Act
|
|
57
67
|
const res = runLint(code, ["traceability/valid-req-reference:error"]);
|
|
68
|
+
// Assert
|
|
58
69
|
expect(res.status).toBe(0);
|
|
59
70
|
});
|
|
60
71
|
});
|
|
@@ -11,67 +11,73 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
11
11
|
/* eslint-env node, jest */
|
|
12
12
|
const child_process_1 = require("child_process");
|
|
13
13
|
const path_1 = __importDefault(require("path"));
|
|
14
|
+
// Ensure ESLint CLI uses built plugin
|
|
14
15
|
const eslintBin = path_1.default.resolve(__dirname, "../../node_modules/.bin/eslint");
|
|
15
16
|
const configPath = path_1.default.resolve(__dirname, "../../eslint.config.js");
|
|
16
|
-
function runEslint(code, rule) {
|
|
17
|
-
const args = [
|
|
18
|
-
"--no-config-lookup",
|
|
19
|
-
"--config",
|
|
20
|
-
configPath,
|
|
21
|
-
"--stdin",
|
|
22
|
-
"--stdin-filename",
|
|
23
|
-
"foo.js",
|
|
24
|
-
"--rule",
|
|
25
|
-
"no-unused-vars:off",
|
|
26
|
-
"--rule",
|
|
27
|
-
rule,
|
|
28
|
-
];
|
|
29
|
-
// Use Node to run the ESLint CLI script
|
|
30
|
-
return (0, child_process_1.spawnSync)("node", [eslintBin, ...args], {
|
|
31
|
-
encoding: "utf-8",
|
|
32
|
-
input: code,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
const cliTests = [
|
|
36
|
-
{
|
|
37
|
-
name: "[REQ-PLUGIN-STRUCTURE] reports error when @story annotation is missing",
|
|
38
|
-
code: "function foo() {}",
|
|
39
|
-
rule: "traceability/require-story-annotation:error",
|
|
40
|
-
expectedStatus: 1,
|
|
41
|
-
stdoutRegex: /require-story-annotation/,
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: "does not report error when @story annotation is present",
|
|
45
|
-
code: `
|
|
46
|
-
/**
|
|
47
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
48
|
-
*/
|
|
49
|
-
function foo() {}
|
|
50
|
-
`,
|
|
51
|
-
rule: "traceability/require-story-annotation:error",
|
|
52
|
-
expectedStatus: 0,
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: "Require Req Annotation CLI (Story 003.0-DEV-FUNCTION-ANNOTATIONS)",
|
|
56
|
-
code: "function foo() {}",
|
|
57
|
-
rule: "traceability/require-req-annotation:error",
|
|
58
|
-
expectedStatus: 1,
|
|
59
|
-
stdoutRegex: /require-req-annotation/,
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
name: "Require Branch Annotation CLI (Story 004.0-DEV-BRANCH-ANNOTATIONS)",
|
|
63
|
-
code: "if (condition) {}",
|
|
64
|
-
rule: "traceability/require-branch-annotation:error",
|
|
65
|
-
expectedStatus: 1,
|
|
66
|
-
stdoutRegex: /require-branch-annotation/,
|
|
67
|
-
},
|
|
68
|
-
];
|
|
69
17
|
describe("ESLint CLI Integration (Story 001.0-DEV-PLUGIN-SETUP)", () => {
|
|
70
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Helper to run ESLint CLI with the traceability plugin and custom rule
|
|
20
|
+
* @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
|
|
21
|
+
* @req REQ-PLUGIN-STRUCTURE - Invoke ESLint CLI for integration testing
|
|
22
|
+
*/
|
|
23
|
+
function runEslint(code, rule) {
|
|
24
|
+
const args = [
|
|
25
|
+
"--no-config-lookup",
|
|
26
|
+
"--config",
|
|
27
|
+
configPath,
|
|
28
|
+
"--stdin",
|
|
29
|
+
"--stdin-filename",
|
|
30
|
+
"foo.js",
|
|
31
|
+
"--rule",
|
|
32
|
+
"no-unused-vars:off",
|
|
33
|
+
"--rule",
|
|
34
|
+
rule,
|
|
35
|
+
];
|
|
36
|
+
return (0, child_process_1.spawnSync)("node", [eslintBin, ...args], {
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
input: code,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
it("[REQ-PLUGIN-STRUCTURE] reports error when @story annotation is missing", () => {
|
|
42
|
+
// Arrange
|
|
43
|
+
const code = "function foo() {}";
|
|
44
|
+
const rule = "traceability/require-story-annotation:error";
|
|
45
|
+
// Act
|
|
46
|
+
const result = runEslint(code, rule);
|
|
47
|
+
// Assert
|
|
48
|
+
expect(result.status).toBe(1);
|
|
49
|
+
expect(result.stdout).toMatch(/require-story-annotation/);
|
|
50
|
+
});
|
|
51
|
+
it("[REQ-PLUGIN-STRUCTURE] does not report error when @story annotation is present", () => {
|
|
52
|
+
// Arrange
|
|
53
|
+
const code = `/**
|
|
54
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
55
|
+
*/
|
|
56
|
+
function foo() {}`;
|
|
57
|
+
const rule = "traceability/require-story-annotation:error";
|
|
58
|
+
// Act
|
|
59
|
+
const result = runEslint(code, rule);
|
|
60
|
+
// Assert
|
|
61
|
+
expect(result.status).toBe(0);
|
|
62
|
+
});
|
|
63
|
+
it("[REQ-REQ-CLI] reports error when @req annotation is missing", () => {
|
|
64
|
+
// Arrange
|
|
65
|
+
const code = "function foo() {}";
|
|
66
|
+
const rule = "traceability/require-req-annotation:error";
|
|
67
|
+
// Act
|
|
68
|
+
const result = runEslint(code, rule);
|
|
69
|
+
// Assert
|
|
70
|
+
expect(result.status).toBe(1);
|
|
71
|
+
expect(result.stdout).toMatch(/require-req-annotation/);
|
|
72
|
+
});
|
|
73
|
+
it("[REQ-BRANCH-CLI] reports error when branch annotations missing", () => {
|
|
74
|
+
// Arrange
|
|
75
|
+
const code = "if (true) {}";
|
|
76
|
+
const rule = "traceability/require-branch-annotation:error";
|
|
77
|
+
// Act
|
|
71
78
|
const result = runEslint(code, rule);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
79
|
+
// Assert
|
|
80
|
+
expect(result.status).toBe(1);
|
|
81
|
+
expect(result.stdout).toMatch(/require-branch-annotation/);
|
|
76
82
|
});
|
|
77
83
|
});
|
|
@@ -48,6 +48,7 @@ describe("detectStaleAnnotations isolated (Story 009.0-DEV-MAINTENANCE-TOOLS)",
|
|
|
48
48
|
expect(result).toEqual([]);
|
|
49
49
|
});
|
|
50
50
|
it("[REQ-MAINT-DETECT] detects stale annotations in nested directories", () => {
|
|
51
|
+
// Arrange
|
|
51
52
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "tmp-nested-"));
|
|
52
53
|
const nestedDir = path.join(tmpDir, "nested");
|
|
53
54
|
fs.mkdirSync(nestedDir);
|
|
@@ -65,8 +66,12 @@ describe("detectStaleAnnotations isolated (Story 009.0-DEV-MAINTENANCE-TOOLS)",
|
|
|
65
66
|
*/
|
|
66
67
|
`;
|
|
67
68
|
fs.writeFileSync(filePath2, content2, "utf8");
|
|
69
|
+
// Act
|
|
68
70
|
const result = (0, detect_1.detectStaleAnnotations)(tmpDir);
|
|
69
|
-
|
|
71
|
+
// Assert
|
|
72
|
+
expect(result).toHaveLength(2);
|
|
73
|
+
expect(result).toContain("stale1.story.md");
|
|
74
|
+
expect(result).toContain("stale2.story.md");
|
|
70
75
|
});
|
|
71
76
|
it("[REQ-MAINT-DETECT] throws error on permission denied", () => {
|
|
72
77
|
const tmpDir2 = fs.mkdtempSync(path.join(os.tmpdir(), "tmp-perm-"));
|
|
@@ -3,9 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Tests for: docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
8
|
+
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
9
|
+
* @req REQ-BRANCH-DETECTION - Verify require-branch-annotation rule enforces branch annotations
|
|
10
|
+
*/
|
|
9
11
|
const eslint_1 = require("eslint");
|
|
10
12
|
const require_branch_annotation_1 = __importDefault(require("../../src/rules/require-branch-annotation"));
|
|
11
13
|
const ruleTester = new eslint_1.RuleTester({
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
/**
|
|
7
7
|
* Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
8
8
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
9
|
+
* @req REQ-ANNOTATION-REQUIRED - Verify require-story-annotation rule enforces @story annotation on functions
|
|
9
10
|
*/
|
|
10
11
|
const eslint_1 = require("eslint");
|
|
11
12
|
const require_story_annotation_1 = __importDefault(require("../../src/rules/require-story-annotation"));
|
package/package.json
CHANGED
package/tests/basic.test.ts
CHANGED
package/tests/index.test.ts
CHANGED
|
@@ -12,6 +12,7 @@ describe("Plugin Default Export and Configs (Story 001.0-DEV-PLUGIN-SETUP)", ()
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it("[REQ-PLUGIN-STRUCTURE] rules object has correct rule names", () => {
|
|
15
|
+
// Arrange: expected rule names in insertion order
|
|
15
16
|
const expected = [
|
|
16
17
|
"require-story-annotation",
|
|
17
18
|
"require-req-annotation",
|
|
@@ -20,7 +21,10 @@ describe("Plugin Default Export and Configs (Story 001.0-DEV-PLUGIN-SETUP)", ()
|
|
|
20
21
|
"valid-story-reference",
|
|
21
22
|
"valid-req-reference",
|
|
22
23
|
];
|
|
23
|
-
|
|
24
|
+
// Act: get actual rule names from plugin
|
|
25
|
+
const actual = Object.keys(rules);
|
|
26
|
+
// Assert: actual matches expected
|
|
27
|
+
expect(actual).toEqual(expected);
|
|
24
28
|
});
|
|
25
29
|
|
|
26
30
|
it("[REQ-RULE-REGISTRY] configs.recommended contains correct rule configuration", () => {
|
|
@@ -12,11 +12,10 @@ const configPath = path.resolve(__dirname, "../../eslint.config.js");
|
|
|
12
12
|
|
|
13
13
|
describe("File and Req Validation CLI Integration (Story 006.0-DEV-FILE-VALIDATION)", () => {
|
|
14
14
|
function runLint(code: string, rules: string[]) {
|
|
15
|
-
const ruleArgs = [
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
];
|
|
15
|
+
const ruleArgs = ["--rule", "no-unused-vars:off"];
|
|
16
|
+
for (const r of rules) {
|
|
17
|
+
ruleArgs.push("--rule", r);
|
|
18
|
+
}
|
|
20
19
|
return spawnSync(
|
|
21
20
|
"node",
|
|
22
21
|
[
|
|
@@ -37,31 +36,43 @@ describe("File and Req Validation CLI Integration (Story 006.0-DEV-FILE-VALIDATI
|
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
it("[REQ-FILE-EXISTENCE] reports missing story file via CLI", () => {
|
|
39
|
+
// Arrange
|
|
40
40
|
const code = "// @story docs/stories/missing-file.story.md";
|
|
41
|
+
// Act
|
|
41
42
|
const res = runLint(code, ["traceability/valid-story-reference:error"]);
|
|
43
|
+
// Assert
|
|
42
44
|
expect(res.status).toBe(1);
|
|
43
45
|
expect(res.stdout).toContain("Story file");
|
|
44
46
|
});
|
|
45
47
|
|
|
46
48
|
it("[REQ-EXTENSION] reports invalid extension via CLI", () => {
|
|
49
|
+
// Arrange
|
|
47
50
|
const code = "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.md";
|
|
51
|
+
// Act
|
|
48
52
|
const res = runLint(code, ["traceability/valid-story-reference:error"]);
|
|
53
|
+
// Assert
|
|
49
54
|
expect(res.status).toBe(1);
|
|
50
55
|
expect(res.stdout).toContain("Invalid story file extension");
|
|
51
56
|
});
|
|
52
57
|
|
|
53
58
|
it("[REQ-DEEP-PARSE] reports missing requirement via CLI", () => {
|
|
59
|
+
// Arrange
|
|
54
60
|
const code =
|
|
55
61
|
"// @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md\n// @req REQ-UNKNOWN";
|
|
62
|
+
// Act
|
|
56
63
|
const res = runLint(code, ["traceability/valid-req-reference:error"]);
|
|
64
|
+
// Assert
|
|
57
65
|
expect(res.status).toBe(1);
|
|
58
66
|
expect(res.stdout).toContain("Requirement 'REQ-UNKNOWN' not found");
|
|
59
67
|
});
|
|
60
68
|
|
|
61
69
|
it("[REQ-DEEP-MATCH] valid story and requirement via CLI", () => {
|
|
70
|
+
// Arrange
|
|
62
71
|
const code =
|
|
63
72
|
"// @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md\n// @req REQ-PLUGIN-STRUCTURE";
|
|
73
|
+
// Act
|
|
64
74
|
const res = runLint(code, ["traceability/valid-req-reference:error"]);
|
|
75
|
+
// Assert
|
|
65
76
|
expect(res.status).toBe(0);
|
|
66
77
|
});
|
|
67
78
|
});
|