mirror of
https://github.com/fosrl/newt.git
synced 2026-03-26 12:36:45 +00:00
213 lines
6.9 KiB
YAML
213 lines
6.9 KiB
YAML
name: CI/CD Pipeline
|
|
|
|
permissions:
|
|
contents: write # gh-release
|
|
packages: write # GHCR push
|
|
id-token: write # Keyless-Signatures & Attestations
|
|
attestations: write # actions/attest-build-provenance
|
|
security-events: write # upload-sarif
|
|
actions: read
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "[0-9]+.[0-9]+.[0-9]+"
|
|
- "[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+"
|
|
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: "SemVer version to release (e.g., 1.2.3, no leading 'v')"
|
|
required: true
|
|
type: string
|
|
target_branch:
|
|
description: "Branch to tag"
|
|
required: false
|
|
default: "main"
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
prepare:
|
|
if: github.event_name == 'workflow_dispatch'
|
|
name: Prepare release (create tag)
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Validate version input
|
|
shell: bash
|
|
env:
|
|
INPUT_VERSION: ${{ inputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
if ! [[ "$INPUT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]]; then
|
|
echo "Invalid version: $INPUT_VERSION (expected X.Y.Z or X.Y.Z-rc.N)" >&2
|
|
exit 1
|
|
fi
|
|
- name: Create and push tag
|
|
shell: bash
|
|
env:
|
|
TARGET_BRANCH: ${{ inputs.target_branch }}
|
|
VERSION: ${{ inputs.version }}
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
git fetch --prune origin
|
|
git checkout "$TARGET_BRANCH"
|
|
git pull --ff-only origin "$TARGET_BRANCH"
|
|
if git rev-parse -q --verify "refs/tags/$VERSION" >/dev/null; then
|
|
echo "Tag $VERSION already exists" >&2
|
|
exit 1
|
|
fi
|
|
git tag -a "$VERSION" -m "Release $VERSION"
|
|
git push origin "refs/tags/$VERSION"
|
|
release:
|
|
if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.actor != 'github-actions[bot]') }}
|
|
name: Build and Release
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 120
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Extract tag name
|
|
env:
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
INPUT_VERSION: ${{ inputs.version }}
|
|
run: |
|
|
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
|
|
echo "TAG=${INPUT_VERSION}" >> $GITHUB_ENV
|
|
else
|
|
echo "TAG=${{ github.ref_name }}" >> $GITHUB_ENV
|
|
fi
|
|
shell: bash
|
|
|
|
- name: Validate pushed tag format (no leading 'v')
|
|
if: ${{ github.event_name == 'push' }}
|
|
shell: bash
|
|
env:
|
|
TAG_GOT: ${{ env.TAG }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ "$TAG_GOT" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]]; then
|
|
echo "Tag OK: $TAG_GOT"
|
|
exit 0
|
|
fi
|
|
echo "ERROR: Tag '$TAG_GOT' is not allowed. Use 'X.Y.Z' or 'X.Y.Z-rc.N' (no leading 'v')." >&2
|
|
exit 1
|
|
- name: Wait for tag to be visible (dispatch only)
|
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
run: |
|
|
set -euo pipefail
|
|
for i in {1..90}; do
|
|
if git ls-remote --tags origin "refs/tags/${TAG}" | grep -qE "refs/tags/${TAG}$"; then
|
|
echo "Tag ${TAG} is visible on origin"; exit 0
|
|
fi
|
|
echo "Tag not yet visible, retrying... ($i/90)"
|
|
sleep 2
|
|
done
|
|
echo "Tag ${TAG} not visible after waiting"; exit 1
|
|
shell: bash
|
|
|
|
- name: Update version in main.go
|
|
run: |
|
|
TAG=${{ env.TAG }}
|
|
if [ -f main.go ]; then
|
|
sed -i 's/version_replaceme/'"$TAG"'/' main.go
|
|
echo "Updated main.go with version $TAG"
|
|
else
|
|
echo "main.go not found"
|
|
fi
|
|
|
|
- name: Ensure repository is at the tagged commit (dispatch only)
|
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
run: |
|
|
set -euo pipefail
|
|
git fetch --tags --force
|
|
git checkout "refs/tags/${TAG}"
|
|
echo "Checked out $(git rev-parse --short HEAD) for tag ${TAG}"
|
|
shell: bash
|
|
|
|
- name: Detect release candidate (rc)
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ "${TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
|
|
echo "IS_RC=true" >> $GITHUB_ENV
|
|
else
|
|
echo "IS_RC=false" >> $GITHUB_ENV
|
|
fi
|
|
shell: bash
|
|
|
|
- name: Install Go
|
|
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
|
with:
|
|
go-version-file: go.mod
|
|
|
|
- name: Cache Go modules
|
|
if: ${{ hashFiles('**/go.sum') != '' }}
|
|
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
|
|
with:
|
|
path: |
|
|
~/.cache/go-build
|
|
~/go/pkg/mod
|
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-go-
|
|
- name: Go vet & test
|
|
if: ${{ hashFiles('**/go.mod') != '' }}
|
|
run: |
|
|
go version
|
|
go vet ./...
|
|
go test ./... -race -covermode=atomic
|
|
shell: bash
|
|
|
|
# - name: Trivy scan (GHCR image)
|
|
# id: trivy
|
|
# uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # v0.33.1
|
|
# with:
|
|
# image-ref: ${{ env.GHCR_IMAGE }}@${{ steps.build.outputs.digest }}
|
|
# format: sarif
|
|
# output: trivy-ghcr.sarif
|
|
# ignore-unfixed: true
|
|
# vuln-type: os,library
|
|
# severity: CRITICAL,HIGH
|
|
# exit-code: ${{ (vars.TRIVY_FAIL || '0') }}
|
|
|
|
# - name: Upload SARIF,trivy
|
|
# if: ${{ always() && hashFiles('trivy-ghcr.sarif') != '' }}
|
|
# uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
|
|
# with:
|
|
# sarif_file: trivy-ghcr.sarif
|
|
# category: Image Vulnerability Scan
|
|
|
|
#- name: Build binaries
|
|
# env:
|
|
# CGO_ENABLED: "0"
|
|
# GOFLAGS: "-trimpath"
|
|
# run: |
|
|
# set -euo pipefail
|
|
# TAG_VAR="${TAG}"
|
|
# make -j 10 go-build-release tag=$TAG_VAR
|
|
# shell: bash
|
|
|
|
- name: Run GoReleaser (binaries + deb/rpm/apk)
|
|
uses: goreleaser/goreleaser-action@v6
|
|
with:
|
|
version: latest
|
|
args: release --clean
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|