@open-tomato/rafa 0.45.0 → 0.46.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 (140) hide show
  1. package/README.md +255 -23
  2. package/dist/PROMPT.md +18 -1
  3. package/dist/adapters/logger/settings.d.ts +132 -0
  4. package/dist/bugs/closest.d.ts +19 -0
  5. package/dist/bugs/fenced.d.ts +8 -0
  6. package/dist/bugs/places.d.ts +20 -0
  7. package/dist/bugs/record.d.ts +145 -0
  8. package/dist/bugs/title.d.ts +83 -0
  9. package/dist/bundled/agents/doc-updater.md +17 -3
  10. package/dist/bundled/agents/loop-implementer.md +14 -2
  11. package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +10 -3
  12. package/dist/bundled/operators/skills/rafa-stretch-sweep/SKILL.md +5 -0
  13. package/dist/bundled/skills/dev-planner/SKILL.md +101 -18
  14. package/dist/cli.js +74726 -62960
  15. package/dist/config/entry.d.ts +119 -0
  16. package/dist/config/index.d.ts +36 -0
  17. package/dist/config/index.js +51 -0
  18. package/dist/config/shape.d.ts +232 -0
  19. package/dist/config-registry.d.ts +127 -0
  20. package/dist/config-schema-board-project.d.ts +157 -0
  21. package/dist/config-schema-bugs.d.ts +71 -0
  22. package/dist/config-schema-errors.d.ts +54 -0
  23. package/dist/config-schema-features.d.ts +64 -0
  24. package/dist/config-schema-hub.d.ts +150 -0
  25. package/dist/config-schema-issues.d.ts +95 -0
  26. package/dist/config-schema-logger.d.ts +91 -0
  27. package/dist/config-schema-loop-continue.d.ts +122 -0
  28. package/dist/config-schema-loop-retries.d.ts +94 -0
  29. package/dist/config-schema-release.d.ts +307 -0
  30. package/dist/config-schema-tests.d.ts +170 -0
  31. package/dist/config-schema-triage.d.ts +142 -0
  32. package/dist/config-schema-wrap-up.d.ts +96 -0
  33. package/dist/core/command/command.d.ts +228 -0
  34. package/dist/core/command/confirm.d.ts +67 -0
  35. package/dist/core/command/index.d.ts +112 -0
  36. package/dist/core/command/lazy.d.ts +54 -0
  37. package/dist/core/command/registry-types.d.ts +96 -0
  38. package/dist/core/command/running.d.ts +96 -0
  39. package/dist/core/command/spends.d.ts +39 -0
  40. package/dist/core/command/types.d.ts +92 -0
  41. package/dist/core/command/version.d.ts +4 -0
  42. package/dist/core/config/branch-template.d.ts +20 -0
  43. package/dist/core/config/config-items.d.ts +86 -0
  44. package/dist/core/config/config-load.d.ts +47 -0
  45. package/dist/core/config/config-origins.d.ts +57 -0
  46. package/dist/core/config/config-readers.d.ts +167 -0
  47. package/dist/core/config/config-schema.d.ts +207 -0
  48. package/dist/core/config/config-sections.d.ts +493 -0
  49. package/dist/core/config/config.d.ts +320 -0
  50. package/dist/core/config/core-section.d.ts +39 -0
  51. package/dist/core/config/dangerous.d.ts +58 -0
  52. package/dist/core/config/default-routing.d.ts +16 -0
  53. package/dist/core/config/index.d.ts +141 -0
  54. package/dist/core/config/scope.d.ts +42 -0
  55. package/dist/core/config/section.d.ts +206 -0
  56. package/dist/core/config/sections.d.ts +45 -0
  57. package/dist/core/config/standard-schema.d.ts +27 -0
  58. package/dist/core/git/commit.d.ts +232 -0
  59. package/dist/core/git/gh-runner.d.ts +24 -0
  60. package/dist/core/git/git.d.ts +22 -0
  61. package/dist/core/git/index.d.ts +85 -0
  62. package/dist/core/loop/claude.d.ts +388 -0
  63. package/dist/core/loop/hop-record.d.ts +52 -0
  64. package/dist/core/loop/index.d.ts +179 -0
  65. package/dist/core/loop/session-env.d.ts +20 -0
  66. package/dist/core/loop/session-record-parse.d.ts +63 -0
  67. package/dist/core/loop/sessions.d.ts +408 -0
  68. package/dist/core/loop/suite-failure.d.ts +25 -0
  69. package/dist/core/output/active.d.ts +100 -0
  70. package/dist/core/output/stream.d.ts +20 -0
  71. package/dist/core/output/text.d.ts +55 -0
  72. package/dist/core/plan/block-reader.d.ts +46 -0
  73. package/dist/core/plan/blocks.d.ts +139 -0
  74. package/dist/core/plan/declaration.d.ts +366 -0
  75. package/dist/core/plan/plan-stamp.d.ts +75 -0
  76. package/dist/core/runtime/identity.d.ts +21 -0
  77. package/dist/core/runtime/index.d.ts +46 -0
  78. package/dist/effort/store/bring-forward.d.ts +131 -0
  79. package/dist/effort/store/check-rows.d.ts +31 -0
  80. package/dist/effort/store/commit-stats.d.ts +42 -0
  81. package/dist/effort/store/copy.d.ts +35 -0
  82. package/dist/effort/store/development-build.d.ts +105 -0
  83. package/dist/effort/store/effort-levels.d.ts +13 -0
  84. package/dist/effort/store/findings.d.ts +214 -0
  85. package/dist/effort/store/fix-schema.d.ts +184 -0
  86. package/dist/effort/store/index.js +10 -7
  87. package/dist/effort/store/location.d.ts +44 -0
  88. package/dist/effort/store/merge-commit-gaps.d.ts +68 -0
  89. package/dist/effort/store/merge-conflicts.d.ts +91 -0
  90. package/dist/effort/store/merge-rules.d.ts +82 -0
  91. package/dist/effort/store/merge-store.d.ts +211 -0
  92. package/dist/effort/store/merge-union.d.ts +92 -0
  93. package/dist/effort/store/migrate.d.ts +146 -0
  94. package/dist/effort/store/migrations.d.ts +92 -0
  95. package/dist/effort/store/ndjson-files.d.ts +114 -0
  96. package/dist/effort/store/origins.d.ts +116 -0
  97. package/dist/effort/store/plan-stubs.d.ts +79 -0
  98. package/dist/effort/store/rebuild-aside.d.ts +172 -0
  99. package/dist/effort/store/schema-plan.d.ts +102 -0
  100. package/dist/effort/store/session-row-types.d.ts +64 -0
  101. package/dist/effort/store/settings.d.ts +13 -0
  102. package/dist/effort/store/sqlite.d.ts +340 -0
  103. package/dist/effort/store/store-generation.d.ts +17 -0
  104. package/dist/effort/store/store-identity.d.ts +220 -0
  105. package/dist/effort/store/store-meta.d.ts +305 -0
  106. package/dist/effort/store/store-replaced.d.ts +72 -0
  107. package/dist/effort/store/types.d.ts +223 -0
  108. package/dist/errors/codes.d.ts +56 -0
  109. package/dist/errors/rafa-codes.d.ts +36 -0
  110. package/dist/index-2a7nb3an.js +125 -0
  111. package/dist/{index-r28fzsvc.js → index-39kbcw68.js} +350 -165
  112. package/dist/{index-nv34ptht.js → index-77ajfffn.js} +14 -9
  113. package/dist/index-cy98y87p.js +2597 -0
  114. package/dist/index-gqz4jn6j.js +13447 -0
  115. package/dist/index-gvek4r8m.js +710 -0
  116. package/dist/index-j4k2vdz3.js +1125 -0
  117. package/dist/index-jh1r4kcn.js +1067 -0
  118. package/dist/{index-mgh2s9bj.js → index-ykggr043.js} +58 -455
  119. package/dist/index-z1w83f81.js +4 -0
  120. package/dist/index.js +14715 -21516
  121. package/dist/learning/index.js +5 -6
  122. package/dist/plan/index.js +12 -11
  123. package/dist/plan-prompt.md +3 -1
  124. package/dist/ports/index.d.ts +732 -0
  125. package/dist/ports/learning.d.ts +101 -0
  126. package/dist/ports/log-level.d.ts +13 -0
  127. package/dist/ports/spec-review.d.ts +66 -0
  128. package/dist/pr/checks.d.ts +133 -0
  129. package/dist/pr/types.d.ts +422 -0
  130. package/dist/ready-4f8edezt.js +2016 -0
  131. package/dist/release-templates/release-bot-fragment.yml +153 -0
  132. package/dist/release-templates/release-publish.yml +110 -0
  133. package/dist/release-templates/release-settle.yml +122 -0
  134. package/dist/release-templates/release-tag.yml +102 -0
  135. package/dist/report/parse.d.ts +415 -0
  136. package/dist/schema/project-id.d.ts +79 -0
  137. package/dist/schema/tiers.d.ts +107 -0
  138. package/package.json +41 -3
  139. package/dist/index-hf2k497d.js +0 -16
  140. package/dist/index-nsr78ct2.js +0 -8219
@@ -0,0 +1,153 @@
1
+ # The rafa release bot fragment workflow: the fragment of a Dependabot
2
+ # pull request, for levels 3 and 4 of the release ladder.
3
+ #
4
+ # Written into a project's `.github/workflows/` by `writeReleaseWorkflow`
5
+ # (`src/release/templates.ts`) at levels 3 and 4 while
6
+ # `.github/dependabot.yml` exists. A bot pull request has no wrap-up to
7
+ # write its fragment, so this workflow writes one with
8
+ # `rafa release fragment --plan=dependabot-<number>`, at `patch` when
9
+ # `dependabot/fetch-metadata` reads the update as `direct:production` and
10
+ # at `none` otherwise, commits it as `chore: release fragment
11
+ # dependabot-<number>` and pushes it to the pull request's branch. A
12
+ # branch that already adds a fragment named for the pull request
13
+ # (`dependabot-<number>.md`, or `-2`, `-3` and on) is left as it is.
14
+ #
15
+ # A `pull_request` run started by Dependabot gets a read-only token, so
16
+ # this runs on `pull_request_target`, in the base branch's context with a
17
+ # writable one. That is why nothing from the pull request's branch runs
18
+ # here: the branch is checked out under `head/` only to add one file and
19
+ # push, while bun is set up from, and rafa installed or run from, the
20
+ # base branch's checkout under `base/`. rafa reads its config (a
21
+ # `rafa.config.ts` included) and loads its modules from the directory it
22
+ # runs in, so the fragment is written in `base/` and copied to `head/`.
23
+ #
24
+ # A commit pushed with the workflow's GITHUB_TOKEN starts no other
25
+ # workflow run, and Dependabot stops rebasing a branch someone else has
26
+ # pushed to; a rebase it is asked for drops the fragment commit, and the
27
+ # `synchronize` run that follows writes it again.
28
+ #
29
+ # rafa needs a config with `release.enabled: true`, and the base's
30
+ # checkout may hold none: when none of `rafa.config.ts`, `rafa.config.mjs`
31
+ # and `.rafa/config.yaml` is there, the workflow writes
32
+ # `.rafa/config.yaml` with that key in `base/`. A committed config is left
33
+ # as it is, so a project that needs other release keys in CI commits
34
+ # them. The written config stays in the runner's checkout: the commit
35
+ # stages the fragment alone.
36
+ #
37
+ # rafa runs from the base's checkout when the project is rafa itself (its
38
+ # manifest names `@open-tomato/rafa` and git tracks `src/rafa.ts`), and
39
+ # from a global install otherwise, so one file serves both.
40
+ name: Release bot fragment
41
+
42
+ on:
43
+ pull_request_target:
44
+ types: [opened, synchronize, reopened]
45
+
46
+ permissions:
47
+ contents: write
48
+ pull-requests: read
49
+
50
+ concurrency:
51
+ group: release-bot-fragment-${{ github.event.pull_request.number }}
52
+ cancel-in-progress: false
53
+
54
+ jobs:
55
+ fragment:
56
+ if: >-
57
+ github.actor == 'dependabot[bot]'
58
+ && github.event.pull_request.head.repo.full_name == github.repository
59
+ runs-on: ubuntu-latest
60
+ timeout-minutes: 15
61
+ steps:
62
+ - name: Fetch metadata
63
+ id: metadata
64
+ uses: dependabot/fetch-metadata@v2
65
+
66
+ - name: Checkout the base
67
+ uses: actions/checkout@v4
68
+ with:
69
+ ref: ${{ github.event.pull_request.base.ref }}
70
+ path: base
71
+ fetch-depth: 0
72
+
73
+ - name: Checkout the head
74
+ uses: actions/checkout@v4
75
+ with:
76
+ ref: ${{ github.event.pull_request.head.ref }}
77
+ path: head
78
+ fetch-depth: 0
79
+ persist-credentials: true
80
+
81
+ - name: Look for the fragment
82
+ id: held
83
+ shell: bash
84
+ working-directory: head
85
+ env:
86
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
87
+ PR_NUMBER: ${{ github.event.pull_request.number }}
88
+ run: |
89
+ added=$(git diff --name-only --diff-filter=A "origin/$BASE_REF...HEAD")
90
+ if printf '%s\n' "$added" | grep -Eq "(^|/)dependabot-$PR_NUMBER(-[0-9]+)?\.md$"; then
91
+ echo "held=true" >> "$GITHUB_OUTPUT"
92
+ else
93
+ echo "held=false" >> "$GITHUB_OUTPUT"
94
+ fi
95
+
96
+ - name: Set up bun
97
+ if: steps.held.outputs.held == 'false'
98
+ uses: oven-sh/setup-bun@v2
99
+ with:
100
+ bun-version-file: base/package.json
101
+
102
+ - name: Write the CI config
103
+ if: steps.held.outputs.held == 'false'
104
+ shell: bash
105
+ working-directory: base
106
+ run: |
107
+ if [ ! -f rafa.config.ts ] && [ ! -f rafa.config.mjs ] && [ ! -f .rafa/config.yaml ]; then
108
+ mkdir -p .rafa
109
+ printf '%s\n' '# Written by the Release bot fragment workflow: the checkout holds no rafa config.' 'release:' ' enabled: true' > .rafa/config.yaml
110
+ fi
111
+
112
+ - name: Write the fragment
113
+ id: write
114
+ if: steps.held.outputs.held == 'false'
115
+ shell: bash
116
+ working-directory: base
117
+ env:
118
+ DEPENDENCY_TYPE: ${{ steps.metadata.outputs.dependency-type }}
119
+ PR_NUMBER: ${{ github.event.pull_request.number }}
120
+ PR_TITLE: ${{ github.event.pull_request.title }}
121
+ run: |
122
+ if [ "$DEPENDENCY_TYPE" = 'direct:production' ]; then
123
+ level=patch
124
+ else
125
+ level=none
126
+ fi
127
+ name=$(node -p "require('./package.json').name")
128
+ if [ "$name" = '@open-tomato/rafa' ] && git ls-files --error-unmatch src/rafa.ts > /dev/null 2>&1; then
129
+ bun install --frozen-lockfile
130
+ written=$(bun src/rafa.ts release fragment "--plan=dependabot-$PR_NUMBER" "--level=$level" "--title=$PR_TITLE" | tail -n 1)
131
+ else
132
+ bun install -g @open-tomato/rafa
133
+ export PATH="${BUN_INSTALL:-$HOME/.bun}/bin:$PATH"
134
+ written=$(rafa release fragment "--plan=dependabot-$PR_NUMBER" "--level=$level" "--title=$PR_TITLE" | tail -n 1)
135
+ fi
136
+ mkdir -p "../head/$(dirname "$written")"
137
+ cp "$written" "../head/$written"
138
+ echo "path=$written" >> "$GITHUB_OUTPUT"
139
+
140
+ - name: Commit and push
141
+ if: steps.held.outputs.held == 'false'
142
+ shell: bash
143
+ working-directory: head
144
+ env:
145
+ FRAGMENT: ${{ steps.write.outputs.path }}
146
+ HEAD_REF: ${{ github.event.pull_request.head.ref }}
147
+ PR_NUMBER: ${{ github.event.pull_request.number }}
148
+ run: |
149
+ git config user.name 'github-actions[bot]'
150
+ git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
151
+ git add -- "$FRAGMENT"
152
+ git commit -m "chore: release fragment dependabot-$PR_NUMBER"
153
+ git push origin "HEAD:$HEAD_REF"
@@ -0,0 +1,110 @@
1
+ # The rafa release publish workflow: level 2 of the release ladder.
2
+ #
3
+ # Written into a project's `.github/workflows/` by `writeReleaseWorkflow`
4
+ # (`src/release/templates.ts`) for `release.publish: ci`. A pushed tag,
5
+ # or a workflow that tags in its own run and calls this one with the tag
6
+ # as `ref`, checks the tag out, runs the gates and then
7
+ # `rafa release publish`, which publishes every release unit whose tag
8
+ # points at the checked-out commit and skips a version the registry
9
+ # already holds.
10
+ #
11
+ # npm trusted publishing needs npm 11.5.1 or newer, `id-token: write` on
12
+ # the job, and a trusted publisher configured on npmjs.com for each
13
+ # package, naming this repository and this workflow file. npm attaches
14
+ # provenance on a trusted publish, so no token and no flag are set here.
15
+ #
16
+ # The publish job runs only when the repository variable
17
+ # `RAFA_RELEASE_PUBLISH` is `ci`: with it unset or holding anything else,
18
+ # GitHub skips the job, and a skipped job does not fail the run. Set it
19
+ # under Settings, Secrets and variables, Actions, Variables, or with
20
+ # `gh variable set RAFA_RELEASE_PUBLISH --body ci`.
21
+ #
22
+ # A tag pushed with a workflow's GITHUB_TOKEN starts no other workflow
23
+ # run, so a workflow that tags calls this one through `workflow_call`
24
+ # instead of waiting for the `push` trigger.
25
+ #
26
+ # rafa needs a config with `release.enabled: true`, and the checkout may
27
+ # hold none: when none of `rafa.config.ts`, `rafa.config.mjs` and
28
+ # `.rafa/config.yaml` is there, the workflow writes `.rafa/config.yaml`
29
+ # with that key. A committed config is left as it is, so a project that
30
+ # needs other release keys in CI commits them.
31
+ #
32
+ # rafa runs from the checkout when the project is rafa itself (its
33
+ # manifest names `@open-tomato/rafa` and git tracks `src/rafa.ts`), and
34
+ # from a global install otherwise, so one file serves both.
35
+ name: Release publish
36
+
37
+ on:
38
+ push:
39
+ tags: ['**']
40
+ workflow_call:
41
+ inputs:
42
+ ref:
43
+ description: The tag or commit to publish from.
44
+ required: true
45
+ type: string
46
+
47
+ permissions:
48
+ contents: read
49
+ id-token: write
50
+
51
+ jobs:
52
+ publish:
53
+ if: vars.RAFA_RELEASE_PUBLISH == 'ci'
54
+ runs-on: ubuntu-latest
55
+ timeout-minutes: 30
56
+ steps:
57
+ - name: Checkout
58
+ uses: actions/checkout@v4
59
+ with:
60
+ ref: ${{ inputs.ref || github.ref }}
61
+ fetch-depth: 0
62
+
63
+ - name: Set up bun
64
+ uses: oven-sh/setup-bun@v2
65
+ with:
66
+ bun-version-file: package.json
67
+
68
+ - name: Set up node
69
+ uses: actions/setup-node@v4
70
+ with:
71
+ node-version: 24
72
+ registry-url: https://registry.npmjs.org
73
+
74
+ - name: Upgrade npm
75
+ run: npm install -g npm@latest && npm --version
76
+
77
+ - name: Install
78
+ run: bun install --frozen-lockfile
79
+
80
+ - name: Test
81
+ if: ${{ !cancelled() }}
82
+ run: bun test
83
+
84
+ - name: Lint
85
+ if: ${{ !cancelled() }}
86
+ run: bunx eslint .
87
+
88
+ - name: Types
89
+ if: ${{ !cancelled() }}
90
+ run: bun run check-types
91
+
92
+ - name: Write the CI config
93
+ shell: bash
94
+ run: |
95
+ if [ ! -f rafa.config.ts ] && [ ! -f rafa.config.mjs ] && [ ! -f .rafa/config.yaml ]; then
96
+ mkdir -p .rafa
97
+ printf '%s\n' '# Written by the Release publish workflow: the checkout holds no rafa config.' 'release:' ' enabled: true' > .rafa/config.yaml
98
+ fi
99
+
100
+ - name: Publish
101
+ shell: bash
102
+ run: |
103
+ name=$(node -p "require('./package.json').name")
104
+ if [ "$name" = '@open-tomato/rafa' ] && git ls-files --error-unmatch src/rafa.ts > /dev/null 2>&1; then
105
+ bun src/rafa.ts release publish
106
+ else
107
+ bun install -g @open-tomato/rafa
108
+ export PATH="${BUN_INSTALL:-$HOME/.bun}/bin:$PATH"
109
+ rafa release publish
110
+ fi
@@ -0,0 +1,122 @@
1
+ # The rafa release settle workflow: level 4 of the release ladder.
2
+ #
3
+ # Written into a project's `.github/workflows/` by `writeReleaseWorkflow`
4
+ # (`src/release/templates.ts`) for `release.settle: push` with
5
+ # `release.tag: settle` and `release.publish: ci`. Every push to the base
6
+ # branch checks it out with full history, sets a git identity for the
7
+ # release commit, and runs `rafa release settle`, which folds the waiting
8
+ # fragments into a release commit, pushes it to the base and tags it.
9
+ # A push with no fragment waiting settles nothing and exits 0.
10
+ #
11
+ # The settle job runs on a push to the repository's default branch. When
12
+ # `pr.base` names another branch, write that branch's name in place of
13
+ # `github.event.repository.default_branch` in the job's `if`.
14
+ #
15
+ # A commit or tag pushed with the workflow's GITHUB_TOKEN starts no other
16
+ # workflow run, so the release commit settle pushes does not run this
17
+ # workflow again, and the publish job calls `release-publish.yml` through
18
+ # `workflow_call` with the release commit as `ref` instead of waiting for
19
+ # its `push: tags` trigger. It runs only when settle pushed a release
20
+ # commit and tagged it; the job grants `id-token: write` for npm trusted
21
+ # publishing, and the settle job needs only `contents: write`.
22
+ #
23
+ # The publish job runs only when the repository variable
24
+ # `RAFA_RELEASE_PUBLISH` is `ci`: with it unset or holding anything else,
25
+ # GitHub skips the job, and a skipped job does not fail the run. Set it
26
+ # under Settings, Secrets and variables, Actions, Variables, or with
27
+ # `gh variable set RAFA_RELEASE_PUBLISH --body ci`.
28
+ # Settling and tagging run either way; publishing waits for the switch.
29
+ #
30
+ # rafa needs a config with `release.enabled: true`, and the checkout may
31
+ # hold none: when none of `rafa.config.ts`, `rafa.config.mjs` and
32
+ # `.rafa/config.yaml` is there, the workflow writes `.rafa/config.yaml`
33
+ # with that key. A committed config is left as it is, so a project that
34
+ # needs other release keys in CI commits them.
35
+ #
36
+ # rafa runs from the checkout when the project is rafa itself (its
37
+ # manifest names `@open-tomato/rafa` and git tracks `src/rafa.ts`), and
38
+ # from a global install otherwise, so one file serves both.
39
+ name: Release settle
40
+
41
+ on:
42
+ push:
43
+ branches: ['**']
44
+
45
+ permissions:
46
+ contents: write
47
+
48
+ concurrency:
49
+ group: release-settle
50
+ cancel-in-progress: false
51
+
52
+ jobs:
53
+ settle:
54
+ if: github.ref_name == github.event.repository.default_branch
55
+ runs-on: ubuntu-latest
56
+ timeout-minutes: 15
57
+ outputs:
58
+ release: ${{ steps.settle.outputs.release }}
59
+ steps:
60
+ - name: Checkout
61
+ uses: actions/checkout@v4
62
+ with:
63
+ ref: ${{ github.ref_name }}
64
+ fetch-depth: 0
65
+
66
+ - name: Set git identity
67
+ run: |
68
+ git config user.name 'github-actions[bot]'
69
+ git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
70
+
71
+ - name: Set up bun
72
+ uses: oven-sh/setup-bun@v2
73
+ with:
74
+ bun-version-file: package.json
75
+
76
+ - name: Write the CI config
77
+ shell: bash
78
+ run: |
79
+ if [ ! -f rafa.config.ts ] && [ ! -f rafa.config.mjs ] && [ ! -f .rafa/config.yaml ]; then
80
+ mkdir -p .rafa
81
+ printf '%s\n' '# Written by the Release settle workflow: the checkout holds no rafa config.' 'release:' ' enabled: true' > .rafa/config.yaml
82
+ fi
83
+
84
+ - name: Settle
85
+ id: settle
86
+ shell: bash
87
+ run: |
88
+ result="${RUNNER_TEMP:-/tmp}/settle.json"
89
+ name=$(node -p "require('./package.json').name")
90
+ if [ "$name" = '@open-tomato/rafa' ] && git ls-files --error-unmatch src/rafa.ts > /dev/null 2>&1; then
91
+ bun install --frozen-lockfile
92
+ bun src/rafa.ts release settle --output=json > "$result"
93
+ else
94
+ bun install -g @open-tomato/rafa
95
+ export PATH="${BUN_INSTALL:-$HOME/.bun}/bin:$PATH"
96
+ rafa release settle --output=json > "$result"
97
+ fi
98
+ cat "$result"
99
+ node -e '
100
+ const fs = require("fs");
101
+ const events = fs.readFileSync(process.argv[1], "utf8").split("\n").flatMap((line) => {
102
+ try { return [JSON.parse(line)]; } catch { return []; }
103
+ });
104
+ const data = (events.find((event) => event && event.type === "result") || {}).data || {};
105
+ const pushed = data.delivered && data.delivered.outcome && data.delivered.outcome.outcome === "pushed";
106
+ const tagged = data.tag && data.tag.outcome === "tagged" && data.tag.tags.length > 0;
107
+ const release = pushed && tagged
108
+ ? data.tag.commit
109
+ : "";
110
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, `release=${release}\n`);
111
+ ' "$result"
112
+
113
+ publish:
114
+ needs: settle
115
+ if: needs.settle.outputs.release != '' && vars.RAFA_RELEASE_PUBLISH == 'ci'
116
+ permissions:
117
+ contents: read
118
+ id-token: write
119
+ uses: ./.github/workflows/release-publish.yml
120
+ with:
121
+ ref: ${{ needs.settle.outputs.release }}
122
+ secrets: inherit
@@ -0,0 +1,102 @@
1
+ # The rafa release tag workflow: level 3 of the release ladder.
2
+ #
3
+ # Written into a project's `.github/workflows/` by `writeReleaseWorkflow`
4
+ # (`src/release/templates.ts`) for `release.settle: pr` with
5
+ # `release.tag: settle` and `release.publish: ci`. Settle never tags a
6
+ # `pr` delivery: it pushes the release commit to `rafa/release` and opens
7
+ # one release pull request. When that pull request merges, by any merge
8
+ # button, this workflow checks the base branch out at the merge commit,
9
+ # runs `rafa release tag --push`, and then publishes.
10
+ #
11
+ # It runs only on the release pull request's merge: a closed pull
12
+ # request that did not merge, or one from another head or from a fork,
13
+ # runs nothing, since `rafa release tag` refuses `tagged` (exit 1) once
14
+ # every unit is tagged.
15
+ #
16
+ # A tag pushed with the workflow's GITHUB_TOKEN starts no other workflow
17
+ # run, so the publish job calls `release-publish.yml` through
18
+ # `workflow_call` with the merge commit as `ref` instead of waiting for
19
+ # its `push: tags` trigger. That job grants `id-token: write` for npm
20
+ # trusted publishing; the tag job needs only `contents: write`.
21
+ #
22
+ # The publish job runs only when the repository variable
23
+ # `RAFA_RELEASE_PUBLISH` is `ci`: with it unset or holding anything else,
24
+ # GitHub skips the job, and a skipped job does not fail the run. Set it
25
+ # under Settings, Secrets and variables, Actions, Variables, or with
26
+ # `gh variable set RAFA_RELEASE_PUBLISH --body ci`.
27
+ # Tagging runs either way; publishing waits for the switch.
28
+ #
29
+ # rafa needs a config with `release.enabled: true`, and the checkout may
30
+ # hold none: when none of `rafa.config.ts`, `rafa.config.mjs` and
31
+ # `.rafa/config.yaml` is there, the workflow writes `.rafa/config.yaml`
32
+ # with that key. A committed config is left as it is, so a project that
33
+ # needs other release keys in CI commits them.
34
+ #
35
+ # rafa runs from the checkout when the project is rafa itself (its
36
+ # manifest names `@open-tomato/rafa` and git tracks `src/rafa.ts`), and
37
+ # from a global install otherwise, so one file serves both.
38
+ name: Release tag
39
+
40
+ on:
41
+ pull_request:
42
+ types: [closed]
43
+
44
+ permissions:
45
+ contents: write
46
+
47
+ jobs:
48
+ tag:
49
+ if: >-
50
+ github.event.pull_request.merged == true
51
+ && github.event.pull_request.head.ref == 'rafa/release'
52
+ && github.event.pull_request.head.repo.full_name == github.repository
53
+ runs-on: ubuntu-latest
54
+ timeout-minutes: 15
55
+ steps:
56
+ - name: Checkout
57
+ uses: actions/checkout@v4
58
+ with:
59
+ ref: ${{ github.event.pull_request.base.ref }}
60
+ fetch-depth: 0
61
+
62
+ - name: Move to the merge commit
63
+ env:
64
+ MERGE_COMMIT: ${{ github.event.pull_request.merge_commit_sha }}
65
+ run: git reset --hard "$MERGE_COMMIT"
66
+
67
+ - name: Set up bun
68
+ uses: oven-sh/setup-bun@v2
69
+ with:
70
+ bun-version-file: package.json
71
+
72
+ - name: Write the CI config
73
+ shell: bash
74
+ run: |
75
+ if [ ! -f rafa.config.ts ] && [ ! -f rafa.config.mjs ] && [ ! -f .rafa/config.yaml ]; then
76
+ mkdir -p .rafa
77
+ printf '%s\n' '# Written by the Release tag workflow: the checkout holds no rafa config.' 'release:' ' enabled: true' > .rafa/config.yaml
78
+ fi
79
+
80
+ - name: Tag
81
+ shell: bash
82
+ run: |
83
+ name=$(node -p "require('./package.json').name")
84
+ if [ "$name" = '@open-tomato/rafa' ] && git ls-files --error-unmatch src/rafa.ts > /dev/null 2>&1; then
85
+ bun install --frozen-lockfile
86
+ bun src/rafa.ts release tag --push --output=json
87
+ else
88
+ bun install -g @open-tomato/rafa
89
+ export PATH="${BUN_INSTALL:-$HOME/.bun}/bin:$PATH"
90
+ rafa release tag --push --output=json
91
+ fi
92
+
93
+ publish:
94
+ needs: tag
95
+ if: vars.RAFA_RELEASE_PUBLISH == 'ci'
96
+ permissions:
97
+ contents: read
98
+ id-token: write
99
+ uses: ./.github/workflows/release-publish.yml
100
+ with:
101
+ ref: ${{ github.event.pull_request.merge_commit_sha }}
102
+ secrets: inherit