From 637cddee70bbfe0105336ba690721c08be07b890 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 12 Jan 2026 19:06:37 +0000 Subject: [PATCH 1/6] fix(action): Simplify install by using build artifact with release fallback The github context is not available when the `uses:` field is evaluated, so we can't use dynamic action references. Instead, inline the install logic into action.yml: - For dogfooding (getsentry/craft): Download from build artifact if available - For all repos (or if artifact unavailable): Download from release using github.action_ref, with fallback to latest This removes the install/ sub-action and all the duplicate Node.js/pnpm build-from-source logic, keeping the flow simple while still enabling dogfooding via the build job's artifact. --- action.yml | 42 ++++++++++++++++++----- install/action.yml | 83 ---------------------------------------------- 2 files changed, 34 insertions(+), 91 deletions(-) delete mode 100644 install/action.yml diff --git a/action.yml b/action.yml index 9e1c4b48..8b039120 100644 --- a/action.yml +++ b/action.yml @@ -83,16 +83,42 @@ runs: echo "GIT_AUTHOR_NAME=${GIT_USER_NAME}" >> $GITHUB_ENV echo "EMAIL=${GIT_USER_EMAIL}" >> $GITHUB_ENV - # For dogfooding (Craft releasing itself) - local path works because - # the checkout is in the Craft repo, so ./install resolves correctly - - name: Install Craft (local) + # === Install Craft === + # For dogfooding (getsentry/craft): try build artifact from build job + # For all repos (or if artifact unavailable): download from release + + - name: Download Craft from build artifact if: github.repository == 'getsentry/craft' - uses: ./install + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 + continue-on-error: true + with: + name: ${{ github.sha }} + path: /tmp/craft-artifact - # For external repos - use fully-qualified reference with action ref - - name: Install Craft - if: github.repository != 'getsentry/craft' - uses: getsentry/craft/install@${{ github.action_ref }} + - name: Install Craft from artifact or release + shell: bash + run: | + if [[ -f /tmp/craft-artifact/dist/craft ]]; then + echo "Installing Craft from build artifact..." + sudo install -m 755 /tmp/craft-artifact/dist/craft /usr/local/bin/craft + else + # Download from release (for external repos or if artifact unavailable) + ACTION_REF="${{ github.action_ref }}" + CRAFT_URL="https://github.com/getsentry/craft/releases/download/${ACTION_REF}/craft" + + echo "Downloading Craft from: ${CRAFT_URL}" + + # Fallback to latest if ref doesn't have a release + if ! curl -sfI "$CRAFT_URL" >/dev/null 2>&1; then + echo "Release not found for ref '${ACTION_REF}', falling back to latest..." + CRAFT_URL=$(curl -s "https://api.github.com/repos/getsentry/craft/releases/latest" \ + | jq -r '.assets[] | select(.name == "craft") | .browser_download_url') + fi + + echo "Installing Craft from: ${CRAFT_URL}" + sudo curl -sL -o /usr/local/bin/craft "$CRAFT_URL" + sudo chmod +x /usr/local/bin/craft + fi - name: Craft Prepare id: craft diff --git a/install/action.yml b/install/action.yml deleted file mode 100644 index 4ecd7f0e..00000000 --- a/install/action.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: "Install Craft" -description: "Install Craft CLI (from build artifact for dogfooding, build from source, or from release)" - -inputs: - craft-version: - description: 'Version of Craft to install (tag or "latest"). Only used when installing from release.' - required: false - default: 'latest' - -runs: - using: "composite" - steps: - - name: Download Craft from build artifact - id: artifact - if: github.repository == 'getsentry/craft' - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 - continue-on-error: true - with: - name: ${{ github.sha }} - path: /tmp/craft-artifact - - - name: Install Craft from artifact - if: steps.artifact.outcome == 'success' - shell: bash - run: | - echo "Installing Craft from build artifact..." - sudo install -m 755 /tmp/craft-artifact/dist/craft /usr/local/bin/craft - - # For getsentry/craft repo: build from source if no artifact available - - name: Setup Node.js (for building from source) - if: github.repository == 'getsentry/craft' && steps.artifact.outcome != 'success' - uses: actions/setup-node@v4 - with: - node-version: '22' - - - name: Get pnpm version from Volta config - if: github.repository == 'getsentry/craft' && steps.artifact.outcome != 'success' - id: pnpm-version - shell: bash - run: echo "version=$(jq -r '.volta.pnpm' package.json)" >> $GITHUB_OUTPUT - - - name: Setup pnpm - if: github.repository == 'getsentry/craft' && steps.artifact.outcome != 'success' - uses: pnpm/action-setup@v4 - with: - version: ${{ steps.pnpm-version.outputs.version }} - - - name: Build Craft from source - id: build - if: github.repository == 'getsentry/craft' && steps.artifact.outcome != 'success' - shell: bash - run: | - echo "Building Craft from source..." - pnpm install --frozen-lockfile - pnpm build - sudo install -m 755 dist/craft /usr/local/bin/craft - - - name: Install Craft from release - if: steps.artifact.outcome != 'success' && steps.build.outcome != 'success' - shell: bash - env: - CRAFT_VERSION: ${{ inputs.craft-version }} - run: | - if [[ "$CRAFT_VERSION" == "latest" || -z "$CRAFT_VERSION" ]]; then - # Try action ref first (e.g., v2, 2.15.0) - ACTION_REF="${{ github.action_ref }}" - CRAFT_URL="https://github.com/getsentry/craft/releases/download/${ACTION_REF}/craft" - - echo "Trying to download Craft from: ${CRAFT_URL}" - - # Fallback to latest if ref doesn't have a release - if ! curl -sfI "$CRAFT_URL" >/dev/null 2>&1; then - echo "Release not found for ref '${ACTION_REF}', falling back to latest..." - CRAFT_URL=$(curl -s "https://api.github.com/repos/getsentry/craft/releases/latest" \ - | jq -r '.assets[] | select(.name == "craft") | .browser_download_url') - fi - else - CRAFT_URL="https://github.com/getsentry/craft/releases/download/${CRAFT_VERSION}/craft" - fi - - echo "Installing Craft from: ${CRAFT_URL}" - sudo curl -sL -o /usr/local/bin/craft "$CRAFT_URL" - sudo chmod +x /usr/local/bin/craft From 7abc9196a0814f5f911f69e204c8c455a6410fbf Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 12 Jan 2026 19:34:44 +0000 Subject: [PATCH 2/6] fix(action): Remove continue-on-error for artifact download In the getsentry/craft repo, the build artifact should always be available from the build job. If the download fails, that's a real error we should surface rather than silently falling back to the release binary. --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 8b039120..d550107a 100644 --- a/action.yml +++ b/action.yml @@ -88,9 +88,9 @@ runs: # For all repos (or if artifact unavailable): download from release - name: Download Craft from build artifact + id: craft-artifact if: github.repository == 'getsentry/craft' uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 - continue-on-error: true with: name: ${{ github.sha }} path: /tmp/craft-artifact From d5ff6f6698a2dc9eccb89c41b034dbc6acd71988 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 12 Jan 2026 19:58:35 +0000 Subject: [PATCH 3/6] fix(action): Add craft_version input for reliable version pinning Add explicit craft_version input as the primary source for determining which Craft version to install, with github.action_ref as a fallback. This ensures reliable version pinning for external repos even if github.action_ref is empty or unavailable in certain contexts. The install logic now: 1. Use craft_version input if provided 2. Fall back to github.action_ref if not 3. If both are empty or "latest", download latest release 4. Otherwise download the specified version with fallback to latest if not found --- action.yml | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/action.yml b/action.yml index d550107a..8fd79664 100644 --- a/action.yml +++ b/action.yml @@ -35,6 +35,12 @@ inputs: description: Use the craft config from the merge target branch required: false default: "false" + craft_version: + description: > + Version of Craft to install (tag or "latest"). + Defaults to the action ref (e.g., "v2") if not specified. + required: false + default: "" outputs: version: @@ -103,16 +109,26 @@ runs: sudo install -m 755 /tmp/craft-artifact/dist/craft /usr/local/bin/craft else # Download from release (for external repos or if artifact unavailable) - ACTION_REF="${{ github.action_ref }}" - CRAFT_URL="https://github.com/getsentry/craft/releases/download/${ACTION_REF}/craft" - - echo "Downloading Craft from: ${CRAFT_URL}" + # Use explicit craft_version input if provided, otherwise fall back to github.action_ref + CRAFT_VERSION="${{ inputs.craft_version }}" + if [[ -z "$CRAFT_VERSION" ]]; then + CRAFT_VERSION="${{ github.action_ref }}" + fi - # Fallback to latest if ref doesn't have a release - if ! curl -sfI "$CRAFT_URL" >/dev/null 2>&1; then - echo "Release not found for ref '${ACTION_REF}', falling back to latest..." + if [[ "$CRAFT_VERSION" == "latest" || -z "$CRAFT_VERSION" ]]; then + echo "Downloading latest Craft release..." CRAFT_URL=$(curl -s "https://api.github.com/repos/getsentry/craft/releases/latest" \ | jq -r '.assets[] | select(.name == "craft") | .browser_download_url') + else + CRAFT_URL="https://github.com/getsentry/craft/releases/download/${CRAFT_VERSION}/craft" + echo "Downloading Craft ${CRAFT_VERSION} from: ${CRAFT_URL}" + + # Fallback to latest if specified version doesn't have a release + if ! curl -sfI "$CRAFT_URL" >/dev/null 2>&1; then + echo "Release not found for version '${CRAFT_VERSION}', falling back to latest..." + CRAFT_URL=$(curl -s "https://api.github.com/repos/getsentry/craft/releases/latest" \ + | jq -r '.assets[] | select(.name == "craft") | .browser_download_url') + fi fi echo "Installing Craft from: ${CRAFT_URL}" From ae7ae99ee979e7601ebfa713ff3fec1a1dd69262 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 12 Jan 2026 19:59:57 +0000 Subject: [PATCH 4/6] fix(action): Restore continue-on-error for artifact download The merge-artifacts job in build.yml only runs if both build and docs jobs succeed. If docs fails, merge-artifacts is skipped and the artifact won't exist. Without continue-on-error, the download would fail and break the release workflow. Restoring continue-on-error allows graceful fallback to downloading from release if the artifact doesn't exist for any reason. --- action.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 8fd79664..16c576c4 100644 --- a/action.yml +++ b/action.yml @@ -37,7 +37,7 @@ inputs: default: "false" craft_version: description: > - Version of Craft to install (tag or "latest"). + Version of Craft to install (tag or "latest"). Defaults to the action ref (e.g., "v2") if not specified. required: false default: "" @@ -97,6 +97,7 @@ runs: id: craft-artifact if: github.repository == 'getsentry/craft' uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 + continue-on-error: true with: name: ${{ github.sha }} path: /tmp/craft-artifact From 4bf74353f2d788119a49ae6c6398a1bbe1e48fc5 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 12 Jan 2026 20:05:26 +0000 Subject: [PATCH 5/6] fix(action): Remove continue-on-error to fail fast on missing artifact Since docs should block releases, if the docs job fails, merge-artifacts won't run and the artifact won't exist. Without continue-on-error, the artifact download will fail, properly propagating the failure. This ensures the release workflow fails fast if any required build step (including docs) fails, rather than silently falling back to downloading from release. Also adds if-no-files-found: ignore to the merge-artifacts upload step to handle the gh-pages.zip file that may not exist. --- .github/workflows/build.yml | 1 + action.yml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aa2e3908..69145582 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,3 +143,4 @@ jobs: ${{ github.workspace }}/*.tgz ${{ github.workspace }}/dist/craft ${{ github.workspace }}/gh-pages.zip + if-no-files-found: ignore diff --git a/action.yml b/action.yml index 16c576c4..6fc69bf0 100644 --- a/action.yml +++ b/action.yml @@ -97,7 +97,6 @@ runs: id: craft-artifact if: github.repository == 'getsentry/craft' uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 - continue-on-error: true with: name: ${{ github.sha }} path: /tmp/craft-artifact From 8fce847eb595188c21c46be04d2760e9d48906c7 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 12 Jan 2026 20:06:29 +0000 Subject: [PATCH 6/6] fix(action): Add robust error handling for Craft installation Add comprehensive error handling to prevent silent failures: 1. Use 'set -euo pipefail' to fail fast on any error 2. Change curl flags from -s to -fsSL (fail on HTTP errors) 3. Verify CRAFT_URL is not empty before downloading 4. Verify downloaded binary is not empty after download 5. Use GitHub Actions error annotations (::error::) for clear failures This prevents scenarios where: - GitHub API fails/rate limits - Network issues occur - Release asset is missing - Binary download fails but script continues All these cases now fail fast with clear error messages. --- action.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/action.yml b/action.yml index 6fc69bf0..1e1457f2 100644 --- a/action.yml +++ b/action.yml @@ -104,6 +104,8 @@ runs: - name: Install Craft from artifact or release shell: bash run: | + set -euo pipefail + if [[ -f /tmp/craft-artifact/dist/craft ]]; then echo "Installing Craft from build artifact..." sudo install -m 755 /tmp/craft-artifact/dist/craft /usr/local/bin/craft @@ -117,7 +119,7 @@ runs: if [[ "$CRAFT_VERSION" == "latest" || -z "$CRAFT_VERSION" ]]; then echo "Downloading latest Craft release..." - CRAFT_URL=$(curl -s "https://api.github.com/repos/getsentry/craft/releases/latest" \ + CRAFT_URL=$(curl -fsSL "https://api.github.com/repos/getsentry/craft/releases/latest" \ | jq -r '.assets[] | select(.name == "craft") | .browser_download_url') else CRAFT_URL="https://github.com/getsentry/craft/releases/download/${CRAFT_VERSION}/craft" @@ -126,14 +128,26 @@ runs: # Fallback to latest if specified version doesn't have a release if ! curl -sfI "$CRAFT_URL" >/dev/null 2>&1; then echo "Release not found for version '${CRAFT_VERSION}', falling back to latest..." - CRAFT_URL=$(curl -s "https://api.github.com/repos/getsentry/craft/releases/latest" \ + CRAFT_URL=$(curl -fsSL "https://api.github.com/repos/getsentry/craft/releases/latest" \ | jq -r '.assets[] | select(.name == "craft") | .browser_download_url') fi fi + # Verify we have a valid URL + if [[ -z "$CRAFT_URL" ]]; then + echo "::error::Failed to determine Craft download URL. The GitHub API may have failed or the release asset is missing." + exit 1 + fi + echo "Installing Craft from: ${CRAFT_URL}" - sudo curl -sL -o /usr/local/bin/craft "$CRAFT_URL" + sudo curl -fsSL -o /usr/local/bin/craft "$CRAFT_URL" sudo chmod +x /usr/local/bin/craft + + # Verify the binary was downloaded successfully + if [[ ! -s /usr/local/bin/craft ]]; then + echo "::error::Downloaded Craft binary is empty or missing" + exit 1 + fi fi - name: Craft Prepare