mirror of
https://github.com/caddyserver/caddy.git
synced 2026-11-11 19:37:55 +00:00
Bumps the actions-deps group with 10 updates in the / directory: | Package | From | To | | --- | --- | --- | | [actions/checkout](https://github.com/actions/checkout) | `7.0.0` | `7.0.1` | | [step-security/harden-runner](https://github.com/step-security/harden-runner) | `2.19.4` | `2.22.3` | | [actions/setup-go](https://github.com/actions/setup-go) | `6.5.0` | `7.0.0` | | [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.1` | `7.0.2` | | [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) | `7.2.3` | `7.3.0` | | [golang/govulncheck-action](https://github.com/golang/govulncheck-action) | `1.0.4` | `1.1.0` | | [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `4.1.0` | `4.1.2` | | [anchore/sbom-action/download-syft](https://github.com/anchore/sbom-action) | `0.24.0` | `0.24.3` | | [ossf/scorecard-action](https://github.com/ossf/scorecard-action) | `2.4.3` | `2.5.0` | | [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) | `4.36.2` | `4.39.1` | Updates `actions/checkout` from 7.0.0 to 7.0.1 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1) Updates `step-security/harden-runner` from 2.19.4 to 2.22.3 - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](https://github.com/step-security/harden-runner/compare/9af89fc71515a100421586dfdb3dc9c984fbf411...46b06cea07f9e64621fdf066ba77ac6915163d43) Updates `actions/setup-go` from 6.5.0 to 7.0.0 - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/924ae3a1cded613372ab5595356fb5720e22ba16...b7ad1dad31e06c5925ef5d2fc7ad053ef454303e) Updates `actions/upload-artifact` from 7.0.1 to 7.0.2 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a...cf430e030ddbb5b0abf93d22962f4752f3646cd9) Updates `goreleaser/goreleaser-action` from 7.2.3 to 7.3.0 - [Release notes](https://github.com/goreleaser/goreleaser-action/releases) - [Commits](https://github.com/goreleaser/goreleaser-action/compare/f06c13b6b1a9625abc9e6e439d9c05a8f2190e94...a4f02ab5355a589de60d917a659ce617ed19b3de) Updates `golang/govulncheck-action` from 1.0.4 to 1.1.0 - [Release notes](https://github.com/golang/govulncheck-action/releases) - [Commits](https://github.com/golang/govulncheck-action/compare/b625fbe08f3bccbe446d94fbf87fcc875a4f50ee...032d45514ae346b1db93c04b0c90b841c370344f) Updates `sigstore/cosign-installer` from 4.1.0 to 4.1.2 - [Release notes](https://github.com/sigstore/cosign-installer/releases) - [Commits](https://github.com/sigstore/cosign-installer/compare/ba7bc0a3fef59531c69a25acd34668d6d3fe6f22...6f9f17788090df1f26f669e9d70d6ae9567deba6) Updates `anchore/sbom-action/download-syft` from 0.24.0 to 0.24.3 - [Release notes](https://github.com/anchore/sbom-action/releases) - [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md) - [Commits](https://github.com/anchore/sbom-action/compare/e22c389904149dbc22b58101806040fa8d37a610...66cbf4bc1f1c0d2edc94016e65bc221b6bb0ad6c) Updates `ossf/scorecard-action` from 2.4.3 to 2.5.0 - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/4eaacf0543bb3f2c246792bd56e8cdeffafb205a...fa7117db83c52d787ae5a89f350999701505d78e) Updates `github/codeql-action/upload-sarif` from 4.36.2 to 4.39.1 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...9b3254085494b55a0f7c4c2b3d2d52cc712ce370) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-deps - dependency-name: actions/setup-go dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions-deps - dependency-name: actions/upload-artifact dependency-version: 7.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-deps - dependency-name: anchore/sbom-action/download-syft dependency-version: 0.24.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-deps - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.39.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-deps - dependency-name: golang/govulncheck-action dependency-version: 1.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-deps - dependency-name: goreleaser/goreleaser-action dependency-version: 7.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-deps - dependency-name: ossf/scorecard-action dependency-version: 2.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-deps - dependency-name: sigstore/cosign-installer dependency-version: 4.1.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-deps - dependency-name: step-security/harden-runner dependency-version: 2.22.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-deps ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
553 lines
22 KiB
YAML
553 lines
22 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*.*.*'
|
|
|
|
env:
|
|
# https://github.com/actions/setup-go/issues/491
|
|
GOTOOLCHAIN: local
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
verify-tag:
|
|
name: Verify Tag Signature and Approvals
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
issues: write
|
|
|
|
outputs:
|
|
verification_passed: ${{ steps.verify.outputs.passed }}
|
|
tag_version: ${{ steps.info.outputs.version }}
|
|
proposal_issue_number: ${{ steps.find_proposal.outputs.result && fromJson(steps.find_proposal.outputs.result).number || '' }}
|
|
|
|
# Values from the event, step outputs and API results are only ever
|
|
# passed through env:, never interpolated as expressions into run: or
|
|
# script: bodies.
|
|
steps:
|
|
# Validate the tag name before anything else uses it. Git allows
|
|
# characters like $, ( and ; in tag names that match the v*.*.* trigger,
|
|
# and the tag name ends up in shell commands (including GoReleaser hooks).
|
|
- name: Validate tag name
|
|
run: |
|
|
if [[ ! "$GITHUB_REF" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then
|
|
echo "❌ Refusing to release $GITHUB_REF: not a vMAJOR.MINOR.PATCH[-PRERELEASE] tag"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: 0
|
|
# Force fetch upstream tags -- because 65 minutes
|
|
# tl;dr: actions/checkout@v3 runs this line:
|
|
# git -c protocol.version=2 fetch --no-tags --prune --progress --no-recurse-submodules --depth=1 origin +ebc278ec98bb24f2852b61fde2a9bf2e3d83818b:refs/tags/
|
|
# which makes its own local lightweight tag, losing all the annotations in the process. Our earlier script ran:
|
|
# git fetch --prune --unshallow
|
|
# which doesn't overwrite that tag because that would be destructive.
|
|
# Credit to @francislavoie for the investigation.
|
|
# https://github.com/actions/checkout/issues/290#issuecomment-680260080
|
|
- name: Force fetch upstream tags
|
|
run: git fetch --tags --force
|
|
|
|
- name: Get tag info
|
|
id: info
|
|
run: |
|
|
echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
|
|
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
|
|
|
# https://github.community/t5/GitHub-Actions/How-to-get-just-the-tag-name/m-p/32167/highlight/true#M1027
|
|
- name: Print Go version and environment
|
|
id: vars
|
|
run: |
|
|
printf "Using go at: $(which go)\n"
|
|
printf "Go version: $(go version)\n"
|
|
printf "\n\nGo environment:\n\n"
|
|
go env
|
|
printf "\n\nSystem environment:\n\n"
|
|
env
|
|
echo "version_tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
|
|
echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
|
|
|
# Add "pip install" CLI tools to PATH
|
|
echo ~/.local/bin >> $GITHUB_PATH
|
|
|
|
# Parse semver
|
|
TAG=${GITHUB_REF/refs\/tags\//}
|
|
SEMVER_RE='[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z\.-]*\)'
|
|
TAG_MAJOR=`echo ${TAG#v} | sed -e "s#$SEMVER_RE#\1#"`
|
|
TAG_MINOR=`echo ${TAG#v} | sed -e "s#$SEMVER_RE#\2#"`
|
|
TAG_PATCH=`echo ${TAG#v} | sed -e "s#$SEMVER_RE#\3#"`
|
|
TAG_SPECIAL=`echo ${TAG#v} | sed -e "s#$SEMVER_RE#\4#"`
|
|
echo "tag_major=${TAG_MAJOR}" >> $GITHUB_OUTPUT
|
|
echo "tag_minor=${TAG_MINOR}" >> $GITHUB_OUTPUT
|
|
echo "tag_patch=${TAG_PATCH}" >> $GITHUB_OUTPUT
|
|
echo "tag_special=${TAG_SPECIAL}" >> $GITHUB_OUTPUT
|
|
|
|
- name: Validate commits and tag signatures
|
|
id: verify
|
|
env:
|
|
signing_keys: ${{ secrets.SIGNING_KEYS }}
|
|
TAG: ${{ steps.vars.outputs.version_tag }}
|
|
run: |
|
|
# Read the string into an array, splitting by IFS
|
|
IFS=";" read -ra keys_collection <<< "$signing_keys"
|
|
|
|
# ref: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#example-usage-of-the-runner-context
|
|
touch "$RUNNER_TEMP/allowed_signers"
|
|
|
|
# Iterate and print the split elements
|
|
for item in "${keys_collection[@]}"; do
|
|
|
|
# trim leading whitespaces
|
|
item="${item##*( )}"
|
|
|
|
# trim trailing whitespaces
|
|
item="${item%%*( )}"
|
|
|
|
IFS=" " read -ra key_components <<< "$item"
|
|
# git wants it in format: email address, type, public key
|
|
# ssh has it in format: type, public key, email address
|
|
echo "${key_components[2]} namespaces=\"git\" ${key_components[0]} ${key_components[1]}" >> "$RUNNER_TEMP/allowed_signers"
|
|
done
|
|
|
|
git config set --global gpg.ssh.allowedSignersFile "$RUNNER_TEMP/allowed_signers"
|
|
|
|
echo "Verifying the tag: $TAG"
|
|
|
|
# Verify the tag is signed
|
|
if ! git verify-tag -v "$TAG" 2>&1; then
|
|
echo "❌ Tag verification failed!"
|
|
echo "passed=false" >> $GITHUB_OUTPUT
|
|
git push --delete origin "$TAG"
|
|
exit 1
|
|
fi
|
|
# Run it again to capture the output
|
|
git verify-tag -v "$TAG" 2>&1 | tee /tmp/verify-output.txt;
|
|
|
|
# SSH verification output typically includes the key fingerprint
|
|
# Use GNU grep with Perl regex for cleaner extraction (Linux environment)
|
|
KEY_SHA256=$(grep -oP "SHA256:[\"']?\K[A-Za-z0-9+/=]+(?=[\"']?)" /tmp/verify-output.txt | head -1 || echo "")
|
|
|
|
if [ -z "$KEY_SHA256" ]; then
|
|
# Try alternative pattern with "key" prefix
|
|
KEY_SHA256=$(grep -oP "key SHA256:[\"']?\K[A-Za-z0-9+/=]+(?=[\"']?)" /tmp/verify-output.txt | head -1 || echo "")
|
|
fi
|
|
|
|
if [ -z "$KEY_SHA256" ]; then
|
|
# Fallback: extract any base64-like string (40+ chars)
|
|
KEY_SHA256=$(grep -oP '[A-Za-z0-9+/]{40,}=?' /tmp/verify-output.txt | head -1 || echo "")
|
|
fi
|
|
|
|
if [ -z "$KEY_SHA256" ]; then
|
|
echo "Somehow could not extract SSH key fingerprint from git verify-tag output"
|
|
echo "Cancelling flow and deleting tag"
|
|
echo "passed=false" >> $GITHUB_OUTPUT
|
|
git push --delete origin "$TAG"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Tag verification succeeded!"
|
|
echo "passed=true" >> $GITHUB_OUTPUT
|
|
echo "key_id=$KEY_SHA256" >> $GITHUB_OUTPUT
|
|
|
|
# Fails closed: there must be exactly one open proposal for this exact
|
|
# version, with enough maintainer approvals of its current head commit.
|
|
# The tag is left in place on failure, so the job can be re-run once
|
|
# the proposal is approved.
|
|
- name: Find related release proposal
|
|
id: find_proposal
|
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
env:
|
|
TAG: ${{ steps.vars.outputs.version_tag }}
|
|
MAINTAINER_LOGINS: ${{ secrets.MAINTAINER_LOGINS }}
|
|
with:
|
|
script: |
|
|
const { checkProposal, REQUIRED_APPROVALS } = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/release-proposal.js`);
|
|
|
|
const { pr, targetCommit, approvers, approved } = await checkProposal({
|
|
github, context, version: process.env.TAG, maintainerLogins: process.env.MAINTAINER_LOGINS,
|
|
});
|
|
console.log(`Found proposal PR #${pr.number}, for commit ${targetCommit}`);
|
|
console.log(`Maintainer approvals of ${pr.head.sha}: ${approvers.join(', ') || 'none'}`);
|
|
|
|
if (!approved) {
|
|
core.setFailed(`Proposal #${pr.number} has ${approvers.length} maintainer approvals of its current head commit; ${REQUIRED_APPROVALS} are required`);
|
|
return;
|
|
}
|
|
|
|
return {
|
|
number: pr.number,
|
|
approvals: approvers.length,
|
|
approvers: approvers.map(login => `@${login}`).join(', '),
|
|
proposedCommit: targetCommit
|
|
};
|
|
result-encoding: json
|
|
|
|
- name: Verify proposal commit
|
|
env:
|
|
PROPOSED_COMMIT: ${{ fromJson(steps.find_proposal.outputs.result).proposedCommit }}
|
|
CURRENT_COMMIT: ${{ steps.info.outputs.sha }}
|
|
TAG: ${{ steps.vars.outputs.version_tag }}
|
|
run: |
|
|
echo "Proposed commit: $PROPOSED_COMMIT"
|
|
echo "Current commit: $CURRENT_COMMIT"
|
|
|
|
# Both are full SHAs, so compare them exactly
|
|
if [[ ! "$PROPOSED_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
|
|
echo "❌ Proposal has no valid target commit: $PROPOSED_COMMIT"
|
|
exit 1
|
|
fi
|
|
if [ "$PROPOSED_COMMIT" != "$CURRENT_COMMIT" ]; then
|
|
echo "❌ Commit mismatch!"
|
|
echo "The tag points to commit $CURRENT_COMMIT but the proposal was for $PROPOSED_COMMIT"
|
|
echo "This indicates an error in tag creation."
|
|
# Delete the tag remotely
|
|
git push --delete origin "$TAG"
|
|
echo "Tag $TAG has been deleted"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Commit hash matches proposal"
|
|
|
|
- name: Update release proposal PR
|
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
env:
|
|
RESULT: ${{ steps.find_proposal.outputs.result }}
|
|
TAG: ${{ steps.info.outputs.version }}
|
|
KEY_ID: ${{ steps.verify.outputs.key_id }}
|
|
SHA: ${{ steps.info.outputs.sha }}
|
|
with:
|
|
script: |
|
|
const result = JSON.parse(process.env.RESULT);
|
|
|
|
// Add in-progress label
|
|
await github.rest.issues.addLabels({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: result.number,
|
|
labels: ['release-in-progress']
|
|
});
|
|
|
|
// Remove approved label if present
|
|
try {
|
|
await github.rest.issues.removeLabel({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: result.number,
|
|
name: 'approved'
|
|
});
|
|
} catch (e) {
|
|
console.log('Approved label not found:', e.message);
|
|
}
|
|
|
|
const commentBody = [
|
|
'## 🚀 Release Workflow Started',
|
|
'',
|
|
`- **Tag:** ${process.env.TAG}`,
|
|
`- **Signed by key:** ${process.env.KEY_ID}`,
|
|
`- **Commit:** ${process.env.SHA}`,
|
|
`- **Approved by:** ${result.approvers}`,
|
|
'',
|
|
'Release workflow is now running. This PR will be updated when the release is published.'
|
|
].join('\n');
|
|
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: result.number,
|
|
body: commentBody
|
|
});
|
|
|
|
- name: Summary
|
|
env:
|
|
PROPOSED_COMMIT: ${{ fromJson(steps.find_proposal.outputs.result).proposedCommit }}
|
|
APPROVERS: ${{ fromJson(steps.find_proposal.outputs.result).approvers }}
|
|
TAG: ${{ steps.info.outputs.version }}
|
|
SHA: ${{ steps.info.outputs.sha }}
|
|
KEY_ID: ${{ steps.verify.outputs.key_id }}
|
|
run: |
|
|
{
|
|
echo "## Tag Verification Summary 🔐"
|
|
echo ""
|
|
echo "- **Tag:** $TAG"
|
|
echo "- **Commit:** $SHA"
|
|
echo "- **Proposed Commit:** $PROPOSED_COMMIT"
|
|
echo "- **Signature:** ✅ Verified"
|
|
echo "- **Signed by:** $KEY_ID"
|
|
echo "- **Approvals:** ✅ Sufficient"
|
|
echo "- **Approved by:** $APPROVERS"
|
|
echo ""
|
|
echo "Proceeding with release build..."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
release:
|
|
name: Release
|
|
needs: verify-tag
|
|
if: ${{ needs.verify-tag.outputs.verification_passed == 'true' }}
|
|
strategy:
|
|
matrix:
|
|
os:
|
|
- ubuntu-latest
|
|
go:
|
|
- '1.27'
|
|
|
|
include:
|
|
# Set the minimum Go patch version for the given Go minor
|
|
# Usable via ${{ matrix.GO_SEMVER }}
|
|
- go: '1.27'
|
|
GO_SEMVER: '~1.27.0'
|
|
|
|
runs-on: ${{ matrix.os }}
|
|
# https://github.com/sigstore/cosign/issues/1258#issuecomment-1002251233
|
|
# https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#adding-permissions-settings
|
|
permissions:
|
|
id-token: write
|
|
# https://docs.github.com/en/rest/overview/permissions-required-for-github-apps#permission-on-contents
|
|
# "Releases" is part of `contents`, so it needs the `write`
|
|
contents: write
|
|
issues: write
|
|
pull-requests: write
|
|
|
|
steps:
|
|
# Same check as in verify-tag: the tag name ends up in GoReleaser's
|
|
# shell hooks via $TAG.
|
|
- name: Validate tag name
|
|
run: |
|
|
if [[ ! "$GITHUB_REF" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then
|
|
echo "❌ Refusing to release $GITHUB_REF: not a vMAJOR.MINOR.PATCH[-PRERELEASE] tag"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Harden the runner (Audit all outbound calls)
|
|
uses: step-security/harden-runner@46b06cea07f9e64621fdf066ba77ac6915163d43 # v2.22.3
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Install Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version: ${{ matrix.GO_SEMVER }}
|
|
check-latest: true
|
|
|
|
# Force fetch upstream tags -- because 65 minutes
|
|
# tl;dr: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v4.2.2 runs this line:
|
|
# git -c protocol.version=2 fetch --no-tags --prune --progress --no-recurse-submodules --depth=1 origin +ebc278ec98bb24f2852b61fde2a9bf2e3d83818b:refs/tags/
|
|
# which makes its own local lightweight tag, losing all the annotations in the process. Our earlier script ran:
|
|
# git fetch --prune --unshallow
|
|
# which doesn't overwrite that tag because that would be destructive.
|
|
# Credit to @francislavoie for the investigation.
|
|
# https://github.com/actions/checkout/issues/290#issuecomment-680260080
|
|
- name: Force fetch upstream tags
|
|
run: git fetch --tags --force
|
|
|
|
# https://github.community/t5/GitHub-Actions/How-to-get-just-the-tag-name/m-p/32167/highlight/true#M1027
|
|
- name: Print Go version and environment
|
|
id: vars
|
|
run: |
|
|
printf "Using go at: $(which go)\n"
|
|
printf "Go version: $(go version)\n"
|
|
printf "\n\nGo environment:\n\n"
|
|
go env
|
|
printf "\n\nSystem environment:\n\n"
|
|
env
|
|
echo "version_tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
|
|
echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
|
|
|
# Add "pip install" CLI tools to PATH
|
|
echo ~/.local/bin >> $GITHUB_PATH
|
|
|
|
# Parse semver
|
|
TAG=${GITHUB_REF/refs\/tags\//}
|
|
SEMVER_RE='[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z\.-]*\)'
|
|
TAG_MAJOR=`echo ${TAG#v} | sed -e "s#$SEMVER_RE#\1#"`
|
|
TAG_MINOR=`echo ${TAG#v} | sed -e "s#$SEMVER_RE#\2#"`
|
|
TAG_PATCH=`echo ${TAG#v} | sed -e "s#$SEMVER_RE#\3#"`
|
|
TAG_SPECIAL=`echo ${TAG#v} | sed -e "s#$SEMVER_RE#\4#"`
|
|
echo "tag_major=${TAG_MAJOR}" >> $GITHUB_OUTPUT
|
|
echo "tag_minor=${TAG_MINOR}" >> $GITHUB_OUTPUT
|
|
echo "tag_patch=${TAG_PATCH}" >> $GITHUB_OUTPUT
|
|
echo "tag_special=${TAG_SPECIAL}" >> $GITHUB_OUTPUT
|
|
|
|
# Cloudsmith CLI tooling for pushing releases
|
|
# See https://help.cloudsmith.io/docs/cli
|
|
- name: Install Cloudsmith CLI
|
|
run: pip install --upgrade cloudsmith-cli
|
|
|
|
- name: Install Cosign
|
|
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
|
- name: Cosign version
|
|
run: cosign version
|
|
- name: Install Syft
|
|
uses: anchore/sbom-action/download-syft@66cbf4bc1f1c0d2edc94016e65bc221b6bb0ad6c # main
|
|
- name: Syft version
|
|
run: syft version
|
|
- name: Install xcaddy
|
|
run: |
|
|
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
|
|
xcaddy version
|
|
# Generate the draft's notes in the same format as GitHub's "Generate
|
|
# release notes" button, compared against the previous *published*
|
|
# release by version (not the previous tag, which may be an abandoned
|
|
# release attempt), and without PRs that already shipped in it as
|
|
# backports. GoReleaser's own changelog can do neither.
|
|
- name: Generate release notes
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
TAG: ${{ steps.vars.outputs.version_tag }}
|
|
NOTES_FILE: ${{ runner.temp }}/release-notes.md
|
|
run: |
|
|
PREVIOUS_RELEASE=$(.github/scripts/previous-release.sh "$TAG")
|
|
echo "Previous published release: ${PREVIOUS_RELEASE:-none}"
|
|
.github/scripts/release-notes.sh "$TAG" "$TAG" "$PREVIOUS_RELEASE" > "$NOTES_FILE"
|
|
cat "$NOTES_FILE"
|
|
|
|
# GoReleaser will take care of publishing those artifacts into the release
|
|
- name: Run GoReleaser
|
|
uses: goreleaser/goreleaser-action@a4f02ab5355a589de60d917a659ce617ed19b3de # v7.3.0
|
|
with:
|
|
version: latest
|
|
args: release --clean --timeout 60m --release-notes ${{ runner.temp }}/release-notes.md
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
TAG: ${{ steps.vars.outputs.version_tag }}
|
|
|
|
# Only publish on non-special tags (e.g. non-beta)
|
|
# We will continue to push to Gemfury for the foreseeable future, although
|
|
# Cloudsmith is probably better, to not break things for existing users of Gemfury.
|
|
# See https://gemfury.com/caddy/deb:caddy
|
|
- name: Publish .deb to Gemfury
|
|
if: ${{ steps.vars.outputs.tag_special == '' }}
|
|
env:
|
|
GEMFURY_PUSH_TOKEN: ${{ secrets.GEMFURY_PUSH_TOKEN }}
|
|
run: |
|
|
for filename in dist/*.deb; do
|
|
# armv6 and armv7 are both "armhf" so we can skip the duplicate
|
|
if [[ "$filename" == *"armv6"* ]]; then
|
|
echo "Skipping $filename"
|
|
continue
|
|
fi
|
|
|
|
curl -F package=@"$filename" https://${GEMFURY_PUSH_TOKEN}:@push.fury.io/caddy/
|
|
done
|
|
|
|
# Publish only special tags (unstable/beta/rc) to the "testing" repo
|
|
# See https://cloudsmith.io/~caddy/repos/testing/
|
|
- name: Publish .deb to Cloudsmith (special tags)
|
|
if: ${{ steps.vars.outputs.tag_special != '' }}
|
|
env:
|
|
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
|
|
run: |
|
|
for filename in dist/*.deb; do
|
|
# armv6 and armv7 are both "armhf" so we can skip the duplicate
|
|
if [[ "$filename" == *"armv6"* ]]; then
|
|
echo "Skipping $filename"
|
|
continue
|
|
fi
|
|
|
|
echo "Pushing $filename to 'testing'"
|
|
cloudsmith push deb caddy/testing/any-distro/any-version $filename
|
|
done
|
|
|
|
# Publish stable tags to Cloudsmith to both repos, "stable" and "testing"
|
|
# See https://cloudsmith.io/~caddy/repos/stable/
|
|
- name: Publish .deb to Cloudsmith (stable tags)
|
|
if: ${{ steps.vars.outputs.tag_special == '' }}
|
|
env:
|
|
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
|
|
run: |
|
|
for filename in dist/*.deb; do
|
|
# armv6 and armv7 are both "armhf" so we can skip the duplicate
|
|
if [[ "$filename" == *"armv6"* ]]; then
|
|
echo "Skipping $filename"
|
|
continue
|
|
fi
|
|
|
|
echo "Pushing $filename to 'stable'"
|
|
cloudsmith push deb caddy/stable/any-distro/any-version $filename
|
|
|
|
echo "Pushing $filename to 'testing'"
|
|
cloudsmith push deb caddy/testing/any-distro/any-version $filename
|
|
done
|
|
|
|
- name: Update release proposal PR
|
|
if: needs.verify-tag.outputs.proposal_issue_number != ''
|
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
env:
|
|
PROPOSAL_NUMBER: ${{ needs.verify-tag.outputs.proposal_issue_number }}
|
|
with:
|
|
script: |
|
|
const prNumber = parseInt(process.env.PROPOSAL_NUMBER, 10);
|
|
|
|
if (prNumber) {
|
|
// Get PR details to find the branch
|
|
const pr = await github.rest.pulls.get({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: prNumber
|
|
});
|
|
|
|
const branchName = pr.data.head.ref;
|
|
|
|
// Remove in-progress label
|
|
try {
|
|
await github.rest.issues.removeLabel({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
name: 'release-in-progress'
|
|
});
|
|
} catch (e) {
|
|
console.log('Label not found:', e.message);
|
|
}
|
|
|
|
// Add released label
|
|
await github.rest.issues.addLabels({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
labels: ['released']
|
|
});
|
|
|
|
// Add final comment
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
body: '## ✅ Release Published\n\nThe release has been successfully published and is now available.'
|
|
});
|
|
|
|
// Close the PR if it's still open
|
|
if (pr.data.state === 'open') {
|
|
await github.rest.pulls.update({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: prNumber,
|
|
state: 'closed'
|
|
});
|
|
console.log(`Closed PR #${prNumber}`);
|
|
}
|
|
|
|
// Delete the branch
|
|
try {
|
|
await github.rest.git.deleteRef({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
ref: `heads/${branchName}`
|
|
});
|
|
console.log(`Deleted branch: ${branchName}`);
|
|
} catch (e) {
|
|
console.log(`Could not delete branch ${branchName}: ${e.message}`);
|
|
}
|
|
}
|