ci(jetbrains): lock release tag before publish

This commit is contained in:
kirillk
2026-05-27 13:01:11 -04:00
parent beb8a406f0
commit 3b58e05e70
8 changed files with 150 additions and 144 deletions
@@ -49,7 +49,7 @@ jobs:
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
- name: Create or update release PR
- name: Create release tag and PR
run: |
args=(--kind "$KIND" --version "$VERSION")
if [[ -n "$FROM_TAG" ]]; then
+50 -50
View File
@@ -2,29 +2,61 @@
name: publish-jetbrains
on:
push:
tags:
- "jetbrains/*"
pull_request:
types:
- closed
branches:
- main
concurrency:
group: publish-jetbrains-${{ github.ref }}
group: publish-jetbrains-pr-${{ github.event.pull_request.number }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
publish:
if: github.repository == 'Kilo-Org/kilocode'
if: >-
github.repository == 'Kilo-Org/kilocode' &&
github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'jetbrains/release/') &&
contains(github.event.pull_request.labels.*.name, 'jetbrains-release') &&
github.event.pull_request.head.repo.full_name == github.repository
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Checkout merged release PR
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.merge_commit_sha }}
- name: Setup Bun for validation
uses: ./.github/actions/setup-bun
- name: Validate release PR and tag
id: release
run: bun script/jetbrains-release-validate.ts --pr "$PR_NUMBER"
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
- name: Save reviewed changelog
run: cp packages/kilo-jetbrains/CHANGELOG.md "$RUNNER_TEMP/jetbrains-CHANGELOG.md"
- name: Checkout release tag
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ steps.release.outputs.tag }}
- name: Restore reviewed changelog
run: cp "$RUNNER_TEMP/jetbrains-CHANGELOG.md" packages/kilo-jetbrains/CHANGELOG.md
- name: Setup Node
uses: actions/setup-node@v4
@@ -48,39 +80,6 @@ jobs:
sudo apt-get update
sudo apt-get install -y patchelf zip
- name: Validate version tag
id: version
run: |
tag="$GITHUB_REF_NAME"
if [[ "$tag" != jetbrains/v* ]]; then
echo "Unsupported tag '$tag'. Expected jetbrains/v<version>." >&2
exit 1
fi
version="${tag#jetbrains/v}"
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
{
echo "version=$version"
echo "kind=rc"
echo "marketplace_channel=eap"
echo "cli_channel=rc"
} >> "$GITHUB_OUTPUT"
exit 0
fi
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
{
echo "version=$version"
echo "kind=stable"
echo "marketplace_channel=default"
echo "cli_channel=latest"
} >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Unsupported JetBrains plugin version '$version'. Expected jetbrains/vx.y.z-rc.n or jetbrains/vx.y.z." >&2
exit 1
- name: Validate publishing secrets
run: |
missing=0
@@ -101,8 +100,8 @@ jobs:
working-directory: packages/kilo-jetbrains
run: bun script/build.ts --production --prepare-cli
env:
KILO_VERSION: ${{ steps.version.outputs.version }}
KILO_CHANNEL: ${{ steps.version.outputs.cli_channel }}
KILO_VERSION: ${{ steps.release.outputs.version }}
KILO_CHANNEL: ${{ steps.release.outputs.cli_channel }}
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
@@ -110,24 +109,24 @@ jobs:
working-directory: packages/kilo-jetbrains
run: ./gradlew verifyPlugin -Pproduction=true -Pkilo.channel="$CHANNEL"
env:
CHANNEL: ${{ steps.version.outputs.marketplace_channel }}
CHANNEL: ${{ steps.release.outputs.marketplace_channel }}
- name: Render release notes
working-directory: packages/kilo-jetbrains
run: |
if ! grep -Fq "## [$VERSION]" CHANGELOG.md; then
echo "Missing packages/kilo-jetbrains/CHANGELOG.md entry for $VERSION. Create a release PR or add the changelog section before tagging." >&2
echo "Missing packages/kilo-jetbrains/CHANGELOG.md entry for $VERSION. Review and merge a release PR before publishing." >&2
exit 1
fi
./gradlew getChangelog --project-version "$VERSION" --no-header --no-empty-sections --output-file=build/release-notes.md
env:
VERSION: ${{ steps.version.outputs.version }}
VERSION: ${{ steps.release.outputs.version }}
- name: Publish to JetBrains Marketplace
working-directory: packages/kilo-jetbrains
run: ./gradlew publishPlugin -Pproduction=true -Pkilo.channel="$CHANNEL"
env:
CHANNEL: ${{ steps.version.outputs.marketplace_channel }}
CHANNEL: ${{ steps.release.outputs.marketplace_channel }}
JETBRAINS_MARKETPLACE_TOKEN: ${{ secrets.JETBRAINS_MARKETPLACE_TOKEN }}
JETBRAINS_CERTIFICATE_CHAIN: ${{ secrets.JETBRAINS_CERTIFICATE_CHAIN }}
JETBRAINS_PRIVATE_KEY: ${{ secrets.JETBRAINS_PRIVATE_KEY }}
@@ -157,7 +156,7 @@ jobs:
- name: Upload to GitHub Release
run: |
tag="$GITHUB_REF_NAME"
tag="$TAG"
title="JetBrains $VERSION"
flags=(--title "$title" --notes-file "$NOTES")
if [[ "$KIND" == "rc" ]]; then
@@ -171,8 +170,9 @@ jobs:
gh release create "$tag" "$ARCHIVE" "${flags[@]}" --repo "$GITHUB_REPOSITORY"
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.version.outputs.version }}
KIND: ${{ steps.version.outputs.kind }}
TAG: ${{ steps.release.outputs.tag }}
VERSION: ${{ steps.release.outputs.version }}
KIND: ${{ steps.release.outputs.kind }}
ARCHIVE: ${{ steps.archive.outputs.path }}
NOTES: packages/kilo-jetbrains/build/release-notes.md
@@ -180,6 +180,6 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: kilo-jetbrains-${{ steps.version.outputs.version }}
name: kilo-jetbrains-${{ steps.release.outputs.version }}
path: packages/kilo-jetbrains/build/distributions/*.zip
if-no-files-found: ignore
@@ -1,47 +0,0 @@
# kilocode_change - new file
name: tag-jetbrains-release
on:
pull_request:
types:
- closed
branches:
- main
permissions:
contents: write
pull-requests: read
jobs:
tag:
if: >-
github.repository == 'Kilo-Org/kilocode' &&
github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'jetbrains/release/') &&
contains(github.event.pull_request.labels.*.name, 'jetbrains-release') &&
github.event.pull_request.head.repo.full_name == github.repository
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
fetch-depth: 0
ref: ${{ github.event.pull_request.merge_commit_sha }}
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Setup Git Committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
kilo-maintainer-app-id: ${{ secrets.KILO_MAINTAINER_APP_ID }}
kilo-maintainer-app-secret: ${{ secrets.KILO_MAINTAINER_APP_SECRET }}
- name: Create release tag
run: bun script/jetbrains-release-tag.ts --pr "$PR_NUMBER"
env:
GH_TOKEN: ${{ steps.committer.outputs.token }}
GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
+6 -4
View File
@@ -13,8 +13,8 @@
- Create a JetBrains Marketplace permanent token from Marketplace `My Tokens`.
- Add `JETBRAINS_MARKETPLACE_TOKEN` to GitHub Actions secrets or the protected environment.
- Confirm `GITHUB_TOKEN` has `contents: write` permission for creating and updating GitHub Releases from `jetbrains/v*` tags.
- Confirm `KILO_MAINTAINER_APP_ID` and `KILO_MAINTAINER_APP_SECRET` are available to create release PRs and tags.
- Confirm `GITHUB_TOKEN` has `contents: write` permission for creating and updating GitHub Releases for `jetbrains/v*` tags.
- Confirm `KILO_MAINTAINER_APP_ID` and `KILO_MAINTAINER_APP_SECRET` are available to create release PRs and immediate release tags.
- Optionally create a protected `jetbrains-marketplace` GitHub Environment with required reviewers.
- If using an environment, move the Marketplace and signing secrets there and set the workflow job environment.
@@ -31,8 +31,9 @@
- Choose an RC version in the form `x.y.z-rc.n`.
- Run the `prepare-jetbrains-release` workflow with `kind=rc` and version `x.y.z-rc.n`.
- Confirm the workflow created `jetbrains/vx.y.z-rc.n` immediately at the intended source commit.
- Review and edit `packages/kilo-jetbrains/CHANGELOG.md` in the generated release PR.
- Merge the release PR to create tag `jetbrains/vx.y.z-rc.n`, for example `jetbrains/v7.0.1-rc.1`.
- Merge the release PR to trigger publish from `jetbrains/vx.y.z-rc.n`, for example `jetbrains/v7.0.1-rc.1`.
- Watch the `publish-jetbrains` workflow.
- Download and retain the workflow artifact if needed.
- Confirm the update appears on the JetBrains Marketplace `eap` channel.
@@ -43,8 +44,9 @@
- Choose a stable version in the form `x.y.z`.
- Run the `prepare-jetbrains-release` workflow with `kind=stable` and version `x.y.z`.
- Confirm the workflow created `jetbrains/vx.y.z` immediately at the intended source commit.
- Review and edit `packages/kilo-jetbrains/CHANGELOG.md` in the generated release PR.
- Merge the release PR to create tag `jetbrains/vx.y.z`.
- Merge the release PR to trigger publish from `jetbrains/vx.y.z`.
- Watch the `publish-jetbrains` workflow.
- Confirm the update appears on the default JetBrains Marketplace channel.
- Confirm the GitHub Release for the `jetbrains/vx.y.z` tag exists and contains the JetBrains plugin ZIP asset.
+24 -14
View File
@@ -1,14 +1,16 @@
# Releasing the JetBrains Plugin
JetBrains releases use a release PR. The PR is where maintainers review and edit the version and changelog before anything is published.
JetBrains releases are locked by an immediate `jetbrains/v<version>` tag, then gated by a reviewed release PR. The tag fixes the exact source code that will be published; the PR is where maintainers review and edit the version and changelog before publishing starts.
## Create a Release PR
The published code comes from `jetbrains/v<version>`. Marketplace and GitHub release notes come from the reviewed changelog merged in the release PR.
## Create Release Tag And PR
1. Open the GitHub Actions workflow:
[https://github.com/Kilo-Org/kilocode/actions/workflows/prepare-jetbrains-release.yml](https://github.com/Kilo-Org/kilocode/actions/workflows/prepare-jetbrains-release.yml)
2. Click **Run workflow**.
2. Click **Run workflow**. This immediately creates `jetbrains/v<version>` at the current `origin/main` commit, then creates or updates the release PR.
3. Fill the inputs:
@@ -32,7 +34,7 @@ version=7.3.13
## Changelog Range Defaults
The workflow chooses a changelog base automatically:
The workflow chooses a changelog base automatically and generates notes against the locked release commit:
| Release | Default `from_tag` |
|---|---|
@@ -40,7 +42,7 @@ The workflow chooses a changelog base automatically:
| Later RC, e.g. `7.3.13-rc.2` | Previous RC for the same base version. |
| Stable, e.g. `7.3.13` | Latest stable JetBrains tag, ignoring RCs. |
Use `from_tag` only to override this comparison range.
Use `from_tag` only to override this comparison range. It does not change the release target commit.
For the first stable JetBrains release, there may be no previous stable tag yet. In that case, pass the last RC or another reviewed JetBrains tag as `from_tag`.
@@ -61,15 +63,17 @@ The PR updates:
Review and edit `packages/kilo-jetbrains/CHANGELOG.md` before merging. This changelog entry is rendered into JetBrains `<change-notes>`, so it appears on the Marketplace and inside IntelliJ plugin UI.
The PR can change release metadata such as `packages/kilo-jetbrains/package.json` and `packages/kilo-jetbrains/CHANGELOG.md`, but it does not change the tagged source code that will be built.
## Merge and Publish
When the release PR is merged, the `tag-jetbrains-release` workflow validates it and creates:
When the release PR is merged, the `publish-jetbrains` workflow validates the existing tag and release PR markers:
```text
jetbrains/v<version>
```
That tag triggers the `publish-jetbrains` workflow:
Then it publishes from that tag:
[https://github.com/Kilo-Org/kilocode/actions/workflows/publish-jetbrains.yml](https://github.com/Kilo-Org/kilocode/actions/workflows/publish-jetbrains.yml)
@@ -80,7 +84,7 @@ Publishing behavior:
| `x.y.z-rc.n` | `eap` | Prerelease |
| `x.y.z` | default | Stable release |
The workflow verifies, signs, and publishes the plugin ZIP, then uploads the ZIP to the matching GitHub Release.
The workflow checks out `jetbrains/v<version>` for verification, signing, and Marketplace publishing. It overlays the reviewed `packages/kilo-jetbrains/CHANGELOG.md` from the merged PR before rendering release notes and before `publishPlugin`, so Marketplace metadata and the GitHub Release use the reviewed changelog.
## Installing RC Builds
@@ -98,22 +102,28 @@ https://plugins.jetbrains.com/plugins/list?channel=eap&pluginId=28350
## Manual Recovery
If the PR was merged but the tag workflow failed after validation, create the tag manually at the merge commit:
If the prepare workflow created the tag but failed before creating or updating the PR, rerun the workflow for the same version. It reuses the tag if it still points to the same locked commit.
If publish validation says the tag points to the wrong SHA, stop and inspect manually. Do not move, delete, or recreate release tags casually.
If publish failed after merge, rerun the failed `publish-jetbrains` workflow if the failure happened before Marketplace accepted the version. Marketplace may reject a duplicate version after a successful publish.
If Marketplace publishing succeeded but GitHub Release upload failed, manually create or edit the GitHub Release for the existing tag. Use the reviewed release notes from `packages/kilo-jetbrains/CHANGELOG.md` in the merged release PR.
If the immediate tag must be created manually because the prepare workflow could not push it, create it at the intended locked `origin/main` commit before merging the release PR:
```bash
git fetch origin main
git tag jetbrains/v7.3.13 <merge-sha>
git tag jetbrains/v7.3.13 <locked-main-sha>
git push origin jetbrains/v7.3.13
```
Do not create a tag before the release PR is merged unless intentionally bypassing the release-PR flow.
## Required GitHub Actions Secrets
| Secret | Purpose |
|---|---|
| `KILO_MAINTAINER_APP_ID` | GitHub App ID used to create/update release PRs and tags. |
| `KILO_MAINTAINER_APP_SECRET` | GitHub App private key used to create/update release PRs and tags. |
| `KILO_MAINTAINER_APP_ID` | GitHub App ID used to create/update release PRs and immediate release tags. |
| `KILO_MAINTAINER_APP_SECRET` | GitHub App private key used to create/update release PRs and immediate release tags. |
| `JETBRAINS_MARKETPLACE_TOKEN` | Marketplace API token for publishing. |
| `JETBRAINS_CERTIFICATE_CHAIN` | PEM certificate chain for plugin signing. |
| `JETBRAINS_PRIVATE_KEY` | PEM private key for plugin signing. |
-1
View File
@@ -48,7 +48,6 @@ const active = new Set([
"publish.yml",
"smoke-test.yml",
"source-check-links.yml",
"tag-jetbrains-release.yml",
"test-vscode.yml",
"test.yml",
"triage.yml",
+29 -8
View File
@@ -45,24 +45,28 @@ await $`git fetch origin main --tags`
const tag = `jetbrains/v${ver}`
const branch = `jetbrains/release/v${ver}`
const sha = (await $`git rev-parse origin/main`.text()).trim()
const from = values["from-tag"] ?? (await base(ver, kind))
const notes = await release(from, tag)
const state = await lock(tag, sha, dry)
const notes = await release(from, tag, sha)
const entry = section(ver, notes)
console.log(`JetBrains ${kind} release PR`)
console.log(`version: ${ver}`)
console.log(`base: ${from}`)
console.log(`tag: ${tag}`)
console.log(`commit: ${sha}`)
console.log(`branch: ${branch}`)
console.log(`tag state: ${state}`)
if (dry) {
console.log("\nGenerated changelog entry:\n")
console.log(entry)
console.log("\nDry run complete. No branch, commit, push, or PR was created.")
console.log("\nDry run complete. No tag, branch, commit, push, or PR was created.")
process.exit(0)
}
await $`git checkout -B ${branch} origin/main`
await $`git checkout -B ${branch} ${sha}`
await writepkg(ver)
await writelog(ver, entry)
await $`git add packages/kilo-jetbrains/package.json packages/kilo-jetbrains/CHANGELOG.md`
@@ -72,7 +76,7 @@ if (changed.exitCode !== 0) await $`git commit -m ${`release(jetbrains): v${ver}
await $`git push --force-with-lease origin ${branch}`
const text = body(ver, kind, from, tag, notes)
const text = body(ver, kind, from, tag, sha, notes)
const view = await $`gh pr view ${branch} --repo ${repo} --json number --jq .number`.nothrow()
if (view.exitCode === 0 && view.stdout.toString().trim()) {
const num = view.stdout.toString().trim()
@@ -120,13 +124,29 @@ async function base(ver: string, kind: "rc" | "stable") {
return hit.tag
}
async function release(from: string, tag: string) {
const res = await $`gh api repos/${repo}/releases/generate-notes --method POST -f tag_name=${tag} -f target_commitish=main -f previous_tag_name=${from} --jq .body`
async function lock(tag: string, sha: string, dry: boolean) {
const res = await $`git rev-parse -q --verify ${`refs/tags/${tag}`}`.nothrow()
if (res.exitCode === 0) {
const got = (await $`git rev-list -n 1 ${tag}`.text()).trim()
if (got === sha) return "exists"
throw new Error(`${tag} already exists at ${got}, expected ${sha}`)
}
if (dry) return "would-create"
await $`git tag ${tag} ${sha}`
await $`git push origin ${tag}`
return "created"
}
async function release(from: string, tag: string, sha: string) {
const res = await $`gh api repos/${repo}/releases/generate-notes --method POST -f tag_name=${tag} -f target_commitish=${sha} -f previous_tag_name=${from} --jq .body`
.quiet()
.nothrow()
if (res.exitCode === 0) return res.stdout.toString().trim()
const text = await $`git log --format=%s ${from}..origin/main`.text()
const base = await $`git rev-parse -q --verify ${from}`.nothrow()
if (base.exitCode !== 0) throw new Error(`Previous JetBrains tag not found: ${from}`)
const text = await $`git log --format=%s ${from}..${sha}`.text()
const lines = text
.split(/\r?\n/)
.map((item) => item.trim())
@@ -197,7 +217,7 @@ function regex(ver: string) {
return new RegExp(`\\n?## \\[${safe}\\][\\s\\S]*?(?=\\n## \\[|$)`)
}
function body(ver: string, kind: string, from: string, tag: string, notes: string) {
function body(ver: string, kind: string, from: string, tag: string, sha: string, notes: string) {
return `## Summary
- Prepare JetBrains ${kind} release ${ver}.
- Review and edit \`packages/kilo-jetbrains/CHANGELOG.md\` before merging.
@@ -206,6 +226,7 @@ JetBrains-Version: ${ver}
JetBrains-Kind: ${kind}
JetBrains-From-Tag: ${from}
JetBrains-Tag: ${tag}
JetBrains-Commit: ${sha}
## Generated Notes
${notes || "No notable changes."}
@@ -2,6 +2,7 @@
// kilocode_change - new file
import { $ } from "bun"
import { appendFileSync } from "node:fs"
import semver from "semver"
import { parseArgs } from "util"
@@ -17,7 +18,10 @@ const { values } = parseArgs({
if (values.help) {
console.log(`
Usage: bun script/jetbrains-release-tag.ts --pr <number> [--dry]
Usage: bun script/jetbrains-release-validate.ts --pr <number> [--dry]
Validates a merged JetBrains release PR and the pre-created immutable release tag.
This helper never creates, moves, deletes, or pushes tags.
`)
process.exit(0)
}
@@ -40,11 +44,25 @@ if (!data.headRefName.startsWith("jetbrains/release/")) throw new Error("PR head
if (data.isCrossRepository) throw new Error("JetBrains release PR must come from this repository")
if (!data.mergeCommit?.oid) throw new Error("PR has no merge commit")
const ver = marker(data.body, "JetBrains-Version") ?? data.headRefName.replace(/^jetbrains\/release\/v/, "")
const tag = marker(data.body, "JetBrains-Tag") ?? `jetbrains/v${ver}`
const ver = need(data.body, "JetBrains-Version")
const kind = need(data.body, "JetBrains-Kind")
const tag = need(data.body, "JetBrains-Tag")
const commit = need(data.body, "JetBrains-Commit")
if (!semver.valid(ver)) throw new Error(`Invalid JetBrains version: ${ver}`)
if (kind !== "rc" && kind !== "stable") throw new Error(`Invalid JetBrains kind: ${kind}`)
if (kind === "rc" && !/^\d+\.\d+\.\d+-rc\.\d+$/.test(ver)) throw new Error("RC versions must match x.y.z-rc.n")
if (kind === "stable" && !/^\d+\.\d+\.\d+$/.test(ver)) throw new Error("Stable versions must match x.y.z")
if (tag !== `jetbrains/v${ver}`) throw new Error(`Tag ${tag} does not match version ${ver}`)
if (!/^jetbrains\/v\d+\.\d+\.\d+(-rc\.\d+)?$/.test(tag)) throw new Error(`Invalid JetBrains tag: ${tag}`)
if (!/^[0-9a-f]{40}$/i.test(commit)) throw new Error(`Invalid JetBrains commit: ${commit}`)
await $`git fetch origin --tags`
const existing = await $`git rev-parse -q --verify ${`refs/tags/${tag}`}`.nothrow()
if (existing.exitCode !== 0) throw new Error(`${tag} does not exist`)
const sha = (await $`git rev-list -n 1 ${tag}`.text()).trim()
if (sha !== commit) throw new Error(`${tag} points at ${sha}, expected ${commit}`)
const pkg = await Bun.file("packages/kilo-jetbrains/package.json").json()
if (pkg.version !== ver) throw new Error(`packages/kilo-jetbrains/package.json version is ${pkg.version}, expected ${ver}`)
@@ -52,27 +70,30 @@ if (pkg.version !== ver) throw new Error(`packages/kilo-jetbrains/package.json v
const changelog = await Bun.file("packages/kilo-jetbrains/CHANGELOG.md").text()
if (!changelog.includes(`## [${ver}]`)) throw new Error(`CHANGELOG.md is missing section for ${ver}`)
await $`git fetch origin --tags`
const existing = await $`git rev-parse -q --verify ${`refs/tags/${tag}`}`.nothrow()
if (existing.exitCode === 0) {
const sha = (await $`git rev-list -n 1 ${tag}`.text()).trim()
if (sha === data.mergeCommit.oid) {
console.log(`${tag} already exists at ${sha}`)
process.exit(0)
}
throw new Error(`${tag} already exists at ${sha}, expected ${data.mergeCommit.oid}`)
const marketplace = kind === "rc" ? "eap" : "default"
const cli = kind === "rc" ? "rc" : "latest"
const output = {
version: ver,
kind,
tag,
commit,
merge: data.mergeCommit.oid,
marketplace_channel: marketplace,
cli_channel: cli,
}
console.log(`Creating ${tag} at ${data.mergeCommit.oid}`)
if (values.dry) {
console.log("Dry run complete. No tag was created.")
process.exit(0)
for (const [key, value] of Object.entries(output)) console.log(`${key}=${value}`)
if (process.env.GITHUB_OUTPUT && !values.dry) {
appendFileSync(process.env.GITHUB_OUTPUT, Object.entries(output).map(([key, value]) => `${key}=${value}\n`).join(""))
}
await $`git tag ${tag} ${data.mergeCommit.oid}`
await $`git push origin ${tag}`
function marker(body: string, key: string) {
const line = body.split(/\r?\n/).find((item) => item.startsWith(`${key}:`))
return line?.slice(key.length + 1).trim()
}
function need(body: string, key: string) {
const value = marker(body, key)
if (!value) throw new Error(`PR body is missing ${key}`)
return value
}