Cosa otterrai
Costruirai una pipeline di release che trasforma un tag Git in un artefatto deployato — firmato, testato, versionato e pubblicato.
Il contratto
- Pushare un tag che corrisponde a
v*.*.*. - CI compila, testa, firma e pubblica.
- Una release GitHub viene creata.
- Il deployment e loggato e verificabile.
Passo 1: convenzioni tag
git tag -a v1.4.0 -m "Release 1.4.0"
git tag -s v1.4.0 -m "Release 1.4.0"
Passo 2: configurare il workflow
# .github/workflows/release.yml
name: release
on:
push:
tags: ['v*.*.*']
permissions:
contents: write
packages: write
id-token: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Passo 3: auto-generare release notes
- name: Generate notes
id: notes
uses: orhun/git-cliff-action@v2
with:
config: cliff.toml
args: --latest --strip header
- name: Create release
uses: softprops/action-gh-release@v2
with:
body: ${{ steps.notes.outputs.content }}
generate_release_notes: true
Passo 4: build matrix per release multi-platform
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- run: cargo build --release
- uses: actions/upload-artifact@v4
with:
name: bin-${{ matrix.os }}
path: target/release/myapp*
Passo 5: artefatti firmati
- uses: sigstore/cosign-installer@v3
- run: |
cosign sign-blob --yes \
--output-certificate cert.pem \
--output-signature sig.bin \
dist/myapp-1.4.0.tgz
Passo 6: release Docker image
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
ghcr.io/${{ github.repository }}:latest
Passo 7: deploy dopo publish
- name: Deploy to production
run: ./scripts/deploy.sh
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
Passo 8: notifica
- name: Slack notify
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Released ${{ github.ref_name }} :rocket:"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Passo 9: canali pre-release
jobs:
release:
steps:
- id: classify
run: |
if [[ "${{ github.ref_name }}" =~ -(alpha|beta|rc) ]]; then
echo "tag=next" >> $GITHUB_OUTPUT
else
echo "tag=latest" >> $GITHUB_OUTPUT
fi
- run: npm publish --tag ${{ steps.classify.outputs.tag }}
Passo 10: integrare con release-please
Combinare bump versione automatizzato con questa pipeline.
Passo 11: taggare lo SHA negli artefatti
- name: Get short SHA
id: vars
run: echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- run: docker build -t myapp:${{ github.ref_name }} -t myapp:${{ steps.vars.outputs.sha }} .
Passo 12: protezione tag
gh api -X POST repos/owner/repo/tags/protection \
-F pattern='v*.*.*'
Insidie comuni
- La pipeline gira su ogni push.
- Force-push di tag dopo release.
- Segreti nei log CI.
- Build da main su tag push.