@synoikia/create-plugin 0.6.1 → 0.8.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.
Files changed (72) hide show
  1. package/README.md +2 -13
  2. package/dist/cli.js +0 -4
  3. package/dist/cli.js.map +1 -1
  4. package/dist/scaffold.js +1 -6
  5. package/dist/scaffold.js.map +1 -1
  6. package/package.json +3 -3
  7. package/templates/plugin/common/README.md +9 -8
  8. package/templates/repo/base/README.md +34 -8
  9. package/templates/repo/base/_github/workflows/ci.yml +13 -2
  10. package/templates/repo/base/_gitignore +1 -0
  11. package/templates/repo/base/_gitleaks.toml +3 -0
  12. package/templates/repo/base/_prettierignore +2 -0
  13. package/templates/repo/base/package.json +2 -13
  14. package/templates/repo/claude/CLAUDE.md +17 -30
  15. package/templates/repo/claude/_claude/guard-paths.json +17 -0
  16. package/templates/repo/claude/_claude/hooks/check-plugins.mjs +39 -0
  17. package/templates/repo/claude/_claude/hooks/session-start.sh +8 -9
  18. package/templates/repo/claude/_claude/settings.json +17 -17
  19. package/dist/workflow/branch.d.ts +0 -2
  20. package/dist/workflow/branch.js +0 -31
  21. package/dist/workflow/branch.js.map +0 -1
  22. package/dist/workflow/config.d.ts +0 -24
  23. package/dist/workflow/config.js +0 -25
  24. package/dist/workflow/config.js.map +0 -1
  25. package/dist/workflow/features.d.ts +0 -20
  26. package/dist/workflow/features.js +0 -165
  27. package/dist/workflow/features.js.map +0 -1
  28. package/dist/workflow/git.d.ts +0 -12
  29. package/dist/workflow/git.js +0 -42
  30. package/dist/workflow/git.js.map +0 -1
  31. package/dist/workflow/glob.d.ts +0 -3
  32. package/dist/workflow/glob.js +0 -21
  33. package/dist/workflow/glob.js.map +0 -1
  34. package/dist/workflow/index.d.ts +0 -2
  35. package/dist/workflow/index.js +0 -162
  36. package/dist/workflow/index.js.map +0 -1
  37. package/dist/workflow/phases.d.ts +0 -22
  38. package/dist/workflow/phases.js +0 -50
  39. package/dist/workflow/phases.js.map +0 -1
  40. package/dist/workflow/prose.d.ts +0 -2
  41. package/dist/workflow/prose.js +0 -113
  42. package/dist/workflow/prose.js.map +0 -1
  43. package/dist/workflow/red.d.ts +0 -2
  44. package/dist/workflow/red.js +0 -36
  45. package/dist/workflow/red.js.map +0 -1
  46. package/dist/workflow/secrets.d.ts +0 -2
  47. package/dist/workflow/secrets.js +0 -5
  48. package/dist/workflow/secrets.js.map +0 -1
  49. package/dist/workflow/security-line.d.ts +0 -6
  50. package/dist/workflow/security-line.js +0 -14
  51. package/dist/workflow/security-line.js.map +0 -1
  52. package/dist/workflow/sync.d.ts +0 -4
  53. package/dist/workflow/sync.js +0 -47
  54. package/dist/workflow/sync.js.map +0 -1
  55. package/dist/workflow/tests.d.ts +0 -2
  56. package/dist/workflow/tests.js +0 -6
  57. package/dist/workflow/tests.js.map +0 -1
  58. package/templates/repo/claude/_claude/agents/security-reviewer.md +0 -33
  59. package/templates/repo/claude/_claude/hooks/format.mjs +0 -20
  60. package/templates/repo/claude/_claude/hooks/guard-paths.mjs +0 -43
  61. package/templates/repo/claude/_claude/skills/add-plugin/SKILL.md +0 -39
  62. package/templates/repo/claude/_claude/skills/release-plugin/SKILL.md +0 -18
  63. package/templates/workflow/base/_githooks/pre-commit +0 -3
  64. package/templates/workflow/base/_githooks/pre-push +0 -4
  65. package/templates/workflow/base/_github/workflows/workflow.yml +0 -45
  66. package/templates/workflow/base/docs/workflow.md +0 -100
  67. package/templates/workflow/claude/_claude/hooks/guard-branch.mjs +0 -73
  68. package/templates/workflow/claude/_claude/skills/architect/SKILL.md +0 -44
  69. package/templates/workflow/claude/_claude/skills/change-workflow/SKILL.md +0 -70
  70. package/templates/workflow/claude/_claude/skills/developer/SKILL.md +0 -57
  71. package/templates/workflow/claude/_claude/skills/requirements-engineer/SKILL.md +0 -59
  72. package/templates/workflow/claude/_claude/skills/technical-writing/SKILL.md +0 -35
@@ -1,25 +0,0 @@
1
- import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
2
- import path from 'node:path';
3
- export const SHARED_COMPONENTS = ['ci', 'docs', 'skills', 'deps'];
4
- export const DEFAULTS = {
5
- ignoreBranches: ['main', 'dependabot/**', 'renovate/**', 'gh-readonly-queue/**'],
6
- features: ['**/features/**/*.feature'],
7
- steps: ['**/features/**/*.ts', '**/features/**/*.js'],
8
- architecture: ['docs/architecture/**'],
9
- unitTests: ['**/test/unit/**/*.test.ts'],
10
- source: ['packages/*/src/**', 'plugins/*/src/**', 'plugins/*/plugin.yaml'],
11
- securityPaths: [],
12
- prose: ['**/*.md', '**/*.feature'],
13
- };
14
- const subdirs = (dir) => existsSync(dir) ? readdirSync(dir).filter((d) => statSync(path.join(dir, d)).isDirectory()) : [];
15
- export function loadConfig(root) {
16
- const pkg = JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8'));
17
- const own = pkg.synoikia?.workflow ?? {};
18
- const components = own.components ?? [
19
- ...subdirs(path.join(root, 'packages')),
20
- ...subdirs(path.join(root, 'plugins')),
21
- ...SHARED_COMPONENTS,
22
- ];
23
- return { ...DEFAULTS, ...own, components };
24
- }
25
- //# sourceMappingURL=config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/workflow/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,IAAI,MAAM,WAAW,CAAC;AAwB7B,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAElE,MAAM,CAAC,MAAM,QAAQ,GAAuC;IAC1D,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,sBAAsB,CAAC;IAChF,QAAQ,EAAE,CAAC,0BAA0B,CAAC;IACtC,KAAK,EAAE,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IACrD,YAAY,EAAE,CAAC,sBAAsB,CAAC;IACtC,SAAS,EAAE,CAAC,2BAA2B,CAAC;IACxC,MAAM,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,EAAE,uBAAuB,CAAC;IAC1E,aAAa,EAAE,EAAE;IACjB,KAAK,EAAE,CAAC,SAAS,EAAE,cAAc,CAAC;CACnC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,EAAE,CAC9B,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAEnG,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAE3E,CAAC;IACF,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI;QACnC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACvC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACtC,GAAG,iBAAiB;KACrB,CAAC;IACF,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,CAAC;AAC7C,CAAC"}
@@ -1,20 +0,0 @@
1
- import type { Feature, GherkinDocument } from '@cucumber/messages';
2
- export interface SourceFile {
3
- path: string;
4
- text: string;
5
- }
6
- export interface ParsedScenario {
7
- file: string;
8
- feature: string;
9
- rule: string | undefined;
10
- name: string;
11
- line: number;
12
- backlog: boolean;
13
- }
14
- export declare function parseFeature(file: SourceFile): GherkinDocument;
15
- /** Every scenario in a feature, with the rule that holds it. */
16
- export declare function scenariosOf(file: string, feature: Feature): ParsedScenario[];
17
- /** Problems in a set of feature files: syntax, ids, tags, shape and solution words. */
18
- export declare function checkFeatures(files: readonly SourceFile[]): string[];
19
- /** Problems with the slice a PR builds: at most three new scenarios outside @backlog, all in one rule. */
20
- export declare function checkSlice(before: readonly SourceFile[], after: readonly SourceFile[]): string[];
@@ -1,165 +0,0 @@
1
- import { AstBuilder, GherkinClassicTokenMatcher, Parser } from '@cucumber/gherkin';
2
- import { IdGenerator } from '@cucumber/messages';
3
- const ALLOWED_TAG = /^@(?:id:[a-z0-9]+(?:-[a-z0-9]+)*|backlog|long-running|exclusive)$/;
4
- /** Words that put a solution in the spec: screens, wire formats and storage. */
5
- const SOLUTION_WORDS = [
6
- /\b(?:click|tap|press)(?:s|es|ed)?\b/i,
7
- /\b(?:button|dropdown|checkbox|text ?field)s?\b/i,
8
- /\bendpoints?\b/i,
9
- /\bstatus code\b/i,
10
- /\b(?:HTTP|JSON|SQL|URL)\b/,
11
- /\b(?:GET|POST|PUT|PATCH|DELETE)\b/,
12
- /\/api\//,
13
- ];
14
- const MAX_STEPS = 5;
15
- const MAX_BACKGROUND = 4;
16
- export function parseFeature(file) {
17
- const parser = new Parser(new AstBuilder(IdGenerator.incrementing()), new GherkinClassicTokenMatcher());
18
- return parser.parse(file.text);
19
- }
20
- const idOf = (tags) => tags.find((t) => t.name.startsWith('@id:'))?.name.slice(4);
21
- /** Every scenario in a feature, with the rule that holds it. */
22
- export function scenariosOf(file, feature) {
23
- const out = [];
24
- const add = (s, rule, ruleTags) => out.push({
25
- file,
26
- feature: idOf(feature.tags) ?? feature.name,
27
- rule,
28
- name: s.name,
29
- line: s.location.line,
30
- backlog: [...feature.tags, ...ruleTags, ...s.tags].some((t) => t.name === '@backlog'),
31
- });
32
- for (const child of feature.children) {
33
- if (child.scenario)
34
- add(child.scenario, undefined, []);
35
- for (const rc of child.rule?.children ?? [])
36
- if (rc.scenario)
37
- add(rc.scenario, child.rule.name, child.rule.tags);
38
- }
39
- return out;
40
- }
41
- function checkSteps(where, steps) {
42
- const issues = [];
43
- if (steps.length > MAX_STEPS)
44
- issues.push(`${where} has ${steps.length} steps. Use ${MAX_STEPS} at most`);
45
- const whens = steps.filter((s) => s.keywordType === 'Action').length;
46
- const thens = steps.filter((s) => s.keywordType === 'Outcome').length;
47
- if (whens !== 1 || thens !== 1)
48
- issues.push(`${where} needs one When and one Then`);
49
- return issues;
50
- }
51
- function checkText(where, text) {
52
- return SOLUTION_WORDS.filter((w) => w.test(text)).map((w) => `${where} names a solution (${String(text.match(w)?.[0])}). Say what someone can do and see`);
53
- }
54
- /** Problems in a set of feature files: syntax, ids, tags, shape and solution words. */
55
- export function checkFeatures(files) {
56
- const issues = [];
57
- const featureIds = new Map();
58
- const scenarioIds = new Map();
59
- const claim = (ids, id, where) => {
60
- const first = ids.get(id);
61
- if (first)
62
- issues.push(`${where}: @id:${id} is also used at ${first}`);
63
- else
64
- ids.set(id, where);
65
- };
66
- for (const file of files) {
67
- let doc;
68
- try {
69
- doc = parseFeature(file);
70
- }
71
- catch (err) {
72
- const lines = (err instanceof Error ? err.message : String(err))
73
- .split('\n')
74
- .filter((l) => l && l !== 'Parser errors:');
75
- issues.push(...lines.map((l) => `${file.path}: ${l}`));
76
- continue;
77
- }
78
- const at = (line) => `${file.path}:${line}`;
79
- for (const c of doc.comments)
80
- issues.push(`${at(c.location.line)}: no comments. Put it in the feature narrative`);
81
- const feature = doc.feature;
82
- if (!feature) {
83
- issues.push(`${file.path}: no Feature`);
84
- continue;
85
- }
86
- const allTags = [...feature.tags];
87
- const fid = idOf(feature.tags);
88
- if (!fid)
89
- issues.push(`${at(feature.location.line)}: the feature needs an @id:<kebab-case> tag`);
90
- else
91
- claim(featureIds, fid, at(feature.location.line));
92
- if (!feature.name.trim())
93
- issues.push(`${at(feature.location.line)}: the feature needs a name`);
94
- issues.push(...checkText(at(feature.location.line), `${feature.name}\n${feature.description}`));
95
- const names = new Set();
96
- const checkScenario = (s) => {
97
- const where = at(s.location.line);
98
- allTags.push(...s.tags);
99
- if (!s.name.trim())
100
- issues.push(`${where}: the scenario needs a name`);
101
- if (names.has(s.name))
102
- issues.push(`${where}: another scenario in this feature is named "${s.name}"`);
103
- names.add(s.name);
104
- const sid = idOf(s.tags);
105
- if (sid)
106
- claim(scenarioIds, sid, where);
107
- if (s.examples.length === 0 && s.keyword.includes('Outline'))
108
- issues.push(`${where}: the outline needs Examples`);
109
- if (s.examples.length > 0 && !s.keyword.includes('Outline'))
110
- issues.push(`${where}: Examples belong to a Scenario Outline`);
111
- issues.push(...checkSteps(where, s.steps));
112
- issues.push(...checkText(where, [s.name, s.description, ...s.steps.map((st) => st.text)].join('\n')));
113
- };
114
- for (const child of feature.children) {
115
- if (child.background) {
116
- const bg = child.background;
117
- if (bg.steps.length > MAX_BACKGROUND)
118
- issues.push(`${at(bg.location.line)}: the Background has ${bg.steps.length} steps. Use ${MAX_BACKGROUND}`);
119
- issues.push(...checkText(at(bg.location.line), bg.steps.map((st) => st.text).join('\n')));
120
- }
121
- if (child.scenario) {
122
- issues.push(`${at(child.scenario.location.line)}: put the scenario in a Rule`);
123
- checkScenario(child.scenario);
124
- }
125
- if (child.rule) {
126
- const rule = child.rule;
127
- allTags.push(...rule.tags);
128
- const scenarios = rule.children.filter((rc) => rc.scenario);
129
- if (!scenarios.length)
130
- issues.push(`${at(rule.location.line)}: the rule needs a scenario`);
131
- issues.push(...checkText(at(rule.location.line), `${rule.name}\n${rule.description}`));
132
- for (const rc of rule.children)
133
- if (rc.scenario)
134
- checkScenario(rc.scenario);
135
- }
136
- }
137
- for (const tag of allTags)
138
- if (!ALLOWED_TAG.test(tag.name))
139
- issues.push(`${at(tag.location.line)}: ${tag.name} is not allowed. Use @id:<kebab-case>, @backlog, @long-running or @exclusive`);
140
- }
141
- return issues;
142
- }
143
- /** Problems with the slice a PR builds: at most three new scenarios outside @backlog, all in one rule. */
144
- export function checkSlice(before, after) {
145
- const key = (s) => `${s.feature}\u0000${s.name}`;
146
- const collect = (files) => files.flatMap((f) => {
147
- try {
148
- const feature = parseFeature(f).feature;
149
- return feature ? scenariosOf(f.path, feature) : [];
150
- }
151
- catch {
152
- return [];
153
- }
154
- });
155
- const old = new Map(collect(before).map((s) => [key(s), s]));
156
- const built = collect(after).filter((s) => !s.backlog && (old.get(key(s))?.backlog ?? true));
157
- const issues = [];
158
- if (built.length > 3)
159
- issues.push(`this PR builds ${built.length} scenarios. A slice is three at most: tag the others @backlog`);
160
- const rules = new Set(built.map((s) => `${s.feature} › ${s.rule ?? '(no rule)'}`));
161
- if (rules.size > 1)
162
- issues.push(`this PR builds scenarios of ${rules.size} rules: ${[...rules].join(', ')}. Pick one`);
163
- return issues;
164
- }
165
- //# sourceMappingURL=features.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"features.js","sourceRoot":"","sources":["../../src/workflow/features.ts"],"names":[],"mappings":"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"}
@@ -1,12 +0,0 @@
1
- import type { Commit } from './phases.js';
2
- export declare const git: (root: string, ...args: string[]) => string;
3
- export declare const currentBranch: (root: string) => string;
4
- export declare const mergeBase: (root: string, base: string) => string;
5
- /** Commits after `base`, oldest first. A merge lists what its conflict resolution changed. */
6
- export declare function commitsSince(root: string, base: string): Commit[];
7
- export declare const changedSince: (root: string, base: string, filter?: string) => string[];
8
- /** Line numbers each file added since `base`. */
9
- export declare function addedLines(root: string, base: string, files: readonly string[]): Map<string, Set<number>>;
10
- export declare const trackedFiles: (root: string, ref?: string) => string[];
11
- export declare const showFile: (root: string, ref: string, file: string) => string | undefined;
12
- export declare const stagedFiles: (root: string) => string[];
@@ -1,42 +0,0 @@
1
- import { execFileSync, spawnSync } from 'node:child_process';
2
- export const git = (root, ...args) => execFileSync('git', args, { cwd: root, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 }).trimEnd();
3
- const lines = (text) => text.split('\n').filter(Boolean);
4
- export const currentBranch = (root) => process.env.GITHUB_HEAD_REF ||
5
- spawnSync('git', ['symbolic-ref', '-q', '--short', 'HEAD'], { cwd: root, encoding: 'utf8' }).stdout.trim();
6
- export const mergeBase = (root, base) => git(root, 'merge-base', base, 'HEAD');
7
- /** Commits after `base`, oldest first. A merge lists what its conflict resolution changed. */
8
- export function commitsSince(root, base) {
9
- return lines(git(root, 'rev-list', '--reverse', `${mergeBase(root, base)}..HEAD`)).map((sha) => {
10
- const parents = git(root, 'rev-list', '--parents', '-n', '1', sha).split(' ').length - 1;
11
- const files = parents > 1
12
- ? git(root, 'show', '--remerge-diff', '--format=', '--name-only', sha)
13
- : git(root, 'diff-tree', '--no-commit-id', '--name-only', '-r', '--root', sha);
14
- return { sha, subject: git(root, 'log', '-1', '--format=%s', sha), files: lines(files) };
15
- });
16
- }
17
- export const changedSince = (root, base, filter = 'ACMR') => lines(git(root, 'diff', '--name-only', `--diff-filter=${filter}`, `${mergeBase(root, base)}...HEAD`));
18
- /** Line numbers each file added since `base`. */
19
- export function addedLines(root, base, files) {
20
- const out = new Map();
21
- if (!files.length)
22
- return out;
23
- const diff = git(root, 'diff', '--unified=0', '--no-color', `${mergeBase(root, base)}...HEAD`, '--', ...files);
24
- let current;
25
- for (const line of diff.split('\n')) {
26
- const file = line.match(/^\+\+\+ b\/(.*)$/)?.[1];
27
- if (file)
28
- out.set(file, (current = new Set()));
29
- const hunk = line.match(/^@@ -\S+ \+(\d+)(?:,(\d+))? @@/);
30
- if (hunk && current)
31
- for (let n = 0; n < Number(hunk[2] ?? 1); n++)
32
- current.add(Number(hunk[1]) + n);
33
- }
34
- return out;
35
- }
36
- export const trackedFiles = (root, ref = 'HEAD') => lines(git(root, 'ls-tree', '-r', '--name-only', ref));
37
- export const showFile = (root, ref, file) => {
38
- const r = spawnSync('git', ['show', `${ref}:${file}`], { cwd: root, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
39
- return r.status === 0 ? r.stdout : undefined;
40
- };
41
- export const stagedFiles = (root) => lines(git(root, 'diff', '--cached', '--name-only', '--diff-filter=ACMRT'));
42
- //# sourceMappingURL=git.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/workflow/git.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- /** Converts a path glob to a RegExp: `**` spans directories, `*` and `?` stay inside one segment. */
2
- export declare function globToRegExp(glob: string): RegExp;
3
- export declare const matchesAny: (file: string, globs: readonly string[]) => boolean;
@@ -1,21 +0,0 @@
1
- /** Converts a path glob to a RegExp: `**` spans directories, `*` and `?` stay inside one segment. */
2
- export function globToRegExp(glob) {
3
- let out = '';
4
- for (let i = 0; i < glob.length; i++) {
5
- const c = glob[i];
6
- if (c === '*' && glob[i + 1] === '*') {
7
- const slash = glob[i + 2] === '/';
8
- out += slash ? '(?:.*/)?' : '.*';
9
- i += slash ? 2 : 1;
10
- }
11
- else if (c === '*')
12
- out += '[^/]*';
13
- else if (c === '?')
14
- out += '[^/]';
15
- else
16
- out += c.replace(/[.+^${}()|[\]\\]/g, '\\$&');
17
- }
18
- return new RegExp(`^${out}$`);
19
- }
20
- export const matchesAny = (file, globs) => globs.some((g) => globToRegExp(g).test(file));
21
- //# sourceMappingURL=glob.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/workflow/glob.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;YAClC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;YACjC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG;YAAE,GAAG,IAAI,OAAO,CAAC;aAChC,IAAI,CAAC,KAAK,GAAG;YAAE,GAAG,IAAI,MAAM,CAAC;;YAC7B,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,KAAwB,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export declare const WORKFLOW_USAGE = "synoikia-plugin workflow <command> (rules: docs/workflow.md)\n\n check-branch [name] Branch name (default: the PR head or the current branch)\n check-phases --base <ref> [--red-green] [--backfill]\n One phase per commit. --red-green runs the scenarios at the test: commit\n check-features [--base <ref>] [--backfill]\n Feature files. With --base: the slice size and new test files\n check-prose [--base <ref>] [--pr-body] [files...]\n Writing rules on files, on lines added since <ref>, or on the PR description\n check-security-line --base <ref> A ready PR that changes a security path has a \"Security audit:\" line\n pre-commit Credential file names, then gitleaks on staged changes when installed\n pre-push [--base <ref>] check-branch, check-features, check-prose and check-phases (default base origin/main)\n hooks install Use .githooks for this clone\n sync [--check] Write the shared workflow files, or list the ones out of date\n";
2
- export declare function runWorkflow(argv: string[], root: string): Promise<number>;
@@ -1,162 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { readFileSync } from 'node:fs';
3
- import path from 'node:path';
4
- import { parseArgs } from 'node:util';
5
- import { checkBranch } from './branch.js';
6
- import { loadConfig } from './config.js';
7
- import { checkFeatures, checkSlice } from './features.js';
8
- import { addedLines, changedSince, commitsSince, currentBranch, git, mergeBase, showFile, stagedFiles, trackedFiles, } from './git.js';
9
- import { matchesAny } from './glob.js';
10
- import { checkPhases } from './phases.js';
11
- import { checkProse } from './prose.js';
12
- import { featuresFailAt } from './red.js';
13
- import { credentialPaths } from './secrets.js';
14
- import { checkSecurityLine } from './security-line.js';
15
- import { syncWorkflow } from './sync.js';
16
- import { unlistedTests } from './tests.js';
17
- export const WORKFLOW_USAGE = `synoikia-plugin workflow <command> (rules: docs/workflow.md)
18
-
19
- check-branch [name] Branch name (default: the PR head or the current branch)
20
- check-phases --base <ref> [--red-green] [--backfill]
21
- One phase per commit. --red-green runs the scenarios at the test: commit
22
- check-features [--base <ref>] [--backfill]
23
- Feature files. With --base: the slice size and new test files
24
- check-prose [--base <ref>] [--pr-body] [files...]
25
- Writing rules on files, on lines added since <ref>, or on the PR description
26
- check-security-line --base <ref> A ready PR that changes a security path has a "Security audit:" line
27
- pre-commit Credential file names, then gitleaks on staged changes when installed
28
- pre-push [--base <ref>] check-branch, check-features, check-prose and check-phases (default base origin/main)
29
- hooks install Use .githooks for this clone
30
- sync [--check] Write the shared workflow files, or list the ones out of date
31
- `;
32
- const OPTIONS = {
33
- base: { type: 'string' },
34
- 'red-green': { type: 'boolean' },
35
- backfill: { type: 'boolean' },
36
- 'pr-body': { type: 'boolean' },
37
- check: { type: 'boolean' },
38
- };
39
- const report = (title, issues) => {
40
- for (const issue of issues)
41
- console.error(`${title}: ${issue}`);
42
- return issues.length ? 1 : 0;
43
- };
44
- const pullRequest = () => {
45
- const file = process.env.GITHUB_EVENT_PATH;
46
- if (!file)
47
- return undefined;
48
- return JSON.parse(readFileSync(file, 'utf8'))
49
- .pull_request;
50
- };
51
- function branch({ root, config }, name) {
52
- const branchName = name ?? currentBranch(root);
53
- if (!branchName)
54
- return report('check-branch', ['no branch (detached HEAD). Pass the name']);
55
- return report('check-branch', checkBranch(branchName, config.components, config.ignoreBranches));
56
- }
57
- const readFeatures = (root, ref, config) => trackedFiles(root, ref ?? 'HEAD')
58
- .filter((f) => matchesAny(f, config.features))
59
- .map((f) => ({ path: f, text: (ref ? showFile(root, ref, f) : readFileSync(path.join(root, f), 'utf8')) ?? '' }));
60
- function features({ root, config }, base, backfill) {
61
- const issues = checkFeatures(readFeatures(root, undefined, config));
62
- if (base) {
63
- if (!backfill)
64
- issues.push(...checkSlice(readFeatures(root, mergeBase(root, base), config), readFeatures(root, undefined, config)));
65
- issues.push(...unlistedTests(changedSince(root, base, 'A'), config.unitTests));
66
- }
67
- return report('check-features', issues);
68
- }
69
- function prose({ root, config }, base, prBody, files) {
70
- const issues = [];
71
- if (files.length)
72
- for (const f of files)
73
- issues.push(...checkProse(f, readFileSync(path.join(root, f), 'utf8')));
74
- else if (base) {
75
- const changed = changedSince(root, base).filter((f) => matchesAny(f, config.prose));
76
- const added = addedLines(root, base, changed);
77
- for (const f of changed)
78
- issues.push(...checkProse(f, readFileSync(path.join(root, f), 'utf8'), added.get(f) ?? new Set()));
79
- }
80
- if (prBody) {
81
- const pr = pullRequest();
82
- if (pr?.body)
83
- issues.push(...checkProse('PR description', pr.body.replace(/\r\n/g, '\n')));
84
- }
85
- return report('check-prose', issues);
86
- }
87
- function phases({ root, config }, base, redGreen, backfill) {
88
- const result = checkPhases(commitsSince(root, base), config, { backfill });
89
- if (result.issues.length || !redGreen || !result.redAt)
90
- return report('check-phases', result.issues);
91
- const sha = result.redAt.sha;
92
- console.log(`check-phases: running ${result.redFeatures.length} feature file(s) at ${sha.slice(0, 7)}, expecting red`);
93
- if (!featuresFailAt(root, sha, result.redFeatures))
94
- return report('check-phases', [
95
- `the scenarios pass at ${sha.slice(0, 7)} ${result.redAt.subject}. Commit the steps before the code, so they fail first`,
96
- ]);
97
- console.log('check-phases: red at the test: commit. CI runs them green at the head');
98
- return 0;
99
- }
100
- function securityLine({ root, config }, base) {
101
- const pr = pullRequest();
102
- if (!pr)
103
- return report('check-security-line', ['no pull request event (GITHUB_EVENT_PATH)']);
104
- return report('check-security-line', checkSecurityLine(pr, changedSince(root, base, 'ACMRD'), config.securityPaths));
105
- }
106
- function preCommit({ root }) {
107
- const found = credentialPaths(stagedFiles(root));
108
- if (found.length)
109
- return report('pre-commit', found.map((f) => `${f} looks like a credential file. If it is tracked already: git rm --cached ${f}`));
110
- const leaks = spawnSync('gitleaks', ['git', '--staged', '--no-banner', '--redact'], { cwd: root, stdio: 'inherit' });
111
- if (leaks.error)
112
- return 0;
113
- return leaks.status === 0 ? 0 : report('pre-commit', ['gitleaks found a secret in the staged changes']);
114
- }
115
- export async function runWorkflow(argv, root) {
116
- const [command, ...rest] = argv;
117
- const { values, positionals } = parseArgs({ args: rest, allowPositionals: true, options: OPTIONS });
118
- const ctx = { root, config: loadConfig(root) };
119
- const base = values.base;
120
- const needBase = () => {
121
- if (!base)
122
- throw new Error(`${command} needs --base <ref>`);
123
- return base;
124
- };
125
- switch (command) {
126
- case 'check-branch':
127
- return branch(ctx, positionals[0]);
128
- case 'check-phases':
129
- return phases(ctx, needBase(), !!values['red-green'], !!values.backfill);
130
- case 'check-features':
131
- return features(ctx, base, !!values.backfill);
132
- case 'check-prose':
133
- return prose(ctx, base, !!values['pr-body'], positionals);
134
- case 'check-security-line':
135
- return securityLine(ctx, needBase());
136
- case 'pre-commit':
137
- return preCommit(ctx);
138
- case 'pre-push': {
139
- const b = base ?? 'origin/main';
140
- if (currentBranch(root) === 'main')
141
- return 0;
142
- git(root, 'rev-parse', '--verify', '--quiet', b);
143
- return branch(ctx) | features(ctx, b, false) | prose(ctx, b, false, []) | phases(ctx, b, false, false);
144
- }
145
- case 'hooks':
146
- if (positionals[0] !== 'install')
147
- break;
148
- git(root, 'config', 'core.hooksPath', '.githooks');
149
- console.log('git hooks: .githooks');
150
- return 0;
151
- case 'sync': {
152
- const changed = syncWorkflow(root, !!values.check);
153
- if (values.check)
154
- return report('sync', changed.map((f) => `${f} differs from the template. Run the sync`));
155
- console.log(changed.length ? `wrote ${changed.join(', ')}` : 'workflow files are current');
156
- return 0;
157
- }
158
- }
159
- console.error(WORKFLOW_USAGE);
160
- return 2;
161
- }
162
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workflow/index.ts"],"names":[],"mappings":"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"}
@@ -1,22 +0,0 @@
1
- import type { WorkflowConfig } from './config.js';
2
- export interface Commit {
3
- sha: string;
4
- subject: string;
5
- files: string[];
6
- }
7
- export declare const PHASES: readonly ["spec", "arch", "test", "feat", "fix", "refactor", "docs", "chore", "ci"];
8
- export type Phase = (typeof PHASES)[number];
9
- export declare const phaseOf: (subject: string) => Phase | undefined;
10
- type Paths = Pick<WorkflowConfig, 'features' | 'steps' | 'architecture' | 'unitTests' | 'source'>;
11
- export interface PhaseResult {
12
- issues: string[];
13
- /** The last `test:` commit before the first code commit: its new scenarios must fail there. */
14
- redAt?: Commit;
15
- /** Feature files that the spec and test commits changed. */
16
- redFeatures: string[];
17
- }
18
- /** Commits of a branch, oldest first: one phase each, and code changes come after a red test commit. */
19
- export declare function checkPhases(commits: readonly Commit[], paths: Paths, opts?: {
20
- backfill?: boolean;
21
- }): PhaseResult;
22
- export {};
@@ -1,50 +0,0 @@
1
- import { matchesAny } from './glob.js';
2
- export const PHASES = ['spec', 'arch', 'test', 'feat', 'fix', 'refactor', 'docs', 'chore', 'ci'];
3
- const PREFIX = new RegExp(`^(${PHASES.join('|')})(?:\\([a-z0-9-]+\\))?!?: \\S`);
4
- export const phaseOf = (subject) => subject.match(PREFIX)?.[1];
5
- const TESTS = ['**/test/**', '**/*.test.ts', '**/*.spec.ts'];
6
- /** What each phase may change. */
7
- function allowed(phase, file, paths) {
8
- const feature = matchesAny(file, paths.features);
9
- const model = matchesAny(file, paths.architecture);
10
- if (phase === 'spec')
11
- return feature;
12
- if (phase === 'arch')
13
- return model;
14
- if (phase === 'test')
15
- return matchesAny(file, [...paths.steps, ...TESTS, ...paths.unitTests]);
16
- return !feature && !model;
17
- }
18
- /** Commits of a branch, oldest first: one phase each, and code changes come after a red test commit. */
19
- export function checkPhases(commits, paths, opts = {}) {
20
- const issues = [];
21
- const redFeatures = new Set();
22
- let lastTest;
23
- let redAt;
24
- let needsRed = false;
25
- for (const c of commits) {
26
- const short = `${c.sha.slice(0, 7)} ${c.subject}`;
27
- const phase = phaseOf(c.subject);
28
- if (!phase) {
29
- issues.push(`${short}: start the subject with one of ${PHASES.map((p) => `${p}:`).join(' ')}`);
30
- continue;
31
- }
32
- for (const f of c.files)
33
- if (!allowed(phase, f, paths))
34
- issues.push(`${short}: ${f} is outside the ${phase} phase`);
35
- if (phase === 'spec' || phase === 'test')
36
- for (const f of c.files)
37
- if (matchesAny(f, paths.features))
38
- redFeatures.add(f);
39
- if (phase === 'test')
40
- lastTest = c;
41
- if ((phase === 'feat' || phase === 'fix') && c.files.some((f) => matchesAny(f, paths.source)) && !redAt) {
42
- needsRed = true;
43
- redAt = lastTest;
44
- }
45
- }
46
- if (needsRed && !opts.backfill && (!redAt || !redFeatures.size))
47
- issues.push('a feat: or fix: commit changes code with no test: commit before it. Show the scenarios red first');
48
- return { issues, redAt: opts.backfill ? undefined : redAt, redFeatures: [...redFeatures] };
49
- }
50
- //# sourceMappingURL=phases.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"phases.js","sourceRoot":"","sources":["../../src/workflow/phases.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- /** Problems with the writing rules in one file. With `lines`, only blocks that touch those lines. */
2
- export declare function checkProse(file: string, text: string, lines?: ReadonlySet<number>): string[];