Skip to content

ci: bump actions/download-artifact from 4.3.0 to 8.0.1 #177

ci: bump actions/download-artifact from 4.3.0 to 8.0.1

ci: bump actions/download-artifact from 4.3.0 to 8.0.1 #177

Workflow file for this run

name: PR Build
on:
workflow_run:
workflows: ["CI"]
types:
- completed
# Removed branches filter - run for all branches to catch PR updates
pull_request_target:
branches: [ main ]
types: [labeled, closed]
push:
branches: [ prbuild ]
paths:
- 'cli/**'
- '.github/workflows/pr-build.yml'
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to build'
required: false
type: number
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
working-directory: cli
env:
GO_VERSION: '1.26.1'
jobs:
# Check if build should run
check-permission:
name: Check Build Permission
runs-on: ubuntu-latest
# Only run if:
# 1. CI workflow succeeded, OR
# Only run if:
# 1. CI workflow succeeded, OR
# 2. Manual trigger via workflow_dispatch, OR
# 3. PR labeled with 'safe-to-build', OR
# 4. Push to prbuild branch (for testing)
if: |
github.event_name == 'workflow_dispatch' ||
github.event_name == 'pull_request_target' ||
github.event_name == 'push' ||
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
outputs:
allowed: ${{ steps.check.outputs.allowed }}
pr_number: ${{ steps.check.outputs.pr_number }}
pr_sha: ${{ steps.check.outputs.pr_sha }}
steps:
- name: Check if build is allowed
id: check
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
let allowed = false;
let prNumber = null;
let prSha = null;
// Workflow dispatch - always allowed
if (context.eventName === 'workflow_dispatch') {
allowed = true;
prNumber = context.payload.inputs.pr_number;
if (prNumber) {
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
prSha = pr.data.head.sha;
}
core.setOutput('allowed', 'true');
core.setOutput('pr_number', prNumber || '');
core.setOutput('pr_sha', prSha || '');
return;
}
// push event (for testing on prbuild branch)
if (context.eventName === 'push') {
allowed = true;
// Find PR for this branch
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${context.ref.replace('refs/heads/', '')}`
});
if (prs.length > 0) {
prNumber = prs[0].number;
prSha = prs[0].head.sha;
}
core.setOutput('allowed', 'true');
core.setOutput('pr_number', prNumber || '');
core.setOutput('pr_sha', prSha || '');
return;
}
// workflow_run - triggered after CI passes
if (context.eventName === 'workflow_run') {
// Get the PR associated with the workflow run
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`
});
if (prs.length > 0) {
const pr = prs[0];
const association = pr.author_association;
// Check if trusted contributor
const trustedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR', 'CONTRIBUTOR'];
if (trustedAssociations.includes(association)) {
allowed = true;
prNumber = pr.number;
prSha = pr.head.sha;
} else {
// For first-time contributors, check if they have the label
const hasLabel = pr.labels.some(label => label.name === 'safe-to-build');
if (hasLabel) {
allowed = true;
prNumber = pr.number;
prSha = pr.head.sha;
}
}
}
}
// pull_request_target with 'safe-to-build' label
if (context.eventName === 'pull_request_target') {
const hasLabel = context.payload.pull_request.labels.some(
label => label.name === 'safe-to-build'
);
if (hasLabel) {
allowed = true;
prNumber = context.payload.pull_request.number;
prSha = context.payload.pull_request.head.sha;
}
}
core.setOutput('allowed', allowed ? 'true' : 'false');
core.setOutput('pr_number', prNumber || '');
core.setOutput('pr_sha', prSha || '');
if (!allowed) {
core.notice('Build skipped - requires maintainer approval. Add "safe-to-build" label to proceed.');
}
build-pr:
name: Build PR Preview
runs-on: ubuntu-latest
timeout-minutes: 20
needs: check-permission
if: needs.check-permission.outputs.allowed == 'true'
permissions:
contents: write
pull-requests: write
steps:
- name: Get PR details
id: pr
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const prNumber = '${{ needs.check-permission.outputs.pr_number }}' || context.payload.pull_request.number;
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
core.setOutput('number', prNumber);
core.setOutput('sha', pr.data.head.sha);
core.setOutput('ref', pr.data.head.ref);
core.setOutput('title', pr.data.title);
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ steps.pr.outputs.sha }}
- name: Set up Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: '${{ env.GO_VERSION }}'
cache: true
cache-dependency-path: cli/go.sum
- name: Calculate PR version
id: version
working-directory: cli
run: |
BASE_VERSION=$(grep '^version:' extension.yaml | awk '{print $2}')
PR_NUMBER="${{ steps.pr.outputs.number }}"
PR_VERSION="${BASE_VERSION}-pr${PR_NUMBER}"
# Use the standard azd extension tag format so azd x publish generates correct URLs
STANDARD_TAG="azd-ext-jongio-azd-exec_${PR_VERSION}"
echo "version=$PR_VERSION" >> $GITHUB_OUTPUT
echo "base_version=$BASE_VERSION" >> $GITHUB_OUTPUT
echo "tag=$STANDARD_TAG" >> $GITHUB_OUTPUT
echo "Building version: $PR_VERSION with tag: $STANDARD_TAG"
- name: Install azd
run: curl -fsSL https://aka.ms/install-azd.sh | bash
- name: Install azd extensions
run: |
# Add the official azd extensions registry source
azd extension source add azd --location https://aka.ms/azd/extensions/registry --type url 2>/dev/null || true
azd extension install microsoft.azd.extensions --source azd
- name: Update extension.yaml with PR version
working-directory: cli
run: |
VERSION="${{ steps.version.outputs.version }}"
# Temporarily update version (won't commit)
sed -i "s/^version: .*/version: ${VERSION}/" extension.yaml
- name: Build binaries
working-directory: cli
run: |
export EXTENSION_ID="jongio.azd.exec"
export EXTENSION_VERSION="${{ steps.version.outputs.version }}"
azd x build --all
- name: Package
working-directory: cli
run: azd x pack
- name: Create PR pre-release
working-directory: cli
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
TAG="azd-ext-jongio-azd-exec_${VERSION}"
PR_NUM="${{ steps.pr.outputs.number }}"
# Delete existing release if it exists (idempotent for re-runs)
gh release delete "$TAG" --repo "${{ github.repository }}" --yes 2>/dev/null || true
# Create pre-release with all binaries (same pattern as release.yml but with --prerelease)
gh release create "$TAG" \
--repo "${{ github.repository }}" \
--title "PR #${PR_NUM} Preview (v${VERSION})" \
--notes "PR #${PR_NUM} preview build. Test using the one-line installer from the PR comment." \
--prerelease \
~/.azd/registry/jongio.azd.exec/${VERSION}/*
- name: Update registry
working-directory: cli
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
# Generate registry (saves to /tmp/pr-registry.json for the install scripts)
echo '{"extensions":[]}' > /tmp/pr-registry.json
azd x publish \
--registry /tmp/pr-registry.json \
--version "$VERSION" \
--repo "${{ github.repository }}"
# Upload registry to the release so install scripts can download it
TAG="azd-ext-jongio-azd-exec_${VERSION}"
gh release upload "$TAG" --repo "${{ github.repository }}" /tmp/pr-registry.json --clobber
- name: Generate installation instructions
id: instructions
run: |
VERSION="${{ steps.version.outputs.version }}"
PR_NUM="${{ steps.pr.outputs.number }}"
TAG="${{ steps.version.outputs.tag }}"
REPO="${{ github.repository }}"
COMMIT="${{ steps.pr.outputs.sha }}"
SHORT_COMMIT=$(echo $COMMIT | cut -c1-7)
# Use the branch where the scripts actually exist
BRANCH="${{ github.ref_name }}"
WEBSITE_URL="https://jongio.github.io/azd-exec/pr/$PR_NUM/"
cat > ../instructions.md <<EOF
## 🚀 Test This PR
A preview build (\`$VERSION\`) is ready for testing!
### 🌐 Website Preview
**Live Preview:** [$WEBSITE_URL]($WEBSITE_URL)
### One-Line Install (Recommended)
**PowerShell (Windows):**
\`\`\`powershell
iex "& { \$(irm https://raw.githubusercontent.com/$REPO/$BRANCH/cli/scripts/install-pr.ps1) } -PrNumber $PR_NUM -Version $VERSION"
\`\`\`
**Bash (macOS/Linux):**
\`\`\`bash
curl -fsSL https://raw.githubusercontent.com/$REPO/$BRANCH/cli/scripts/install-pr.sh | bash -s $PR_NUM $VERSION
\`\`\`
### Uninstall
When you're done testing:
**PowerShell (Windows):**
\`\`\`powershell
iex "& { \$(irm https://raw.githubusercontent.com/$REPO/$BRANCH/cli/scripts/uninstall-pr.ps1) } -PrNumber $PR_NUM"
\`\`\`
**Bash (macOS/Linux):**
\`\`\`bash
curl -fsSL https://raw.githubusercontent.com/$REPO/$BRANCH/cli/scripts/uninstall-pr.sh | bash -s $PR_NUM
\`\`\`
---
**Build Info:**
- **Version:** \`$VERSION\`
- **Commit:** \`$SHORT_COMMIT\`
- **Release:** [View pre-release](https://github.com/$REPO/releases/tag/$TAG)
**What to Test:**
Please review the PR description and test the changes described there.
EOF
- name: Comment on PR
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const fs = require('fs');
const instructions = fs.readFileSync('instructions.md', 'utf8');
const prNumber = '${{ steps.pr.outputs.number }}';
// Find existing comment
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const botComment = comments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('🚀 Test This PR')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: instructions
});
console.log('Updated existing comment');
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: instructions
});
console.log('Created new comment');
}
# Cleanup job - removes registry releases when PR closes
cleanup:
name: Cleanup PR Registry
runs-on: ubuntu-latest
if: github.event.action == 'closed' && github.event_name == 'pull_request_target'
permissions:
contents: write
defaults:
run:
working-directory: .
steps:
- name: Delete PR registry release
env:
GH_TOKEN: ${{ github.token }}
run: |
PR_NUM=${{ github.event.pull_request.number }}
# Find and delete releases matching this PR
gh release list --repo ${{ github.repository }} --json tagName,name --limit 100 | \
jq -r ".[] | select(.tagName | contains(\"-pr${PR_NUM}\")) | .tagName" | \
while read tag; do
echo "Deleting release: $tag"
gh release delete "$tag" --repo ${{ github.repository }} --yes || true
# Delete tag
git push --delete origin "$tag" 2>/dev/null || true
done