@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.
- package/LICENSE +21 -0
- package/README.md +302 -2
- package/bin/_json.mjs +95 -0
- package/bin/_lib.sh +153 -0
- package/bin/cli.mjs +105 -0
- package/bin/gh-bootstrap.sh +622 -0
- package/bin/gh-reset.sh +148 -0
- package/bin/onboard.sh +340 -0
- package/bin/sync-managed.sh +81 -0
- package/config/actions.env +33 -0
- package/config/repo-settings.json +10 -0
- package/config/repos.env +25 -0
- package/config/rulesets/protect-dev.json +10 -0
- package/config/rulesets/protect-main.json +10 -0
- package/config/rulesets/require-pull-request.json +33 -0
- package/config/secrets.env.example +31 -0
- package/docs/ARCHITECTURE.md +477 -0
- package/docs/AUTO_WORK_ITEMS_WORKFLOW.md +305 -0
- package/docs/CI_FLOW.md +205 -0
- package/docs/CLI.md +229 -0
- package/docs/COMMIT_GUIDE.md +133 -0
- package/docs/CONFIGURATION.md +177 -0
- package/docs/GITHUB_ACTIONS_SETUP.md +315 -0
- package/docs/MIGRATION.md +175 -0
- package/docs/ONBOARDING.md +166 -0
- package/docs/REPO_RULES.md +116 -0
- package/managed/scripts/release/validate-conventional-subject.sh +32 -0
- package/package.json +66 -4
- package/renovate/tooling.json +45 -0
- package/templates/.github/actions.env +17 -0
- package/templates/.github/workflows/auto-pr.yml +33 -0
- package/templates/.github/workflows/pr-checks.yml +48 -0
- package/templates/.github/workflows/promote-dev-to-main.yml +26 -0
- package/templates/.github/workflows/release.yml +36 -0
- package/templates/.husky/commit-msg +18 -0
- package/templates/eslint.config.mjs +6 -0
- package/templates/renovate.json +4 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Repository settings and branch rulesets
|
|
2
|
+
|
|
3
|
+
The workflows enforce the flow inside CI. These two files enforce it on GitHub
|
|
4
|
+
itself, the same way on every repo: `ebalzan-ci bootstrap` applies them
|
|
5
|
+
alongside the variables and secrets.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
config/repo-settings.json + <repo>/.github/repo-settings.json → PATCH /repos/{repo}
|
|
9
|
+
config/rulesets/<file>.json + <repo>/.github/rulesets/<file>.json → repo rulesets, matched by "name"
|
|
10
|
+
shared repo (deep-merged over it, wins)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Both are plain GitHub REST payloads, so anything the API accepts can go in
|
|
14
|
+
them. Keys starting with `$` (like `"$comment"`) are documentation and are
|
|
15
|
+
never sent.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Repository settings
|
|
20
|
+
|
|
21
|
+
`config/repo-settings.json`:
|
|
22
|
+
|
|
23
|
+
| Setting | Value | Why |
|
|
24
|
+
| ----------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
25
|
+
| `allow_squash_merge` | `true` | The only merge method. One PR = one commit = one Conventional Commit on the target branch. |
|
|
26
|
+
| `allow_merge_commit` | `false` | A merge commit is not a Conventional Commit, and it would carry unrelated history into `main`. |
|
|
27
|
+
| `allow_rebase_merge` | `false` | Replays every branch commit; each would need to be conventional, and the PR title would not be the subject. |
|
|
28
|
+
| `squash_merge_commit_title` | `PR_TITLE` | **Important.** GitHub's default (`COMMIT_OR_PR_TITLE`) uses the _commit_ subject for a single-commit PR, bypassing the PR-title check that guards the release bump. |
|
|
29
|
+
| `squash_merge_commit_message` | `COMMIT_MESSAGES` | The branch's commit messages go in the body, so a `BREAKING CHANGE:` footer still reaches the release scan. |
|
|
30
|
+
| `delete_branch_on_merge` | `true` | Work branches are short-lived; the tracking issue keeps the history. |
|
|
31
|
+
| `allow_update_branch` | `true` | Offers "Update branch" on PRs that fall behind `dev`. |
|
|
32
|
+
|
|
33
|
+
`bootstrap --dry-run` lists only the keys whose current value differs:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
==> Repository settings to change
|
|
37
|
+
allow_rebase_merge true → false
|
|
38
|
+
squash_merge_commit_title "COMMIT_OR_PR_TITLE" → "PR_TITLE"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To change one for a single repo, put just that key in its
|
|
42
|
+
`.github/repo-settings.json`:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{ "delete_branch_on_merge": false }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Branch rulesets
|
|
51
|
+
|
|
52
|
+
| File | Ruleset name | Default | Rules |
|
|
53
|
+
| --------------------------- | -------------------------- | ------------ | ------------------------------------------------------------------------------------------ |
|
|
54
|
+
| `protect-main.json` | `ci: protect main` | **active** | `main` cannot be deleted or force-pushed. |
|
|
55
|
+
| `protect-dev.json` | `ci: protect dev` | **active** | `dev` cannot be deleted. |
|
|
56
|
+
| `require-pull-request.json` | `ci: require pull request` | **disabled** | Changes to `main`/`dev` only by squash-merged PR with `title / Validate PR Title` passing. |
|
|
57
|
+
|
|
58
|
+
### Why `dev` can still be force-pushed
|
|
59
|
+
|
|
60
|
+
`release.yml`'s `sync-dev` job force-points `dev` at every release commit (the
|
|
61
|
+
squash merge into `main` leaves `dev` with the same content under unrelated
|
|
62
|
+
history; see [CI_FLOW.md §4](CI_FLOW.md#4-version-bump-rules-commit-scan)). A
|
|
63
|
+
`non_fast_forward` rule on `dev` would break every release. The test suite
|
|
64
|
+
fails if an active ruleset adds one.
|
|
65
|
+
|
|
66
|
+
### Why "require pull request" ships disabled
|
|
67
|
+
|
|
68
|
+
The release job pushes the `chore(release): X.Y.Z` commit straight to `main`
|
|
69
|
+
and force-points `dev`, both as `github-actions[bot]` (`GITHUB_TOKEN`). With
|
|
70
|
+
PRs required, those pushes need a bypass. The ruleset lists two bypass actors:
|
|
71
|
+
|
|
72
|
+
| Actor | Id | Why |
|
|
73
|
+
| ---------------------------- | ------- | -------------------------------- |
|
|
74
|
+
| `RepositoryRole` admin | `5` | You, for emergencies. |
|
|
75
|
+
| `Integration` GitHub Actions | `15368` | The release and sync-dev pushes. |
|
|
76
|
+
|
|
77
|
+
Whether GitHub honours the GitHub Actions app as a bypass actor depends on the
|
|
78
|
+
account type and plan, so it is off until you have seen it work. To turn it on
|
|
79
|
+
for one repo:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mkdir -p .github/rulesets
|
|
83
|
+
echo '{ "enforcement": "active" }' > .github/rulesets/require-pull-request.json
|
|
84
|
+
ebalzan-ci bootstrap --skip vars,secrets
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Then merge a promotion PR and check that the release run pushed its commit and
|
|
88
|
+
synced `dev`. If it was rejected, set the file back to `"disabled"` and
|
|
89
|
+
re-run the bootstrap. Once it works on your setup, flip `enforcement` in
|
|
90
|
+
`config/rulesets/require-pull-request.json` itself to roll it out everywhere.
|
|
91
|
+
|
|
92
|
+
### Plans
|
|
93
|
+
|
|
94
|
+
Rulesets are free on **public** repos. On **private** repos they need GitHub
|
|
95
|
+
Pro (personal accounts) or Team (organizations); otherwise GitHub answers
|
|
96
|
+
"Upgrade to GitHub Pro or make this repository public" and `bootstrap` warns
|
|
97
|
+
and skips the step, leaving the rest of the sync intact.
|
|
98
|
+
|
|
99
|
+
### Adding, overriding, removing
|
|
100
|
+
|
|
101
|
+
- **Override** a shared ruleset in one repo: a file with the **same file name**
|
|
102
|
+
in `.github/rulesets/`, containing only the keys to change. Arrays (such as
|
|
103
|
+
`rules` or `conditions.ref_name.include`) are replaced whole.
|
|
104
|
+
- **Add** a ruleset to one repo: any new file name in `.github/rulesets/`. Give
|
|
105
|
+
it a `"name"` starting with `ci: ` if you want `--prune` to manage it.
|
|
106
|
+
- **Add** one for every repo: a new file in `config/rulesets/`, then a release.
|
|
107
|
+
- **Remove** a shared one from one repo: override it with
|
|
108
|
+
`{ "enforcement": "disabled" }`.
|
|
109
|
+
- **Delete** one everywhere: remove its file, then `ebalzan-ci bootstrap --all
|
|
110
|
+
--prune`. Pruning only ever deletes repo rulesets whose name starts with
|
|
111
|
+
`ci: `; rulesets you made by hand under other names are never touched.
|
|
112
|
+
|
|
113
|
+
Rulesets are matched to GitHub by `name`: renaming one in a file creates a new
|
|
114
|
+
ruleset and leaves the old one until `--prune`.
|
|
115
|
+
|
|
116
|
+
Reference for the payload: [GitHub REST — repository rulesets](https://docs.github.com/en/rest/repos/rules).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
#
|
|
3
|
+
# MANAGED BY ebalzan/ci (managed/scripts/release/validate-conventional-subject.sh).
|
|
4
|
+
# Run it through the CLI (`ebalzan-ci commit-msg`) rather than copying it. If a
|
|
5
|
+
# repo still keeps a copy, do not edit it: change it in ebalzan/ci, then run
|
|
6
|
+
# `ebalzan-ci sync-managed --all`. PR Checks fails while a repo's copy differs.
|
|
7
|
+
#
|
|
8
|
+
# The one Conventional Commits rule, used by the husky commit-msg hook (locally,
|
|
9
|
+
# via `ebalzan-ci commit-msg`) and by the shared PR-title check (in CI). The
|
|
10
|
+
# allowed types must match branchReleaseTypes in scripts/release/release-utils.mjs
|
|
11
|
+
# and TYPE_CONFIG in actions/auto-work-items/src/config.ts.
|
|
12
|
+
set -eu
|
|
13
|
+
|
|
14
|
+
subject="${1-}"
|
|
15
|
+
label="${2-commit message}"
|
|
16
|
+
commit_regex='^(feat|fix|docs|style|refact|perf|test|build|ci|chore|revert)(\([^)]+\))?(!)?: .+'
|
|
17
|
+
|
|
18
|
+
if [ -z "$subject" ]; then
|
|
19
|
+
echo "Invalid $label: value is empty."
|
|
20
|
+
echo "Use Conventional Commits, for example:"
|
|
21
|
+
echo " feat(viewer): add section filters"
|
|
22
|
+
echo " fix: prevent null model crash"
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
printf '%s\n' "$subject" | grep -qE "$commit_regex" && exit 0
|
|
27
|
+
|
|
28
|
+
echo "Invalid $label: \"$subject\""
|
|
29
|
+
echo "Use Conventional Commits, for example:"
|
|
30
|
+
echo " feat(viewer): add section filters"
|
|
31
|
+
echo " fix: prevent null model crash"
|
|
32
|
+
exit 1
|
package/package.json
CHANGED
|
@@ -1,6 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ebalzan/ci",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "One set of CI/CD rules for all your GitHub repos: reusable workflows (Conventional Commits, auto issue/PR, semver releases), a CLI that syncs Actions config, repo settings and branch rulesets, and a commit-msg hook.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"github-actions",
|
|
7
|
+
"reusable-workflows",
|
|
8
|
+
"ci",
|
|
9
|
+
"cd",
|
|
10
|
+
"conventional-commits",
|
|
11
|
+
"semantic-release",
|
|
12
|
+
"semver",
|
|
13
|
+
"rulesets",
|
|
14
|
+
"husky",
|
|
15
|
+
"commit-msg",
|
|
16
|
+
"renovate-preset",
|
|
17
|
+
"devops"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://github.com/ebalzan/ci#readme",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/ebalzan/ci/issues"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/ebalzan/ci.git"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"author": "ebalzan",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"bin": {
|
|
31
|
+
"ebalzan-ci": "bin/cli.mjs"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"bin/",
|
|
35
|
+
"managed/",
|
|
36
|
+
"templates/",
|
|
37
|
+
"renovate/",
|
|
38
|
+
"docs/",
|
|
39
|
+
"config/actions.env",
|
|
40
|
+
"config/repos.env",
|
|
41
|
+
"config/repo-settings.json",
|
|
42
|
+
"config/rulesets/",
|
|
43
|
+
"config/secrets.env.example"
|
|
44
|
+
],
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsc -p actions/auto-work-items/tsconfig.json",
|
|
53
|
+
"check": "npm run build && git diff --exit-code -- actions/auto-work-items/dist && bash -n bin/*.sh managed/scripts/release/*.sh && node --check bin/cli.mjs && node --check bin/_json.mjs && node --check scripts/release/*.mjs",
|
|
54
|
+
"test": "node --test 'test/*.test.mjs'",
|
|
55
|
+
"gh:bootstrap": "bash bin/gh-bootstrap.sh",
|
|
56
|
+
"gh:reset": "bash bin/gh-reset.sh",
|
|
57
|
+
"sync-managed": "bash bin/sync-managed.sh",
|
|
58
|
+
"format": "prettier --write .",
|
|
59
|
+
"format:check": "prettier --check ."
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@ebalzan/config": "0.1.0",
|
|
63
|
+
"@types/node": "25.6.2",
|
|
64
|
+
"prettier": "3.9.10",
|
|
65
|
+
"typescript": "6.0.3"
|
|
66
|
+
},
|
|
67
|
+
"prettier": "@ebalzan/config/prettier"
|
|
68
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
+
"description": "Shared Renovate preset: keeps the lint, format, git-hook and compiler tooling on the same versions in every repo that extends it as github>ebalzan/ci//renovate/tooling#v2. Only the packages listed below are managed; every other dependency is left alone.",
|
|
4
|
+
"extends": ["config:recommended"],
|
|
5
|
+
"baseBranchPatterns": ["dev"],
|
|
6
|
+
"branchPrefix": "chore/renovate-",
|
|
7
|
+
"semanticCommits": "enabled",
|
|
8
|
+
"semanticCommitType": "chore",
|
|
9
|
+
"semanticCommitScope": "deps",
|
|
10
|
+
"rangeStrategy": "pin",
|
|
11
|
+
"minimumReleaseAge": "3 days",
|
|
12
|
+
"schedule": ["before 9am on monday"],
|
|
13
|
+
"dependencyDashboard": true,
|
|
14
|
+
"packageRules": [
|
|
15
|
+
{
|
|
16
|
+
"description": "Only the shared tooling below is managed; every other dependency (framework, runtime, GitHub Actions) stays manual.",
|
|
17
|
+
"matchPackageNames": ["*"],
|
|
18
|
+
"enabled": false
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"description": "One PR per repo for the shared tooling, including the two @ebalzan packages (majors get their own PR). chore keeps the branch type and the PR title in step for pr-title.",
|
|
22
|
+
"matchPackageNames": [
|
|
23
|
+
"prettier",
|
|
24
|
+
"eslint",
|
|
25
|
+
"@eslint/js",
|
|
26
|
+
"eslint-config-prettier",
|
|
27
|
+
"eslint-plugin-prettier",
|
|
28
|
+
"typescript-eslint",
|
|
29
|
+
"lint-staged",
|
|
30
|
+
"husky",
|
|
31
|
+
"typescript",
|
|
32
|
+
"@ebalzan/config",
|
|
33
|
+
"@ebalzan/ci"
|
|
34
|
+
],
|
|
35
|
+
"groupName": "dev tooling",
|
|
36
|
+
"semanticCommitType": "chore",
|
|
37
|
+
"enabled": true
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"description": "typescript-eslint (used directly, or through eslint-config-next / eslint-config-expo) only supports typescript <6.1. Raise this once it does.",
|
|
41
|
+
"matchPackageNames": ["typescript"],
|
|
42
|
+
"allowedVersions": "<6.1"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# GitHub Actions VARIABLES specific to THIS repo. Non-sensitive; committed.
|
|
2
|
+
#
|
|
3
|
+
# The shared defaults (describe model, size/estimate maps, …) live in
|
|
4
|
+
# __CI_REPO__'s config/actions.env and are read at run time — they are not
|
|
5
|
+
# pushed here. `ebalzan-ci bootstrap` pushes this file as repository variables;
|
|
6
|
+
# a key set here overrides the shared one. Every key: __CI_REPO__
|
|
7
|
+
# docs/CONFIGURATION.md.
|
|
8
|
+
#
|
|
9
|
+
# Removing a line does not delete the variable on GitHub; run
|
|
10
|
+
# `ebalzan-ci bootstrap --prune`.
|
|
11
|
+
|
|
12
|
+
# This repo's Projects (v2) board number (owned by the repo owner unless
|
|
13
|
+
# AUTO_PROJECT_OWNER says otherwise). Leave unset to run without a board.
|
|
14
|
+
# AUTO_PROJECT_NUMBER=
|
|
15
|
+
|
|
16
|
+
# Milestone put on every work item and promotion PR (exact title, open).
|
|
17
|
+
# AUTO_MILESTONE_TITLE=
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Auto Create Work Items — thin caller of __CI_REPO__'s shared workflow.
|
|
3
|
+
#
|
|
4
|
+
# On every push to a work branch (feat/…, fix/…, …) it creates or updates the
|
|
5
|
+
# tracking issue, the PR into dev and, when AUTO_PROJECT_NUMBER is set, the
|
|
6
|
+
# Projects (v2) card. Generated by `ebalzan-ci onboard`; the logic lives in
|
|
7
|
+
# __CI_REPO__ (docs/AUTO_WORK_ITEMS_WORKFLOW.md), so this file only holds what
|
|
8
|
+
# cannot live there: the trigger, the permissions and the secrets.
|
|
9
|
+
# =============================================================================
|
|
10
|
+
name: Auto Create Work Items
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
branches-ignore:
|
|
15
|
+
- main
|
|
16
|
+
- dev
|
|
17
|
+
tags-ignore:
|
|
18
|
+
- '**'
|
|
19
|
+
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
issues: write
|
|
23
|
+
pull-requests: write
|
|
24
|
+
repository-projects: write
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
work-items:
|
|
28
|
+
uses: __CI_REPO__/.github/workflows/auto-work-items.yml@__CI_REF__
|
|
29
|
+
with:
|
|
30
|
+
runs-on: __RUNS_ON__
|
|
31
|
+
secrets:
|
|
32
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
33
|
+
GH_PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# PR Checks — the quality gate for every PR into dev or main.
|
|
3
|
+
#
|
|
4
|
+
# title The shared PR-title check (__CI_REPO__): the title must be a
|
|
5
|
+
# Conventional Commit whose type matches the branch prefix. Keep the
|
|
6
|
+
# job id `title`: the check is reported as `title / Validate PR Title`,
|
|
7
|
+
# the name the shared rulesets require.
|
|
8
|
+
#
|
|
9
|
+
# Add this repo's own build/test/lint jobs below; they run in parallel.
|
|
10
|
+
# Generated by `ebalzan-ci onboard`.
|
|
11
|
+
# =============================================================================
|
|
12
|
+
name: PR Checks
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
pull_request:
|
|
16
|
+
branches: ['main', 'dev']
|
|
17
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
pull-requests: read
|
|
22
|
+
|
|
23
|
+
concurrency:
|
|
24
|
+
group: pr-checks-${{ github.event.pull_request.number }}
|
|
25
|
+
cancel-in-progress: true
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
title:
|
|
29
|
+
uses: __CI_REPO__/.github/workflows/pr-title.yml@__CI_REF__
|
|
30
|
+
with:
|
|
31
|
+
runs-on: __RUNS_ON__
|
|
32
|
+
|
|
33
|
+
# A Node repo's own checks. Uncomment and adapt; other stacks replace the
|
|
34
|
+
# steps (e.g. `go test ./...`).
|
|
35
|
+
# validate:
|
|
36
|
+
# name: Validate
|
|
37
|
+
# runs-on: __RUNS_ON__
|
|
38
|
+
# steps:
|
|
39
|
+
# - uses: actions/checkout@v4
|
|
40
|
+
# - uses: actions/setup-node@v4
|
|
41
|
+
# with:
|
|
42
|
+
# node-version: 24
|
|
43
|
+
# cache: npm
|
|
44
|
+
# - run: npm ci
|
|
45
|
+
# # Prettier/ESLint/TypeScript extend @ebalzan/config instead of copying it.
|
|
46
|
+
# - run: npx --no-install ebalzan-config verify
|
|
47
|
+
# # The repo's own script: format:check, lint, typecheck, test, …
|
|
48
|
+
# - run: npm run validate
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Promote dev → main — keeps ONE evergreen dev → main PR open.
|
|
3
|
+
#
|
|
4
|
+
# Every push to dev opens or updates it, titled with the release it will cut
|
|
5
|
+
# (e.g. `feat: promote dev to main (v1.4.0)`). Merging it (squash) is the
|
|
6
|
+
# release approval. Generated by `ebalzan-ci onboard`; logic in __CI_REPO__.
|
|
7
|
+
# =============================================================================
|
|
8
|
+
name: Promote dev to main
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: ['dev']
|
|
13
|
+
workflow_dispatch: {}
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
issues: write
|
|
18
|
+
pull-requests: write
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
promote:
|
|
22
|
+
uses: __CI_REPO__/.github/workflows/promote-dev-to-main.yml@__CI_REF__
|
|
23
|
+
with:
|
|
24
|
+
runs-on: __RUNS_ON__
|
|
25
|
+
secrets:
|
|
26
|
+
GH_PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Release — every push to main becomes a versioned release.
|
|
3
|
+
#
|
|
4
|
+
# The shared job computes the next semver from the Conventional Commits since
|
|
5
|
+
# the last tag, bumps package.json when there is one, tags vX.Y.Z, creates the
|
|
6
|
+
# GitHub Release and points dev at the release commit. Generated by
|
|
7
|
+
# `ebalzan-ci onboard`; logic in __CI_REPO__ (docs/CI_FLOW.md).
|
|
8
|
+
#
|
|
9
|
+
# Shipping is this repo's business: chain jobs on the outputs. `tag` is empty
|
|
10
|
+
# when nothing was released (the release commit's own run).
|
|
11
|
+
# =============================================================================
|
|
12
|
+
name: Release
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: ['main']
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: write
|
|
20
|
+
pull-requests: read
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
release:
|
|
24
|
+
uses: __CI_REPO__/.github/workflows/release.yml@__CI_REF__
|
|
25
|
+
with:
|
|
26
|
+
runs-on: __RUNS_ON__
|
|
27
|
+
|
|
28
|
+
# deploy:
|
|
29
|
+
# needs: release
|
|
30
|
+
# if: ${{ needs.release.outputs.tag != '' }}
|
|
31
|
+
# runs-on: __RUNS_ON__
|
|
32
|
+
# steps:
|
|
33
|
+
# - uses: actions/checkout@v4
|
|
34
|
+
# with:
|
|
35
|
+
# ref: ${{ needs.release.outputs.tag }}
|
|
36
|
+
# - run: echo "ship ${{ needs.release.outputs.tag }}"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Conventional Commits check for every local commit, from __CI_PACKAGE__
|
|
2
|
+
# (generated by `ebalzan-ci onboard`). The same rule runs on every PR title in
|
|
3
|
+
# CI, so a missing package only loses the early local warning — never the check.
|
|
4
|
+
|
|
5
|
+
# 1. The package, as a devDependency of this repo.
|
|
6
|
+
if [ -x node_modules/.bin/ebalzan-ci ]; then
|
|
7
|
+
exec node_modules/.bin/ebalzan-ci commit-msg "$1"
|
|
8
|
+
fi
|
|
9
|
+
|
|
10
|
+
# 2. A checkout of __CI_REPO__ next to this repo (or wherever CI_DIR points).
|
|
11
|
+
ci_dir="${CI_DIR:-../__CI_REPO_NAME__}"
|
|
12
|
+
if [ -f "$ci_dir/bin/cli.mjs" ]; then
|
|
13
|
+
exec node "$ci_dir/bin/cli.mjs" commit-msg "$1"
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
echo "commit-msg: __CI_PACKAGE__ is not installed; commit message not checked locally."
|
|
17
|
+
echo "Install it with: npm install --save-dev __CI_PACKAGE__"
|
|
18
|
+
exit 0
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// ESLint: the shared rules from @ebalzan/config, then this repo's own blocks
|
|
2
|
+
// (generated by `ebalzan-ci onboard`). A later block wins for the files it
|
|
3
|
+
// matches, e.g. { ignores: ['generated/'] } or { files: [...], rules: {...} }.
|
|
4
|
+
import node from '@ebalzan/config/eslint/node'
|
|
5
|
+
|
|
6
|
+
export default [...node]
|