mirror of
https://github.com/caddyserver/caddy.git
synced 2026-04-08 18:21:58 -04:00
544 lines
22 KiB
YAML
544 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
|
|
# environment: 'default'
|
|
|
|
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 || '' }}
|
|
|
|
steps:
|
|
- name: Harden the runner (Audit all outbound calls)
|
|
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
|
with:
|
|
egress-policy: audit
|
|
- name: Checkout code
|
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
with:
|
|
fetch-depth: 0
|
|
# Force fetch upstream tags -- because 65 minutes
|
|
# tl;dr: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 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
|
|
|
|
- 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 "::set-output name=version_tag::${GITHUB_REF/refs\/tags\//}"
|
|
echo "::set-output name=short_sha::$(git rev-parse --short HEAD)"
|
|
|
|
# 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 "::set-output name=tag_major::${TAG_MAJOR}"
|
|
echo "::set-output name=tag_minor::${TAG_MINOR}"
|
|
echo "::set-output name=tag_patch::${TAG_PATCH}"
|
|
echo "::set-output name=tag_special::${TAG_SPECIAL}"
|
|
|
|
- name: Validate commits and tag signatures
|
|
id: verify
|
|
env:
|
|
signing_keys: ${{ secrets.SIGNING_KEYS }}
|
|
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"
|
|
# email address, type, public key
|
|
echo "${key_components[0]} namespaces=\"git\" ${key_components[1]} ${key_components[2]}" >> "${{ runner.temp }}/allowed_signers"
|
|
done
|
|
|
|
git config --global gpg.ssh.allowedSignersFile "${{ runner.temp }}/allowed_signers"
|
|
|
|
echo "Verifying the tag: ${{ steps.vars.outputs.version_tag }}"
|
|
|
|
# Verify the tag is signed
|
|
if ! git verify-tag -v "${{ steps.vars.outputs.version_tag }}" 2>&1; then
|
|
echo "❌ Tag verification failed!"
|
|
echo "passed=false" >> $GITHUB_OUTPUT
|
|
git push --delete origin "${{ steps.vars.outputs.version_tag }}"
|
|
exit 1
|
|
fi
|
|
|
|
# Run it again to capture the output
|
|
git verify-tag -v "${{ steps.vars.outputs.version_tag }}" 2>&1 | tee /tmp/verify-output.txt;
|
|
|
|
# Extract SSH key information from verification output
|
|
|
|
# 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 "${{ steps.vars.outputs.version_tag }}"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Tag verification succeeded!"
|
|
echo "SSH Key SHA256: $KEY_SHA256"
|
|
echo "passed=true" >> $GITHUB_OUTPUT
|
|
echo "key_id=$KEY_SHA256" >> $GITHUB_OUTPUT
|
|
|
|
- name: Find related release proposal
|
|
id: find_proposal
|
|
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
|
env:
|
|
MAINTAINER_LOGINS: ${{ secrets.MAINTAINER_LOGINS }}
|
|
with:
|
|
script: |
|
|
const version = '${{ steps.vars.outputs.version_tag }}';
|
|
|
|
// Search for the release proposal issue
|
|
const issues = await github.rest.issues.listForRepo({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
labels: 'release-proposal',
|
|
state: 'open',
|
|
labels: 'release-proposal,needs-approval'
|
|
});
|
|
|
|
const proposal = issues.data.find(issue =>
|
|
issue.title.includes(version)
|
|
);
|
|
|
|
if (!proposal) {
|
|
console.log(`⚠️ No release proposal found for ${version}`);
|
|
console.log('This might be a hotfix or emergency release');
|
|
return { number: null, approved: false, approvals: 0 };
|
|
}
|
|
|
|
// Get reactions to check for approvals (👍 emoji)
|
|
const reactions = await github.rest.reactions.listForIssue({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: proposal.number,
|
|
content: '+1'
|
|
});
|
|
|
|
console.log(`Found proposal #${proposal.number} for version ${version} with ${reactions.data.length} 👍 reactions`);
|
|
|
|
// Extract commit hash from proposal body
|
|
const commitMatch = proposal.body.match(/\*\*Commit:\*\*\s*`([a-f0-9]+)`/);
|
|
const proposedCommit = commitMatch ? commitMatch[1] : null;
|
|
|
|
if (proposedCommit) {
|
|
console.log(`Proposal is for commit: ${proposedCommit}`);
|
|
} else {
|
|
console.log('⚠️ No commit hash found in proposal');
|
|
}
|
|
|
|
// Get maintainer logins from secret (comma or semicolon separated)
|
|
const maintainerLoginsStr = process.env.MAINTAINER_LOGINS || '';
|
|
const maintainerLogins = new Set(
|
|
maintainerLoginsStr
|
|
.split(/[,;]/)
|
|
.map(login => login.trim().toLowerCase())
|
|
.filter(login => login.length > 0)
|
|
);
|
|
|
|
console.log(`Found ${maintainerLogins.size} maintainer logins in secret`);
|
|
|
|
// Count approvals from maintainers
|
|
const maintainerApprovals = reactions.data.filter(reaction =>
|
|
maintainerLogins.has(reaction.user.login.toLowerCase())
|
|
);
|
|
|
|
const approvalCount = maintainerApprovals.length;
|
|
const approved = approvalCount >= 2;
|
|
|
|
console.log(`Found ${approvalCount} maintainer approvals`);
|
|
console.log(`Approved: ${approved}`);
|
|
|
|
return {
|
|
number: proposal.number,
|
|
approved: approved,
|
|
approvals: approvalCount,
|
|
approvers: maintainerApprovals.map(r => '@' + r.user.login).join(', '),
|
|
proposedCommit: proposedCommit
|
|
};
|
|
result-encoding: json
|
|
|
|
- name: Check approval requirements
|
|
run: |
|
|
APPROVALS='${{ steps.find_proposal.outputs.result }}'
|
|
|
|
# Parse JSON
|
|
APPROVED=$(echo "$APPROVALS" | jq -r '.approved')
|
|
COUNT=$(echo "$APPROVALS" | jq -r '.approvals')
|
|
APPROVERS=$(echo "$APPROVALS" | jq -r '.approvers')
|
|
PROPOSED_COMMIT=$(echo "$APPROVALS" | jq -r '.proposedCommit')
|
|
CURRENT_COMMIT="${{ steps.info.outputs.sha }}"
|
|
|
|
echo "Approval status: $APPROVED"
|
|
echo "Approval count: $COUNT"
|
|
echo "Approvers: $APPROVERS"
|
|
echo "Proposed commit: $PROPOSED_COMMIT"
|
|
echo "Current commit: $CURRENT_COMMIT"
|
|
|
|
# Check if commits match
|
|
if [ "$PROPOSED_COMMIT" != "null" ] && [ "$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 the code has changed since the proposal was created."
|
|
# delete the tag
|
|
git push --delete origin "${{ steps.vars.outputs.version_tag }}"
|
|
echo "Tag ${{steps.vars.outputs.version_tag}} has been deleted"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$PROPOSED_COMMIT" != "null" ]; then
|
|
echo "✅ Commit hash matches proposal"
|
|
fi
|
|
|
|
if [ "$APPROVED" != "true" ]; then
|
|
echo "❌ Release does not have minimum 2 maintainer approvals"
|
|
echo "Current approvals: $COUNT"
|
|
# Delete the tag remotely
|
|
git push --delete origin "${{ steps.vars.outputs.version_tag }}"
|
|
|
|
echo "Tag ${{steps.vars.outputs.version_tag}} has been deleted"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Release has sufficient approvals"
|
|
|
|
- name: Update release proposal
|
|
if: steps.find_proposal.outputs.result != 'null'
|
|
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
|
with:
|
|
script: |
|
|
const result = ${{ steps.find_proposal.outputs.result }};
|
|
|
|
if (result.number) {
|
|
const commentBody = [
|
|
'## ✅ Release Tag Created and Verified',
|
|
'',
|
|
'- **Tag:** ${{ steps.info.outputs.version }}',
|
|
'- **SSH Key SHA256:** ${{ steps.verify.outputs.key_id }}',
|
|
`- **Approvals:** ${result.approvals} maintainers (${result.approvers})`,
|
|
'- **Commit:** ${{ steps.info.outputs.sha }}',
|
|
'',
|
|
'Release workflow is now running. This issue will be closed 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
|
|
});
|
|
|
|
// remove earlier labels
|
|
await github.rest.issues.removeLabel({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: result.number,
|
|
name: 'needs-approval'
|
|
});
|
|
await github.rest.issues.removeLabel({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: result.number,
|
|
name: 'release-proposal'
|
|
});
|
|
|
|
// add 'release-in-progress' label
|
|
await github.rest.issues.addLabels({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: result.number,
|
|
labels: ['release-in-progress']
|
|
});
|
|
}
|
|
|
|
- name: Summary
|
|
run: |
|
|
APPROVALS='${{ steps.find_proposal.outputs.result }}'
|
|
PROPOSED_COMMIT=$(echo "$APPROVALS" | jq -r '.proposedCommit // "N/A"')
|
|
|
|
echo "## Tag Verification Summary 🔐" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **Tag:** ${{ steps.info.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **Commit:** ${{ steps.info.outputs.sha }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **Proposed Commit:** $PROPOSED_COMMIT" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **Signature:** ✅ Verified" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **SSH Key SHA256:** ${{ steps.verify.outputs.key_id }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **Approvals:** ✅ Sufficient" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
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.25'
|
|
|
|
include:
|
|
# Set the minimum Go patch version for the given Go minor
|
|
# Usable via ${{ matrix.GO_SEMVER }}
|
|
- go: '1.25'
|
|
GO_SEMVER: '~1.25.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
|
|
|
|
steps:
|
|
- name: Harden the runner (Audit all outbound calls)
|
|
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout code
|
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Install Go
|
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
|
with:
|
|
go-version: ${{ matrix.GO_SEMVER }}
|
|
check-latest: true
|
|
|
|
# Force fetch upstream tags -- because 65 minutes
|
|
# tl;dr: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 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@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # main
|
|
- name: Cosign version
|
|
run: cosign version
|
|
- name: Install Syft
|
|
uses: anchore/sbom-action/download-syft@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # main
|
|
- name: Syft version
|
|
run: syft version
|
|
- name: Install xcaddy
|
|
run: |
|
|
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
|
|
xcaddy version
|
|
# GoReleaser will take care of publishing those artifacts into the release
|
|
- name: Run GoReleaser
|
|
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
|
|
with:
|
|
version: latest
|
|
args: release --clean --timeout 60m
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
TAG: ${{ steps.vars.outputs.version_tag }}
|
|
COSIGN_EXPERIMENTAL: 1
|
|
|
|
# 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: Close release proposal issue
|
|
if: needs.verify-tag.outputs.proposal_issue_number != ''
|
|
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
|
with:
|
|
script: |
|
|
const issueNumber = parseInt('${{ needs.verify-tag.outputs.proposal_issue_number }}');
|
|
|
|
if (issueNumber) {
|
|
// Add final comment
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: issueNumber,
|
|
body: '## ✅ Release Published\n\nThe release has been successfully published. Closing this proposal.'
|
|
});
|
|
|
|
// Remove the release-in-progress label
|
|
try {
|
|
await github.rest.issues.removeAllLabels({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: issueNumber
|
|
});
|
|
} catch (error) {
|
|
console.log('Label might not exist on issue');
|
|
}
|
|
|
|
// Close the issue
|
|
await github.rest.issues.update({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: issueNumber,
|
|
state: 'closed',
|
|
state_reason: 'completed'
|
|
});
|
|
|
|
console.log(`Closed issue #${issueNumber}`);
|
|
}
|