@ebalzan/ci 0.0.0-stage → 3.0.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 (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +302 -2
  3. package/bin/_json.mjs +95 -0
  4. package/bin/_lib.sh +153 -0
  5. package/bin/cli.mjs +105 -0
  6. package/bin/gh-bootstrap.sh +622 -0
  7. package/bin/gh-reset.sh +148 -0
  8. package/bin/onboard.sh +340 -0
  9. package/bin/sync-managed.sh +81 -0
  10. package/config/actions.env +33 -0
  11. package/config/repo-settings.json +10 -0
  12. package/config/repos.env +25 -0
  13. package/config/rulesets/protect-dev.json +10 -0
  14. package/config/rulesets/protect-main.json +10 -0
  15. package/config/rulesets/require-pull-request.json +33 -0
  16. package/config/secrets.env.example +31 -0
  17. package/docs/ARCHITECTURE.md +477 -0
  18. package/docs/AUTO_WORK_ITEMS_WORKFLOW.md +305 -0
  19. package/docs/CI_FLOW.md +205 -0
  20. package/docs/CLI.md +229 -0
  21. package/docs/COMMIT_GUIDE.md +133 -0
  22. package/docs/CONFIGURATION.md +177 -0
  23. package/docs/GITHUB_ACTIONS_SETUP.md +315 -0
  24. package/docs/MIGRATION.md +175 -0
  25. package/docs/ONBOARDING.md +166 -0
  26. package/docs/REPO_RULES.md +116 -0
  27. package/managed/scripts/release/validate-conventional-subject.sh +32 -0
  28. package/package.json +66 -4
  29. package/renovate/tooling.json +45 -0
  30. package/templates/.github/actions.env +17 -0
  31. package/templates/.github/workflows/auto-pr.yml +33 -0
  32. package/templates/.github/workflows/pr-checks.yml +48 -0
  33. package/templates/.github/workflows/promote-dev-to-main.yml +26 -0
  34. package/templates/.github/workflows/release.yml +36 -0
  35. package/templates/.husky/commit-msg +18 -0
  36. package/templates/eslint.config.mjs +6 -0
  37. package/templates/renovate.json +4 -0
package/bin/cli.mjs ADDED
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ //
3
+ // ebalzan-ci — the command-line entry point of @ebalzan/ci.
4
+ //
5
+ // Every command except commit-msg, path and version runs one of the bash tools
6
+ // next to this file with the arguments unchanged, so `ebalzan-ci <cmd> --help`
7
+ // prints that tool's own help. Reference: docs/CLI.md.
8
+
9
+ import { spawnSync } from 'node:child_process'
10
+ import { existsSync, readFileSync } from 'node:fs'
11
+ import { dirname, join } from 'node:path'
12
+ import process from 'node:process'
13
+ import { fileURLToPath } from 'node:url'
14
+
15
+ const BIN_DIR = dirname(fileURLToPath(import.meta.url))
16
+ const ROOT = dirname(BIN_DIR)
17
+ const VALIDATOR = join(ROOT, 'managed', 'scripts', 'release', 'validate-conventional-subject.sh')
18
+
19
+ const SCRIPTS = {
20
+ bootstrap: 'gh-bootstrap.sh',
21
+ reset: 'gh-reset.sh',
22
+ onboard: 'onboard.sh',
23
+ 'sync-managed': 'sync-managed.sh',
24
+ }
25
+
26
+ // Subjects git writes itself; they are not Conventional Commits and need not be.
27
+ const GIT_GENERATED = /^(Merge |Revert "|fixup! |squash! |amend! )/
28
+
29
+ const HELP = `Usage: ebalzan-ci <command> [options]
30
+
31
+ Commands:
32
+ onboard Add the shared workflows, hook and rules to a repo, then bootstrap it
33
+ bootstrap Sync variables, secrets, settings and rulesets onto a repo (or --all)
34
+ reset Delete Actions variables/secrets on a repo (typed confirmation)
35
+ commit-msg Validate a commit message (the husky commit-msg hook calls this)
36
+ sync-managed Refresh local copies of managed files (deprecated)
37
+ path Print the package directory (to source bin/_lib.sh, read config/)
38
+ version Print the package version
39
+ help Show this help
40
+
41
+ Run 'ebalzan-ci <command> --help' for a command's options.
42
+ Docs: https://github.com/ebalzan/ci#readme`
43
+
44
+ function version() {
45
+ return JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')).version
46
+ }
47
+
48
+ // commit-msg FILE|SUBJECT — husky passes the path of the message file; a
49
+ // non-path argument is checked as the subject itself (handy for scripts).
50
+ function commitMsg(args) {
51
+ const [arg] = args
52
+ if (!arg || arg === '--help' || arg === '-h') {
53
+ console.log('Usage: ebalzan-ci commit-msg <message-file | subject>')
54
+ return arg ? 0 : 1
55
+ }
56
+ const text = existsSync(arg) ? readFileSync(arg, 'utf8') : arg
57
+ const subject =
58
+ text
59
+ .split(/\r?\n/)
60
+ .find(line => line.trim() && !line.startsWith('#'))
61
+ ?.trim() ?? ''
62
+ if (GIT_GENERATED.test(subject)) return 0
63
+ return run('sh', [VALIDATOR, subject, 'commit message'])
64
+ }
65
+
66
+ function run(command, args) {
67
+ const result = spawnSync(command, args, { stdio: 'inherit' })
68
+ if (result.error) {
69
+ console.error(`ebalzan-ci: could not run ${command}: ${result.error.message}`)
70
+ if (command === 'bash' || command === 'sh') {
71
+ console.error('The tools need a POSIX shell (Linux, macOS, WSL or Git Bash on Windows).')
72
+ }
73
+ return 127
74
+ }
75
+ return result.status ?? 1
76
+ }
77
+
78
+ function main(argv) {
79
+ const [command, ...args] = argv
80
+ if (Object.hasOwn(SCRIPTS, command ?? ''))
81
+ return run('bash', [join(BIN_DIR, SCRIPTS[command]), ...args])
82
+ switch (command) {
83
+ case 'commit-msg':
84
+ return commitMsg(args)
85
+ case 'path':
86
+ console.log(ROOT)
87
+ return 0
88
+ case 'version':
89
+ case '--version':
90
+ case '-v':
91
+ console.log(version())
92
+ return 0
93
+ case undefined:
94
+ case 'help':
95
+ case '--help':
96
+ case '-h':
97
+ console.log(HELP)
98
+ return command === undefined ? 1 : 0
99
+ default:
100
+ console.error(`ebalzan-ci: unknown command '${command}'.\n\n${HELP}`)
101
+ return 1
102
+ }
103
+ }
104
+
105
+ process.exit(main(process.argv.slice(2)))