diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index e7653ca..b6606cf 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -11,14 +11,10 @@ concurrency: cancel-in-progress: true jobs: - check-and-create-nightly: + check-commits: runs-on: ubuntu-latest - permissions: - contents: write outputs: - nightly_version: ${{ env.NIGHTLY_VERSION }} - skip_nightly: ${{ env.SKIP_NIGHTLY }} - changelog_body: ${{ env.CHANGELOG_BODY }} + skip_nightly: ${{ steps.check.outputs.skip_nightly }} steps: - name: Checkout code uses: actions/checkout@v6 @@ -26,7 +22,7 @@ jobs: fetch-depth: 0 - name: Check for unreleased commits - id: check_commits + id: check run: | # Find the latest release tag (any x.y.z release) LATEST_RELEASE=$(git tag -l 'v*.*.*' --sort=-version:refname | grep -v 'prerelease' | grep -v '^nightly' | head -n1) @@ -34,18 +30,16 @@ jobs: if [ -z "$LATEST_RELEASE" ]; then echo "No existing releases found, creating first nightly" COMMITS_SINCE_RELEASE=$(git rev-list HEAD --count) - LATEST_RELEASE_COMMIT="" else echo "Latest release: $LATEST_RELEASE" COMMITS_SINCE_RELEASE=$(git rev-list ${LATEST_RELEASE}..HEAD --count) - LATEST_RELEASE_COMMIT="$LATEST_RELEASE" fi echo "Commits since latest release: $COMMITS_SINCE_RELEASE" if [ "$COMMITS_SINCE_RELEASE" -eq "0" ]; then echo "No new commits since latest release, skipping nightly" - echo "SKIP_NIGHTLY=true" >> "$GITHUB_ENV" + echo "skip_nightly=true" >> "$GITHUB_OUTPUT" exit 0 fi @@ -59,31 +53,26 @@ jobs: if [ "$EXISTING_NIGHTLY_COMMIT" = "$CURRENT_COMMIT" ]; then echo "Nightly release already exists for current commit" - echo "SKIP_NIGHTLY=true" >> "$GITHUB_ENV" + echo "skip_nightly=true" >> "$GITHUB_OUTPUT" exit 0 fi - # Use fixed nightly tag name - NIGHTLY_VERSION="nightly" - echo "NIGHTLY_VERSION=$NIGHTLY_VERSION" >> "$GITHUB_ENV" - echo "Creating nightly release: $NIGHTLY_VERSION" - - - name: Extract changelog for nightly - id: changelog - if: env.SKIP_NIGHTLY != 'true' - run: | - # Extract the Unreleased section from CHANGELOG.md using make target - CHANGELOG_CONTENT=$(make extract-changelog-unreleased) + echo "skip_nightly=false" >> "$GITHUB_OUTPUT" - # Save to environment variable, handling multiline content - { - echo 'CHANGELOG_BODY<> "$GITHUB_ENV" + nightly-release: + needs: check-commits + if: needs.check-commits.outputs.skip_nightly != 'true' + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write # Permission for keyless signing + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Delete existing nightly release and tag - if: env.SKIP_NIGHTLY != 'true' run: | # Delete existing nightly release if it exists if gh release view nightly >/dev/null 2>&1; then @@ -95,44 +84,11 @@ jobs: if git rev-parse --verify nightly >/dev/null 2>&1; then echo "Deleting existing nightly tag" git tag -d nightly - if ! git push origin :refs/tags/nightly; then - echo "Warning: Failed to delete remote nightly tag" >&2 - exit 1 - fi + git push origin :refs/tags/nightly 2>/dev/null || true fi env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Create nightly release - if: env.SKIP_NIGHTLY != 'true' - run: | - VERSION="${{ env.NIGHTLY_VERSION }}" - CURRENT_DATE=$(date -u +%Y-%m-%d) - SHORT_COMMIT=$(git rev-parse --short HEAD) - - echo "Creating nightly release: $VERSION" - gh release create "$VERSION" \ - --title "Nightly Release ($CURRENT_DATE - $SHORT_COMMIT)" \ - --notes "${{ env.CHANGELOG_BODY }}" \ - --prerelease - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - build-and-upload: - needs: check-and-create-nightly - if: needs.check-and-create-nightly.outputs.skip_nightly != 'true' - runs-on: ubuntu-latest - permissions: - contents: write - id-token: write # Permission for keyless signing - strategy: - matrix: - goos: [linux, windows, darwin] - goarch: [amd64, arm64] - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Set up Go uses: actions/setup-go@v6 with: @@ -141,19 +97,10 @@ jobs: - name: Install cosign uses: sigstore/cosign-installer@v4.0.0 - - name: Build release artifacts - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - run: make build-release package-release - - - name: Sign release artifacts - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - run: make sign-release - - - name: Upload assets to nightly release - run: make upload-release-assets VERSION="${{ needs.check-and-create-nightly.outputs.nightly_version }}" + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: '~> v2' + args: release --nightly --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/prerelease.yaml b/.github/workflows/prerelease.yaml index 4dfe1c9..686b3df 100644 --- a/.github/workflows/prerelease.yaml +++ b/.github/workflows/prerelease.yaml @@ -12,97 +12,27 @@ on: type: string jobs: - determine-version: + prerelease: runs-on: ubuntu-latest permissions: contents: write - outputs: - prerelease_version: ${{ env.PRERELEASE_VERSION }} - changelog_body: ${{ env.CHANGELOG_BODY }} + id-token: write # Permission for keyless signing steps: - name: Checkout code uses: actions/checkout@v6 with: fetch-depth: 0 + ref: ${{ inputs.tag || '' }} - - name: Extract version from tag - id: get_version + - name: Validate prerelease tag run: | - # Get version from tag (either from push event or manual input) if [ "${{ github.event_name }}" = "push" ]; then VERSION="${{ github.ref_name }}" else VERSION="${{ inputs.tag }}" fi - - # Validate version format using make target make validate-prerelease-tag VERSION="$VERSION" - echo "PRERELEASE_VERSION=$VERSION" >> "$GITHUB_ENV" - echo "Pre-release version: $VERSION" - - - name: Extract changelog - id: changelog - run: | - VERSION="${{ env.PRERELEASE_VERSION }}" - # Extract the base release version (without -rc.N suffix) - RELEASE_VERSION=$(echo "$VERSION" | sed 's/-rc\.[0-9]*$//') - - # Extract changelog using make target (tries version-specific, then unreleased) - CHANGELOG_CONTENT=$(make extract-changelog-version VERSION="$RELEASE_VERSION" 2>/dev/null || echo "Pre-release build for ${RELEASE_VERSION}. See CHANGELOG.md for details.") - - # Save to environment variable, handling multiline content - { - echo 'CHANGELOG_BODY<> "$GITHUB_ENV" - - - name: Create or update pre-release - run: | - VERSION="${{ env.PRERELEASE_VERSION }}" - - # Check if release already exists - if gh release view "$VERSION" >/dev/null 2>&1; then - echo "Pre-release $VERSION already exists, checking if changelog needs to be updated..." - - # Get current release notes - CURRENT_NOTES=$(gh release view "$VERSION" --json body -q .body) - - # Check if changelog content is already in the notes - if echo "$CURRENT_NOTES" | grep -qF "${{ env.CHANGELOG_BODY }}"; then - echo "Changelog already present in release notes, skipping update..." - else - echo "Appending changelog to existing release notes..." - NEW_NOTES="${CURRENT_NOTES}\n\n---\n\n${{ env.CHANGELOG_BODY }}" - gh release edit "$VERSION" --notes "$NEW_NOTES" - fi - else - echo "Creating pre-release $VERSION..." - gh release create "$VERSION" \ - --title "$VERSION" \ - --notes "${{ env.CHANGELOG_BODY }}" \ - --prerelease - fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - build-and-upload: - needs: determine-version - runs-on: ubuntu-latest - permissions: - contents: write - id-token: write # Permission for keyless signing - strategy: - matrix: - goos: [linux, windows, darwin] - goarch: [amd64, arm64] - steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - name: Set up Go uses: actions/setup-go@v6 with: @@ -111,20 +41,10 @@ jobs: - name: Install cosign uses: sigstore/cosign-installer@v4.0.0 - - name: Build release artifacts - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - VERSION: ${{ needs.determine-version.outputs.prerelease_version }} - run: make build-release package-release - - - name: Sign release artifacts - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - run: make sign-release - - - name: Upload assets to release - run: make upload-release-assets VERSION="${{ needs.determine-version.outputs.prerelease_version }}" + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: '~> v2' + args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3234dc7..c0612ca 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,127 +13,42 @@ on: type: string jobs: - determine-version: + release: runs-on: ubuntu-latest permissions: contents: write - outputs: - version: ${{ env.VERSION }} - changelog_body: ${{ env.CHANGELOG_BODY }} + id-token: write # Permission for keyless signing steps: - name: Checkout code uses: actions/checkout@v6 with: fetch-depth: 0 + ref: ${{ inputs.tag || '' }} - - name: Extract version from tag - id: get_version + - name: Validate release tag run: | - # Get version from tag (either from push event or manual input) if [ "${{ github.event_name }}" = "push" ]; then VERSION="${{ github.ref_name }}" else VERSION="${{ inputs.tag }}" fi - - # Validate version format using make target make validate-release-tag VERSION="$VERSION" - echo "VERSION=$VERSION" >> "$GITHUB_ENV" - echo "Release version: $VERSION" - - - name: Validate CHANGELOG has version section - run: make validate-changelog-has-version VERSION="${{ env.VERSION }}" - - name: Set up Go uses: actions/setup-go@v6 with: go-version-file: 'go.mod' - - name: Extract changelog for release - id: changelog - run: | - VERSION="${{ env.VERSION }}" - # Extract the specific version section from CHANGELOG.md using make target - CHANGELOG_CONTENT=$(make extract-changelog-version VERSION="$VERSION") - - # Save to environment variable, handling multiline content - { - echo 'CHANGELOG_BODY<> "$GITHUB_ENV" - - name: Run tests run: make test - - name: Create or update release - run: | - VERSION="${{ env.VERSION }}" - - # Check if release already exists - if gh release view "$VERSION" >/dev/null 2>&1; then - echo "Release $VERSION already exists, checking if changelog needs to be updated..." - - # Get current release notes - CURRENT_NOTES=$(gh release view "$VERSION" --json body -q .body) - - # Check if changelog content is already in the notes - if echo "$CURRENT_NOTES" | grep -qF "${{ env.CHANGELOG_BODY }}"; then - echo "Changelog already present in release notes, skipping update..." - else - echo "Appending changelog to existing release notes..." - NEW_NOTES="${CURRENT_NOTES}\n\n---\n\n${{ env.CHANGELOG_BODY }}" - gh release edit "$VERSION" --notes "$NEW_NOTES" - fi - else - echo "Creating release $VERSION..." - gh release create "$VERSION" \ - --title "$VERSION" \ - --notes "${{ env.CHANGELOG_BODY }}" \ - --latest - fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - build-and-upload: - needs: determine-version - runs-on: ubuntu-latest - permissions: - contents: write - id-token: write # Permission for keyless signing - strategy: - matrix: - goos: [linux, windows, darwin] - goarch: [amd64, arm64] - steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' - - name: Install cosign uses: sigstore/cosign-installer@v4.0.0 - - name: Build release artifacts - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - VERSION: ${{ needs.determine-version.outputs.version }} - run: make build-release package-release - - - name: Sign release artifacts - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - run: make sign-release - - - name: Upload assets to release - run: make upload-release-assets VERSION="${{ needs.determine-version.outputs.version }}" + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: '~> v2' + args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..c2d826d --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,45 @@ +version: 2 + +builds: + - main: ./cmd + binary: "kubernetes-extension-{{ .Os }}-{{ .Arch }}" + flags: + - -trimpath + ldflags: + - -s -w + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + +archives: + - format: zip + name_template: "kubernetes-extension-{{ .Os }}-{{ .Arch }}" + +signs: + - cmd: cosign + artifacts: archive + signature: "${artifact}.bundle" + args: + - sign-blob + - --yes + - "${artifact}" + - --bundle + - "${signature}" + +release: + prerelease: auto + +nightly: + tag_name: nightly + name_template: "Nightly Release ({{ .Date }} - {{ .ShortCommit }})" + keep_single_release: true + publish_release: true + +changelog: + sort: asc diff --git a/Makefile b/Makefile index 8e6cf3f..193118c 100644 --- a/Makefile +++ b/Makefile @@ -26,77 +26,7 @@ build-release: fi @echo "Build complete!" -.PHONY: package-release -package-release: - @echo "Packaging release artifacts for $(GOOS)/$(GOARCH)..." - @cd dist && \ - if [ "$(GOOS)" = "windows" ]; then \ - zip "$(BINARY_NAME)-$(GOOS)-$(GOARCH).zip" "$(BINARY_NAME)-$(GOOS)-$(GOARCH).exe"; \ - else \ - zip "$(BINARY_NAME)-$(GOOS)-$(GOARCH).zip" "$(BINARY_NAME)-$(GOOS)-$(GOARCH)"; \ - fi - @echo "Packaging complete!" - -.PHONY: sign-release -sign-release: - @echo "Signing release artifacts for $(GOOS)/$(GOARCH)..." - @cd dist && \ - cosign sign-blob --yes "$(BINARY_NAME)-$(GOOS)-$(GOARCH).zip" \ - --bundle "$(BINARY_NAME)-$(GOOS)-$(GOARCH).zip.bundle" - @echo "Signing complete!" - -.PHONY: release -release: build-release package-release sign-release - @echo "Release build complete for $(GOOS)/$(GOARCH)!" - -# Changelog parsing pipeline: removes section boundaries, formats sections with their items -define CHANGELOG_PIPELINE -sed '$$d' | tail -n +2 | sed -e '$$G' | awk '/^### /{section=$$0; items=""; next} /^( *)?- /{items=items $$0 "\n"; next} /^$$/ && items{print section "\n" items; items=""}' | sed '/^$$/d' -endef - -# Changelog extraction targets -.PHONY: extract-changelog-unreleased -extract-changelog-unreleased: - @echo "Extracting unreleased changelog section..." >&2 - @CHANGELOG_CONTENT=$$(sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | $(CHANGELOG_PIPELINE)); \ - if [ -z "$$CHANGELOG_CONTENT" ]; then \ - CHANGELOG_CONTENT="See CHANGELOG.md for details."; \ - fi; \ - printf '%s\n' "$$CHANGELOG_CONTENT" - -.PHONY: extract-changelog-version -extract-changelog-version: - @if [ -z "$(VERSION)" ]; then \ - echo "Error: VERSION is required. Usage: make extract-changelog-version VERSION=v1.0.0"; \ - exit 1; \ - fi - @echo "Extracting changelog for version $(VERSION)..." >&2 - @VERSION_NO_V=$$(echo "$(VERSION)" | sed 's/^v//'); \ - CHANGELOG_CONTENT=$$(sed -n "/## \[$${VERSION_NO_V}\]/,/## \[/p" CHANGELOG.md | $(CHANGELOG_PIPELINE)); \ - if [ -z "$$CHANGELOG_CONTENT" ]; then \ - CHANGELOG_CONTENT=$$(sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | $(CHANGELOG_PIPELINE)); \ - fi; \ - if [ -z "$$CHANGELOG_CONTENT" ]; then \ - CHANGELOG_CONTENT="See CHANGELOG.md for details."; \ - fi; \ - printf '%s\n' "$$CHANGELOG_CONTENT" - # Version validation targets -.PHONY: validate-version-tag -validate-version-tag: - @if [ -z "$(VERSION)" ]; then \ - echo "Error: VERSION is required. Usage: make validate-version-tag VERSION=v1.0.0"; \ - exit 1; \ - fi - @echo "Validating version tag format: $(VERSION)" - @if echo "$(VERSION)" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$$'; then \ - echo "✓ Version tag $(VERSION) is valid"; \ - else \ - echo "✗ Error: Version tag must match format 'vX.Y.Z' or 'vX.Y.Z-rc.N'"; \ - echo " Got: $(VERSION)"; \ - exit 1; \ - fi - .PHONY: validate-release-tag validate-release-tag: @if [ -z "$(VERSION)" ]; then \ @@ -126,41 +56,3 @@ validate-prerelease-tag: echo " Got: $(VERSION)"; \ exit 1; \ fi - -.PHONY: validate-changelog-has-version -validate-changelog-has-version: - @if [ -z "$(VERSION)" ]; then \ - echo "Error: VERSION is required. Usage: make validate-changelog-has-version VERSION=v1.0.0"; \ - exit 1; \ - fi - @VERSION_NO_V=$$(echo "$(VERSION)" | sed 's/^v//'); \ - echo "Checking if CHANGELOG.md contains section for version $${VERSION_NO_V}..."; \ - if grep -q "## \[$${VERSION_NO_V}\]" CHANGELOG.md; then \ - echo "✓ CHANGELOG.md contains section for version $${VERSION_NO_V}"; \ - else \ - echo "✗ Error: CHANGELOG.md must contain a section for version $${VERSION_NO_V}"; \ - echo " Expected format: ## [$${VERSION_NO_V}]"; \ - echo " Current CHANGELOG sections:"; \ - grep "^## \[" CHANGELOG.md || echo " No version sections found"; \ - exit 1; \ - fi - -# Release management targets -.PHONY: upload-release-assets -upload-release-assets: - @if [ -z "$(VERSION)" ]; then \ - echo "Error: VERSION is required. Usage: make upload-release-assets VERSION=v1.0.0"; \ - exit 1; \ - fi - @if [ -z "$(GITHUB_TOKEN)" ]; then \ - echo "Error: GITHUB_TOKEN environment variable is required"; \ - exit 1; \ - fi - @echo "Uploading release assets for $(VERSION)..." - @for file in dist/*.zip dist/*.bundle; do \ - if [ -f "$$file" ]; then \ - echo "Uploading $$file..."; \ - gh release upload "$(VERSION)" "$$file" --clobber; \ - fi; \ - done - @echo "✓ All assets uploaded successfully"