|
| 1 | +name: Release |
| 2 | + |
| 3 | +on: |
| 4 | + push: |
| 5 | + tags: |
| 6 | + - '*' |
| 7 | + workflow_dispatch: |
| 8 | + inputs: |
| 9 | + tag: |
| 10 | + description: 'Tag to create release for' |
| 11 | + required: true |
| 12 | + type: string |
| 13 | + |
| 14 | +permissions: |
| 15 | + contents: write |
| 16 | + id-token: write |
| 17 | + |
| 18 | +jobs: |
| 19 | + release: |
| 20 | + name: Create Release |
| 21 | + runs-on: ubuntu-latest |
| 22 | + |
| 23 | + env: |
| 24 | + RELEASE_TAG: ${{ inputs.tag || github.ref_name }} |
| 25 | + |
| 26 | + steps: |
| 27 | + - name: Checkout code |
| 28 | + uses: actions/checkout@v4 |
| 29 | + with: |
| 30 | + fetch-depth: 0 |
| 31 | + ref: ${{ inputs.tag || github.ref }} |
| 32 | + |
| 33 | + - name: Verify tag is on main branch |
| 34 | + run: | |
| 35 | + if ! git branch -r --contains "${RELEASE_TAG}" | grep -q 'origin/main'; then |
| 36 | + echo "::error::Tag ${RELEASE_TAG} is not on main branch. Releases can only be created from tags on main." |
| 37 | + exit 1 |
| 38 | + fi |
| 39 | +
|
| 40 | + - name: Get previous tag |
| 41 | + id: prev_tag |
| 42 | + run: | |
| 43 | + PREV_TAG=$(git tag --sort=-creatordate | grep -v "^${RELEASE_TAG}$" | head -1) |
| 44 | + echo "tag=${PREV_TAG}" >> $GITHUB_OUTPUT |
| 45 | + echo "Previous tag: ${PREV_TAG}" |
| 46 | +
|
| 47 | + - name: Fetch manifest.json |
| 48 | + id: manifest |
| 49 | + run: | |
| 50 | + MANIFEST=$(curl -sf https://storage.googleapis.com/gitpod-runner-releases/gcp/stable/manifest.json) |
| 51 | + echo "version=$(echo "$MANIFEST" | jq -r '.version')" >> $GITHUB_OUTPUT |
| 52 | + echo "runner_image=$(echo "$MANIFEST" | jq -r '.runner_image')" >> $GITHUB_OUTPUT |
| 53 | + echo "proxy_image=$(echo "$MANIFEST" | jq -r '.proxy_image')" >> $GITHUB_OUTPUT |
| 54 | + echo "prometheus_image=$(echo "$MANIFEST" | jq -r '.prometheus_image')" >> $GITHUB_OUTPUT |
| 55 | + echo "node_exporter_image=$(echo "$MANIFEST" | jq -r '.node_exporter_image')" >> $GITHUB_OUTPUT |
| 56 | + echo "cli_url=$(echo "$MANIFEST" | jq -r '.cli_url')" >> $GITHUB_OUTPUT |
| 57 | + echo "supervisor_url=$(echo "$MANIFEST" | jq -r '.supervisor_url')" >> $GITHUB_OUTPUT |
| 58 | + echo "vm_image=$(echo "$MANIFEST" | jq -r '.vm_image')" >> $GITHUB_OUTPUT |
| 59 | +
|
| 60 | + - name: Generate changelog |
| 61 | + id: changelog |
| 62 | + run: | |
| 63 | + if [ -n "${{ steps.prev_tag.outputs.tag }}" ]; then |
| 64 | + # Get commits between tags, excluding automated image update commits |
| 65 | + CHANGELOG=$(git log --pretty=format:"- %s (%h)" \ |
| 66 | + "${{ steps.prev_tag.outputs.tag }}..${RELEASE_TAG}" \ |
| 67 | + --grep="Update GCP runner, proxy, prometheus, and node-exporter images" --invert-grep) |
| 68 | + else |
| 69 | + # First release - get all commits excluding automated ones |
| 70 | + CHANGELOG=$(git log --pretty=format:"- %s (%h)" \ |
| 71 | + --grep="Update GCP runner, proxy, prometheus, and node-exporter images" --invert-grep) |
| 72 | + fi |
| 73 | +
|
| 74 | + # Handle empty changelog |
| 75 | + if [ -z "$CHANGELOG" ]; then |
| 76 | + CHANGELOG="- No user-facing changes in this release" |
| 77 | + fi |
| 78 | +
|
| 79 | + # Write to file to preserve newlines |
| 80 | + echo "$CHANGELOG" > changelog.txt |
| 81 | +
|
| 82 | + - name: Detect IAM/permission changes |
| 83 | + id: iam_changes |
| 84 | + run: | |
| 85 | + IAM_FILES="iam.tf docs/iam.md docs/detailed_iam_reference.md docs/terraform_service_account_permissions.md" |
| 86 | +
|
| 87 | + if [ -n "${{ steps.prev_tag.outputs.tag }}" ]; then |
| 88 | + # Check if any IAM-related files changed between tags |
| 89 | + CHANGED_FILES=$(git diff --name-only "${{ steps.prev_tag.outputs.tag }}..${RELEASE_TAG}" -- $IAM_FILES 2>/dev/null || true) |
| 90 | +
|
| 91 | + if [ -n "$CHANGED_FILES" ]; then |
| 92 | + echo "has_changes=true" >> $GITHUB_OUTPUT |
| 93 | +
|
| 94 | + # Get commits that touched IAM files |
| 95 | + IAM_COMMITS=$(git log --pretty=format:"- %s (%h)" \ |
| 96 | + "${{ steps.prev_tag.outputs.tag }}..${RELEASE_TAG}" \ |
| 97 | + --grep="Update GCP runner, proxy, prometheus, and node-exporter images" --invert-grep \ |
| 98 | + -- $IAM_FILES) |
| 99 | +
|
| 100 | + echo "$IAM_COMMITS" > iam_changelog.txt |
| 101 | + echo "Changed files: $CHANGED_FILES" |
| 102 | + else |
| 103 | + echo "has_changes=false" >> $GITHUB_OUTPUT |
| 104 | + fi |
| 105 | + else |
| 106 | + echo "has_changes=false" >> $GITHUB_OUTPUT |
| 107 | + fi |
| 108 | +
|
| 109 | + - name: Create release tarball |
| 110 | + run: | |
| 111 | + # Create tarball in /tmp to avoid "file changed as we read it" error |
| 112 | + tar --exclude='.git' \ |
| 113 | + --exclude='.github' \ |
| 114 | + --exclude='.devcontainer' \ |
| 115 | + --exclude='.cursor' \ |
| 116 | + --exclude='tests' \ |
| 117 | + --exclude='.pre-commit-config.yaml' \ |
| 118 | + --exclude='changelog.txt' \ |
| 119 | + --exclude='iam_changelog.txt' \ |
| 120 | + --exclude='release_body.md' \ |
| 121 | + -czvf /tmp/terraform-google-ona-runner-${RELEASE_TAG}.tar.gz . |
| 122 | + mv /tmp/terraform-google-ona-runner-${RELEASE_TAG}.tar.gz . |
| 123 | +
|
| 124 | + - name: Build release body |
| 125 | + id: body |
| 126 | + run: | |
| 127 | + cat << 'EOF' > release_body.md |
| 128 | + ## Container Images |
| 129 | +
|
| 130 | + | Component | Image | |
| 131 | + |-----------|-------| |
| 132 | + | Runner | `${{ steps.manifest.outputs.runner_image }}` | |
| 133 | + | Proxy | `${{ steps.manifest.outputs.proxy_image }}` | |
| 134 | + | Prometheus | `${{ steps.manifest.outputs.prometheus_image }}` | |
| 135 | + | Node Exporter | `${{ steps.manifest.outputs.node_exporter_image }}` | |
| 136 | +
|
| 137 | + ## Assets |
| 138 | +
|
| 139 | + | Asset | URL | |
| 140 | + |-------|-----| |
| 141 | + | CLI Binary | `${{ steps.manifest.outputs.cli_url }}` | |
| 142 | + | Supervisor Binary | `${{ steps.manifest.outputs.supervisor_url }}` | |
| 143 | + | VM Image | `${{ steps.manifest.outputs.vm_image }}` | |
| 144 | +
|
| 145 | + EOF |
| 146 | +
|
| 147 | + # Add IAM changes section if there are any |
| 148 | + if [ "${{ steps.iam_changes.outputs.has_changes }}" = "true" ]; then |
| 149 | + cat << 'EOF' >> release_body.md |
| 150 | + ## ⚠️ IAM/Permission Changes |
| 151 | +
|
| 152 | + This release includes changes to IAM roles or permissions. Review the following commits and update your IAM configuration if needed: |
| 153 | +
|
| 154 | + EOF |
| 155 | + cat iam_changelog.txt >> release_body.md |
| 156 | + echo "" >> release_body.md |
| 157 | + echo "See [docs/iam.md](docs/iam.md) and [docs/terraform_service_account_permissions.md](docs/terraform_service_account_permissions.md) for the updated permission requirements." >> release_body.md |
| 158 | + echo "" >> release_body.md |
| 159 | + fi |
| 160 | +
|
| 161 | + cat << 'EOF' >> release_body.md |
| 162 | + ## Changelog |
| 163 | +
|
| 164 | + EOF |
| 165 | + cat changelog.txt >> release_body.md |
| 166 | +
|
| 167 | + - name: Create Release |
| 168 | + uses: softprops/action-gh-release@v2 |
| 169 | + with: |
| 170 | + tag_name: ${{ env.RELEASE_TAG }} |
| 171 | + name: ${{ env.RELEASE_TAG }} |
| 172 | + body_path: release_body.md |
| 173 | + files: | |
| 174 | + terraform-google-ona-runner-${{ env.RELEASE_TAG }}.tar.gz |
| 175 | + fail_on_unmatched_files: true |
| 176 | + env: |
| 177 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 178 | + |
| 179 | + - name: Authenticate to GCP |
| 180 | + uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # pin@v3 |
| 181 | + with: |
| 182 | + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_POOL }} |
| 183 | + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} |
| 184 | + |
| 185 | + - name: Publish release notification |
| 186 | + run: | |
| 187 | + MANIFEST=$(curl -sf https://storage.googleapis.com/gitpod-runner-releases/gcp/stable/manifest.json) |
| 188 | +
|
| 189 | + # Build enriched payload with terraform module changes |
| 190 | + PAYLOAD=$(echo "$MANIFEST" | jq \ |
| 191 | + --arg iam_changes "${{ steps.iam_changes.outputs.has_changes }}" \ |
| 192 | + --rawfile changelog changelog.txt \ |
| 193 | + '. + { |
| 194 | + terraform_changes: ($changelog | split("\n") | map(select(. != ""))), |
| 195 | + iam_changes_detected: ($iam_changes == "true") |
| 196 | + }') |
| 197 | +
|
| 198 | + gcloud pubsub topics publish gcp-runner-releases \ |
| 199 | + --project=gitpod-next-production \ |
| 200 | + --message="$PAYLOAD" \ |
| 201 | + --attribute="event_type=release.stable,version=${RELEASE_TAG},source=ci_stable_promotion" |
0 commit comments