diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 20f412b..5f279ad 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -162,3 +162,77 @@ jobs: target_commitish: ${{ github.sha }} files: | *.AppImage* + + create_release_pr: + name: "👻 Upstream Stable Release" + if: ${{ github.event_name == 'schedule' && github.ref_name == 'main' }} + permissions: + contents: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 # zizmor: ignore[artipacked] + with: + fetch-depth: 0 + + - name: Detect upstream stable release + id: detect + run: | + set -eu + if version="$(./bin/check-upstream-release.sh)"; then + echo "New upstream stable release: ${version}" + echo "release=true" >> "${GITHUB_OUTPUT}" + echo "version=${version}" >> "${GITHUB_OUTPUT}" + else + echo "No new upstream stable release" + echo "release=false" >> "${GITHUB_OUTPUT}" + fi + + - name: Push release branch and tag + if: ${{ steps.detect.outputs.release == 'true' }} + env: + VERSION: ${{ steps.detect.outputs.version }} + run: | + set -eux + branch="release/${VERSION}" + tag="v${VERSION}" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + if git ls-remote --exit-code --heads origin "${branch}" >/dev/null 2>&1; then + git checkout -B "${branch}" "origin/${branch}" + else + git checkout -b "${branch}" + printf '%s\n' "${VERSION}" > VERSION + git add VERSION + git commit -m "chore(release): set VERSION to ${VERSION}" + git push origin "${branch}" + fi + + if ! git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then + git tag -a "${tag}" -m "Ghostty ${VERSION}" + git push origin "${tag}" + fi + + - name: Open release pull request + if: ${{ steps.detect.outputs.release == 'true' }} + env: + GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.detect.outputs.version }} + run: | + set -eux + branch="release/${VERSION}" + if [ -n "$(gh pr list --head "${branch}" --state open --json number --jq '.[0].number')" ]; then + echo "Open pull request for ${branch} already exists" + exit 0 + fi + gh pr create \ + --base main \ + --head "${branch}" \ + --title "👻 Release Ghostty ${VERSION}" \ + --body "Automated release PR for upstream Ghostty \`${VERSION}\`. + + - Updates \`VERSION\` to \`${VERSION}\` + - Adds tag \`v${VERSION}\` + + Upstream tag: https://github.com/ghostty-org/ghostty/releases/tag/v${VERSION}" diff --git a/bin/check-upstream-release.sh b/bin/check-upstream-release.sh new file mode 100755 index 0000000..d6e3f8e --- /dev/null +++ b/bin/check-upstream-release.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +set -eux + +UPSTREAM_REPO="${UPSTREAM_REPO:-ghostty-org/ghostty}" +RELEASE_BASE_URL="${RELEASE_BASE_URL:-https://release.files.ghostty.org}" + +get_latest_stable_tag() { + git ls-remote --tags --refs "https://github.com/${UPSTREAM_REPO}.git" | + sed 's#.*refs/tags/##' | + grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | + sed 's/^v//' | + sort -V | + tail -n1 +} + +release_artifact_exists() { + curl -fsI "${RELEASE_BASE_URL}/${1}/ghostty-${1}.tar.gz" >/dev/null 2>&1 +} + +current="$(cat VERSION)" +latest="$(get_latest_stable_tag)" + +if [ -z "${latest}" ]; then + echo "No upstream stable release found" >&2 + exit 1 +fi + +if ! release_artifact_exists "${latest}"; then + echo "Upstream ${latest} has no published release artifact yet" >&2 + exit 1 +fi + +if [ "${latest}" = "${current}" ]; then + echo "Already on latest upstream release ${current}" >&2 + exit 1 +fi + +newest="$(printf '%s\n%s\n' "${current}" "${latest}" | sort -V | tail -n1)" +if [ "${newest}" != "${latest}" ]; then + echo "Current version ${current} is newer than upstream ${latest}" >&2 + exit 1 +fi + +echo "${latest}"