diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml index 0eecad57..c8e994ed 100644 --- a/.github/workflows/danger.yml +++ b/.github/workflows/danger.yml @@ -8,7 +8,7 @@ on: branches: [main] jobs: danger: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/release-published.yml b/.github/workflows/release-published.yml index 807f0bb7..1997a1cb 100644 --- a/.github/workflows/release-published.yml +++ b/.github/workflows/release-published.yml @@ -15,18 +15,37 @@ jobs: if: ${{!github.event.repository.fork}} runs-on: macos-15 steps: + - name: 🛒 Checkout repo + env: + GIT_CONFIG_COUNT: 1 + GIT_CONFIG_KEY_0: init.defaultBranch + GIT_CONFIG_VALUE_0: ${{github.event.repository.default_branch}} + uses: actions/checkout@v4 + - name: 🚰 Apply pr-pull label to custom tap formula bump PR env: - GH_TOKEN: ${{secrets.HOMEBREW_GITHUB_API_TOKEN}} + TOKEN_APP_ID: ${{secrets.TOKEN_APP_ID}} + TOKEN_APP_INSTALLATION_ID: ${{secrets.TOKEN_APP_INSTALLATION_ID}} + TOKEN_APP_PRIVATE_KEY: ${{secrets.TOKEN_APP_PRIVATE_KEY}} run: | - gh release -R "${GITHUB_REPOSITORY}" download "${GITHUB_REF_NAME}" -p bump.url - gh pr edit "$(/dev/null)" + found_bump_url="${?}" + setopt errexit + + if [[ "${found_bump_url}" -eq 0 ]]; then + [[ -n "${bump_url}" ]] && gh pr edit "${bump_url}" --add-label pr-pull + gh release -R "${GITHUB_REPOSITORY}" delete-asset "${GITHUB_REF_NAME}" bump.url -y + else + printf $'No custom tap formula bump PR URL found for tag\'%s\'\n' "${GITHUB_REF_NAME}" + fi - name: 🍺 Bump homebrew-core formula if: ${{!github.event.release.prerelease}} env: - HOMEBREW_GITHUB_API_TOKEN: ${{secrets.HOMEBREW_GITHUB_API_TOKEN}} + HOMEBREW_GITHUB_API_TOKEN: ${{github.token}} run: | brew bump-formula-pr\ --tag "${GITHUB_REF_NAME}"\ diff --git a/.github/workflows/tag-pushed.yml b/.github/workflows/tag-pushed.yml index d67640ac..d6f26aff 100644 --- a/.github/workflows/tag-pushed.yml +++ b/.github/workflows/tag-pushed.yml @@ -14,8 +14,6 @@ jobs: tag-pushed: if: ${{!github.event.repository.fork}} runs-on: macos-15 - permissions: - contents: write steps: - name: 🛒 Checkout repo env: @@ -56,13 +54,19 @@ jobs: - name: 📦 Build universal executable & package it in an installer run: | + sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer script/package - name: 🚰 Bump custom tap formula env: - HOMEBREW_GITHUB_API_TOKEN: ${{secrets.HOMEBREW_GITHUB_API_TOKEN}} + TOKEN_APP_ID: ${{secrets.TOKEN_APP_ID}} + TOKEN_APP_INSTALLATION_ID: ${{secrets.TOKEN_APP_INSTALLATION_ID}} + TOKEN_APP_PRIVATE_KEY: ${{secrets.TOKEN_APP_PRIVATE_KEY}} run: | + export HOMEBREW_GITHUB_API_TOKEN="$(script/generate_token)" + brew tap "${GITHUB_REPOSITORY_OWNER}/tap" + unsetopt errexit bump_output="$(brew bump-formula-pr\ --tag "${GITHUB_REF_NAME}"\ @@ -76,8 +80,10 @@ jobs: 2>&1)" exit_code="${?}" setopt errexit + printf %s "${bump_output}" printf %s "${${(f)bump_output}[-1]}" > .build/bump.url + exit "${exit_code}" - name: 📝 Create draft release @@ -89,6 +95,6 @@ jobs: ".build/mas-${GITHUB_REF_NAME#v}.pkg"\ .build/bump.url\ -d\ + ${"${GITHUB_REF_NAME//[^-]}":+-p}\ -t "${GITHUB_REF_NAME}: ${$(git tag -l "${GITHUB_REF_NAME}" --format='%(contents)')%%$'\n'*}"\ - --generate-notes\ - ${"${GITHUB_REF_NAME//[^-]/}":+ -p} + --generate-notes diff --git a/script/generate_token b/script/generate_token new file mode 100755 index 00000000..696b2ae0 --- /dev/null +++ b/script/generate_token @@ -0,0 +1,23 @@ +#!/bin/zsh -Ndefgku +# +# script/generate_token +# mas +# +# Generates a GitHub App installation access token for GitHub Workflows. +# + +. "${0:a:h}/_setup_script" + +header=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9 +payload="${${$(printf '{"iss":%s,"iat":%s,"exp":%s}' "${TOKEN_APP_ID}" "$(("$(date +%s)" - 60))"\ + "$(("$(date +%s)" + 540))" | base64)//[=$'\n']}//\/+/_-}" + + +# shellcheck disable=SC1009,SC1036,SC1072,SC1073 +curl\ + -sX POST\ + -H "Authorization: Bearer ${header}.${payload}.${${$(printf %s "${header}.${payload}" | + openssl dgst -sha256 -sign =(printf %s "${TOKEN_APP_PRIVATE_KEY}") | base64)//[=$'\n']}//\/+/_-}"\ + -H 'Accept: application/vnd.github+json'\ + "https://api.github.com/app/installations/${TOKEN_APP_INSTALLATION_ID}/access_tokens" | + jq -r .token diff --git a/script/release_cancel b/script/release_cancel new file mode 100755 index 00000000..11246ee4 --- /dev/null +++ b/script/release_cancel @@ -0,0 +1,25 @@ +#!/bin/zsh -Ndefgku +# +# script/release_cancel +# mas +# +# Cancel a GitHub draft release. +# +# Usage: release_cancel +# + +. "${0:a:h}/_setup_script" + +tag="${1}" + +printf $'==> 🚀 Canceling release for tag %s\n\n' "${tag}" + +bump_url="$(gh release -R https://github.com/mas-cli/mas download "${tag}" -p bump.url -O - 2>/dev/null || true)" +if [[ -n "${bump_url}" ]]; then + gh pr close "${bump_url}" -d + printf $'\n' +else + printf $'No custom tap formula bump PR URL found for draft release tag \'%s\'\n\n' "${tag}" +fi + +gh release -R https://github.com/mas-cli/mas delete "${tag}" --cleanup-tag -y diff --git a/script/release_start b/script/release_start new file mode 100755 index 00000000..2e0bfb30 --- /dev/null +++ b/script/release_start @@ -0,0 +1,57 @@ +#!/bin/zsh -Ndefgku +# +# script/release_start +# mas +# +# Start the release process by creating & pushing a signed annotated version tag to the GitHub mas-cli/mas repo. +# +# Usage: release_start [] +# +# must match the following zsh pattern: +# +# ^v[[:digit:]]+(\.[[:digit:]]+)*(-(alpha|beta|rc)\.[[:digit:]]+)?$ +# +# must may contain at most 64 characters, which may be only visible characters or spaces +# +# if optional value supplied, must be on the main branch; defaults to HEAD +# + +. "${0:a:h}/_setup_script" + +tag="${1}" +title="${2}" +ref="${3:-HEAD}" + +printf $'==> 🚀 Starting release for mas %s\n\n' "${tag#v}" + +if [[ ! "${tag}" =~ '^v[[:digit:]]+(\.[[:digit:]]+)*(-(alpha|beta|rc)\.[[:digit:]]+)?$' ]]; then + printf $'\'%s\' is not a valid version tag\n' "${tag}" >&2 + exit 1 +fi + +if [[ "${#title}" -gt 64 ]]; then + printf $'\'%s\' is too long for a version title, which may contain at most 64 characters\n' "${title}" >&2 + exit 2 +fi + +if [[ "${title}" =~ [[:cntrl:]$'\t\n\r'] ]]; then + printf $'\'%s\' is not a valid version title, which may contain only visible characters or spaces\n' "${title}" >&2 + exit 3 +fi + +# shellcheck disable=SC1009,SC1027,SC1036,SC1072,SC1073 +if [[ "${title}" = (' '*|*' ') ]]; then + printf $'\'%s\' is not a valid version title, which may not begin or end with a space\n' "${title}" >&2 + exit 4 +fi + +if ! git merge-base --is-ancestor "${ref}" upstream/main; then + printf $'\'%s\' is not a valid reference for a version, which must be on the upstream/main branch\n' "${ref}" >&2 + exit 5 +fi + +git tag -s "${tag}" -m "${title}" "${ref}" + +printf $'Created version tag \'%s\' with title \'%s\' for \'%s\'\n\n' "${tag}" "${title}" "${ref}" + +git push upstream tag "${tag}"