diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ec0d9f3..ca7a43a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,3 +75,5 @@ jobs: uses: ./.github/actions/nix-devshell - run: make lint + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4c2e8780..70c4cdc0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,9 @@ name: release on: + push: + branches: + - main release: types: [published] @@ -8,6 +11,7 @@ permissions: {} jobs: build: + name: Build Coder Desktop runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}} if: ${{ github.repository_owner == 'coder' }} permissions: @@ -40,7 +44,34 @@ jobs: run: make release - name: Upload Release Assets - run: gh release upload "$RELEASE_TAG" "$out"/* + run: gh release upload "$RELEASE_TAG" "$out"/* --clobber env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RELEASE_TAG: ${{ github.event.release.tag_name }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event_name == 'release' && github.event.release.tag_name || 'preview' }} + + update-cask: + name: Update homebrew-coder cask + runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}} + if: ${{ github.repository_owner == 'coder' }} + needs: build + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 1 + persist-credentials: false + + - name: Setup Nix + uses: ./.github/actions/nix-devshell + + - name: Update homebrew-coder + env: + GH_TOKEN: ${{ secrets.CODERCI_GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event_name == 'release' && github.event.release.tag_name || 'preview' }} + ASSIGNEE: ${{ github.actor }} + run: | + git config --global user.email "ci@coder.com" + git config --global user.name "Coder CI" + gh auth setup-git + + ./scripts/update-cask.sh --version "$RELEASE_TAG" --assignee "$ASSIGNEE" diff --git a/Makefile b/Makefile index 81fe6723..ee073008 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,12 @@ XCPROJECT := Coder\ Desktop/Coder\ Desktop.xcodeproj SCHEME := Coder\ Desktop SWIFT_VERSION := 6.0 -CURRENT_PROJECT_VERSION=$(shell git describe --tags) +CURRENT_PROJECT_VERSION:=$(shell git describe --match 'v[0-9]*' --dirty='.devel' --always --tags) ifeq ($(strip $(CURRENT_PROJECT_VERSION)),) $(error CURRENT_PROJECT_VERSION cannot be empty) endif -MARKETING_VERSION=$(shell git describe --tags --abbrev=0 | sed 's/^v//' | sed 's/-.*$$//') +MARKETING_VERSION:=$(shell git describe --match 'v[0-9]*' --tags --abbrev=0 | sed 's/^v//' | sed 's/-.*$$//') ifeq ($(strip $(MARKETING_VERSION)),) $(error MARKETING_VERSION cannot be empty) endif @@ -132,3 +132,5 @@ help: ## Show this help .PHONY: watch-gen watch-gen: ## Generate Xcode project file and watch for changes watchexec -w 'Coder Desktop/project.yml' make $(XCPROJECT) + +print-%: ; @echo $*=$($*) diff --git a/scripts/update-cask.sh b/scripts/update-cask.sh new file mode 100755 index 00000000..01f25827 --- /dev/null +++ b/scripts/update-cask.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + echo "Usage: $0 [--version ] [--assignee ]" + echo " --version Set the VERSION variable to fetch and generate the cask file for" + echo " --assignee Set the ASSIGNE variable to assign the PR to (optional)" + echo " -h, --help Display this help message" +} + +VERSION="" +ASSIGNE="" + +# Parse command line arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --version) + VERSION="$2" + shift 2 + ;; + --assignee) + ASSIGNE="$2" + shift 2 + ;; + -h | --help) + usage + exit 0 + ;; + *) + echo "Unknown parameter passed: $1" + usage + exit 1 + ;; + esac +done + +# Assert version is not empty and starts with v +[ -z "$VERSION" ] && { + echo "Error: VERSION cannot be empty" + exit 1 +} +[[ "$VERSION" =~ ^v || "$VERSION" == "preview" ]] || { + echo "Error: VERSION must start with a 'v'" + exit 1 +} + +# Download the Coder Desktop dmg +GH_RELEASE_FOLDER=$(mktemp -d) + +gh release download "$VERSION" \ + --repo coder/coder-desktop-macos \ + --dir "$GH_RELEASE_FOLDER" \ + --pattern 'Coder.Desktop.dmg' + +HASH=$(shasum -a 256 "$GH_RELEASE_FOLDER"/Coder.Desktop.dmg | awk '{print $1}' | tr -d '\n') + +IS_PREVIEW=false +if [[ "$VERSION" == "preview" ]]; then + IS_PREVIEW=true + VERSION=$(make 'print-CURRENT_PROJECT_VERSION' | sed 's/CURRENT_PROJECT_VERSION=//g') +fi + +# Check out the homebrew tap repo +TAP_CHECHOUT_FOLDER=$(mktemp -d) + +gh repo clone "coder/homebrew-coder" "$TAP_CHECHOUT_FOLDER" + +cd "$TAP_CHECHOUT_FOLDER" + +BREW_BRANCH="auto-release/desktop-$VERSION" + +# Check if a PR already exists. +# Continue on a main branch release, as the sha256 will change. +pr_count="$(gh pr list --search "head:$BREW_BRANCH" --json id,closed | jq -r ".[] | select(.closed == false) | .id" | wc -l)" +if [[ "$pr_count" -gt 0 && "$IS_PREVIEW" == false ]]; then + echo "Bailing out as PR already exists" 2>&1 + exit 0 +fi + +git checkout -b "$BREW_BRANCH" + +# If this is a main branch build, append a preview suffix to the cask. +SUFFIX="" +CONFLICTS_WITH="coder-desktop-preview" +TAG=$VERSION +if [[ "$IS_PREVIEW" == true ]]; then + SUFFIX="-preview" + CONFLICTS_WITH="coder-desktop" + TAG="preview" +fi + +mkdir -p "$TAP_CHECHOUT_FOLDER"/Casks + +# Overwrite the cask file +cat >"$TAP_CHECHOUT_FOLDER"/Casks/coder-desktop${SUFFIX}.rb <= :sonoma" + + app "Coder Desktop.app" + conflicts_with cask: "coder/coder/${CONFLICTS_WITH}" +end +EOF + +git add . +git commit -m "Coder Desktop $VERSION" +git push -u origin -f "$BREW_BRANCH" + +# Create a PR only if none exists +if [[ "$pr_count" -eq 0 ]]; then + gh pr create \ + --base master --head "$BREW_BRANCH" \ + --title "Coder Desktop $VERSION" \ + --body "This automatic PR was triggered by the release of Coder Desktop $VERSION" \ + ${ASSIGNE:+ --assignee "$ASSIGNE" --reviewer "$ASSIGNE"} +fi