diff --git a/.github/workflows/promote-release.yml b/.github/workflows/promote-release.yml new file mode 100644 index 00000000..670cdf9b --- /dev/null +++ b/.github/workflows/promote-release.yml @@ -0,0 +1,110 @@ +name: Promote release + +on: + workflow_dispatch: + inputs: + tag: + description: GitHub release tag (v1.2.3) + required: true + type: string + dry_run: + description: Print formula changes without opening a tap PR + required: false + type: boolean + default: false + +permissions: + contents: read + +jobs: + homebrew: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "20" + - name: Resolve tag and download macOS CLI zip + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ inputs.tag }} + run: | + set -euo pipefail + VERSION=$(node --input-type=module -e "import { parseTag } from './scripts/promote/homebrew.mjs'; console.log(parseTag(process.env.TAG));") + ASSET=$(VERSION="$VERSION" node --input-type=module -e "import { assetName } from './scripts/promote/homebrew.mjs'; console.log(assetName(process.env.VERSION));") + gh release view "$TAG" --json assets --jq '.assets[].name' | grep -Fx "$ASSET" + gh release download "$TAG" --pattern "$ASSET" + unzip -Z1 "$ASSET" | grep -Fx 'bin/dw' + SHA=$(sha256sum "$ASSET" | awk '{print $1}') + { + echo "VERSION=$VERSION" + echo "ASSET=$ASSET" + echo "SHA=$SHA" + } >> "$GITHUB_ENV" + - name: Checkout tap + uses: actions/checkout@v4 + with: + repository: mulesoft/homebrew-data-weave + token: ${{ secrets.HOMEBREW_TAP_TOKEN }} + path: tap + - name: Rewrite formula + id: formula + env: + TAG: ${{ inputs.tag }} + SHA: ${{ env.SHA }} + run: | + set -euo pipefail + node --input-type=module <<'EOF' + import { appendFileSync, readFileSync, writeFileSync } from "node:fs"; + import { + alreadyPromoted, + parseTag, + releaseAssetUrl, + rewriteFormula, + } from "./scripts/promote/homebrew.mjs"; + + const tag = process.env.TAG; + const version = parseTag(tag); + const formulaPath = "tap/formula/dw.rb"; + const formula = readFileSync(formulaPath, "utf8"); + + if (alreadyPromoted(formula, version)) { + console.log(`already promoted: ${version}`); + appendFileSync(process.env.GITHUB_OUTPUT, "skipped=true\n"); + process.exit(0); + } + + const next = rewriteFormula(formula, { + url: releaseAssetUrl("mulesoft/data-weave-cli", tag, version), + sha256: process.env.SHA, + version, + }); + writeFileSync(formulaPath, next); + console.log(next); + appendFileSync(process.env.GITHUB_OUTPUT, "skipped=false\n"); + EOF + - name: Open tap pull request + if: steps.formula.outputs.skipped == 'false' && inputs.dry_run == false + env: + GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + TAG: ${{ inputs.tag }} + VERSION: ${{ env.VERSION }} + ASSET: ${{ env.ASSET }} + SHA: ${{ env.SHA }} + working-directory: tap + run: | + set -euo pipefail + BRANCH="promote-dw-${VERSION}" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git checkout -B "$BRANCH" + git add formula/dw.rb + git commit -m "chore: promote dw ${VERSION}" + git push -u origin "$BRANCH" --force + if gh pr list --repo mulesoft/homebrew-data-weave --head "$BRANCH" --json number --jq '.[0].number' | grep -q .; then + echo "PR already open" + else + gh pr create --repo mulesoft/homebrew-data-weave --base master --head "$BRANCH" \ + --title "Promote dw ${VERSION}" \ + --body "From ${TAG} asset ${ASSET} sha256 ${SHA}" + fi diff --git a/scripts/promote/homebrew.mjs b/scripts/promote/homebrew.mjs new file mode 100644 index 00000000..f95e6f4a --- /dev/null +++ b/scripts/promote/homebrew.mjs @@ -0,0 +1,39 @@ +export function parseTag(tag) { + if (!/^v[0-9]/.test(tag)) { + throw new Error(`Expected a version tag beginning with v and a digit: ${tag}`); + } + + return tag.slice(1); +} + +export function assetName(version) { + return `dw-cli-${version}-macos-arm64.zip`; +} + +export function releaseAssetUrl(repo, tag, version) { + return `https://github.com/${repo}/releases/download/${tag}/${assetName(version)}`; +} + +export function parseFormulaVersion(formula) { + return formula.match(/^\s*version "([^"]+)"/m)?.[1]; +} + +export function rewriteFormula(formula, { url, sha256, version, homepage }) { + let rewritten = formula + .replace(/^(\s*url) "[^"]+"/m, `$1 "${url}"`) + .replace(/^(\s*sha256) "[^"]+"/m, `$1 "${sha256}"`) + .replace(/^(\s*version) "[^"]+"/m, `$1 "${version}"`); + + if (rewritten.match(/^\s*homepage "[^"]*mulesoft-labs\/data-weave-cli[^"]*"/m)) { + rewritten = rewritten.replace( + /^(\s*homepage) "[^"]+"/m, + `$1 "${homepage ?? "https://github.com/mulesoft/data-weave-cli"}"`, + ); + } + + return rewritten; +} + +export function alreadyPromoted(formula, version) { + return parseFormulaVersion(formula) === version; +}