Just use the latest tag directly instead of trying to exclude the current version. Since we're generating release notes BEFORE creating the tag, the latest tag will always be the previous release.
291 lines
11 KiB
YAML
291 lines
11 KiB
YAML
name: Release
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: 'Version number (e.g., 4.28.1)'
|
|
required: true
|
|
type: string
|
|
|
|
jobs:
|
|
build-docker-images:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 60
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
outputs:
|
|
tag: ${{ steps.set_version.outputs.tag }}
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set version output
|
|
id: set_version
|
|
run: |
|
|
VERSION="${{ inputs.version }}"
|
|
TAG="v${VERSION}"
|
|
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
|
echo "Building Docker images for ${TAG}..."
|
|
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKER_USERNAME }}
|
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
|
|
- name: Log in to GHCR
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Build and push Pulse server image
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
platforms: linux/amd64,linux/arm64
|
|
push: true
|
|
provenance: false
|
|
tags: |
|
|
rcourtman/pulse:latest
|
|
rcourtman/pulse:${{ steps.set_version.outputs.tag }}
|
|
ghcr.io/${{ github.repository_owner }}/pulse:latest
|
|
ghcr.io/${{ github.repository_owner }}/pulse:${{ steps.set_version.outputs.tag }}
|
|
labels: |
|
|
org.opencontainers.image.title=Pulse
|
|
org.opencontainers.image.description=Proxmox monitoring system
|
|
org.opencontainers.image.version=${{ steps.set_version.outputs.tag }}
|
|
org.opencontainers.image.created=${{ github.event.repository.updated_at }}
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
|
|
org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }}
|
|
org.opencontainers.image.licenses=MIT
|
|
|
|
- name: Build and push Docker agent image
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
file: ./Dockerfile
|
|
target: agent_runtime
|
|
platforms: linux/amd64,linux/arm64
|
|
push: true
|
|
provenance: false
|
|
tags: |
|
|
rcourtman/pulse-docker-agent:latest
|
|
rcourtman/pulse-docker-agent:${{ steps.set_version.outputs.tag }}
|
|
ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:latest
|
|
ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${{ steps.set_version.outputs.tag }}
|
|
labels: |
|
|
org.opencontainers.image.title=Pulse Docker Agent
|
|
org.opencontainers.image.description=Docker container monitoring agent for Pulse
|
|
org.opencontainers.image.version=${{ steps.set_version.outputs.tag }}
|
|
org.opencontainers.image.created=${{ github.event.repository.updated_at }}
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
|
|
org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }}
|
|
org.opencontainers.image.licenses=MIT
|
|
|
|
- name: Output Docker image information
|
|
run: |
|
|
echo "✅ Docker images built and pushed successfully!"
|
|
echo ""
|
|
echo "Server images:"
|
|
echo " - rcourtman/pulse:${{ steps.set_version.outputs.tag }}"
|
|
echo " - rcourtman/pulse:latest"
|
|
echo ""
|
|
echo "Agent images:"
|
|
echo " - rcourtman/pulse-docker-agent:${{ steps.set_version.outputs.tag }}"
|
|
echo " - rcourtman/pulse-docker-agent:latest"
|
|
|
|
create-release:
|
|
needs: build-docker-images
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version: '1.24'
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
# Install zip for Windows binaries
|
|
sudo apt-get update
|
|
sudo apt-get install -y zip
|
|
|
|
# Install Helm for chart packaging
|
|
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
|
|
|
- name: Build release artifacts
|
|
run: |
|
|
echo "Building release v${{ inputs.version }}..."
|
|
./scripts/build-release.sh ${{ inputs.version }}
|
|
|
|
- name: Validate release artifacts
|
|
run: |
|
|
echo "Validating release v${{ inputs.version }}..."
|
|
# Note: Docker image validation is skipped in this workflow
|
|
# since we're only validating the built artifacts (tarballs, binaries, checksums)
|
|
# Docker images were built and validated in previous job
|
|
|
|
# Run validation with --skip-docker flag
|
|
./scripts/validate-release.sh ${{ inputs.version }} --skip-docker || {
|
|
echo "❌ Release validation failed!"
|
|
echo "The workflow will now fail. No release will be created."
|
|
exit 1
|
|
}
|
|
|
|
- name: Generate release notes
|
|
id: generate_notes
|
|
env:
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
run: |
|
|
echo "Generating release notes using LLM..."
|
|
|
|
# Find previous release tag (simply get the latest tag)
|
|
PREVIOUS_TAG=$(git tag --sort=-version:refname | head -1)
|
|
|
|
if [ -z "$PREVIOUS_TAG" ]; then
|
|
echo "No previous tag found, comparing with first commit"
|
|
PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD)
|
|
fi
|
|
|
|
echo "Comparing v${{ inputs.version }} with ${PREVIOUS_TAG}..."
|
|
|
|
# Generate notes - script writes output between separator lines
|
|
TEMP_OUTPUT=$(mktemp)
|
|
|
|
# Run script, capture exit code (don't fail immediately)
|
|
set +e
|
|
./scripts/generate-release-notes.sh ${{ inputs.version }} "${PREVIOUS_TAG}" > "$TEMP_OUTPUT" 2>&1
|
|
SCRIPT_EXIT=$?
|
|
set -e
|
|
|
|
if [ $SCRIPT_EXIT -ne 0 ]; then
|
|
echo "❌ Release notes generation failed:"
|
|
cat "$TEMP_OUTPUT"
|
|
rm -f "$TEMP_OUTPUT"
|
|
exit 1
|
|
fi
|
|
|
|
# Extract notes between separator lines (everything between the two ━━━ lines)
|
|
RELEASE_NOTES=$(awk '/^Generated release notes:/{flag=1;next}/^━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━$/{if(flag==1){flag=2}else if(flag==2){flag=3}}flag==2' "$TEMP_OUTPUT")
|
|
|
|
rm -f "$TEMP_OUTPUT"
|
|
|
|
# Save to output (escape for GitHub Actions multiline)
|
|
echo "RELEASE_NOTES<<EOF" >> $GITHUB_OUTPUT
|
|
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
|
|
echo "EOF" >> $GITHUB_OUTPUT
|
|
|
|
echo "✅ Release notes generated successfully"
|
|
|
|
- name: Create draft release
|
|
id: create_release
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
VERSION="${{ inputs.version }}"
|
|
TAG="v${VERSION}"
|
|
|
|
echo "Creating draft release for ${TAG}..."
|
|
|
|
# Use LLM-generated release notes
|
|
NOTES="${{ steps.generate_notes.outputs.RELEASE_NOTES }}"
|
|
|
|
# Create draft release with generated notes
|
|
gh release create "${TAG}" \
|
|
--draft \
|
|
--title "Pulse ${TAG}" \
|
|
--notes "$NOTES"
|
|
|
|
echo "release_url=$(gh release view ${TAG} --json url -q .url)" >> $GITHUB_OUTPUT
|
|
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
|
|
|
- name: Upload checksums.txt first
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
TAG="${{ steps.create_release.outputs.tag }}"
|
|
|
|
echo "Uploading checksums.txt..."
|
|
gh release upload "${TAG}" release/checksums.txt
|
|
|
|
# Also upload individual .sha256 files
|
|
echo "Uploading individual checksum files..."
|
|
gh release upload "${TAG}" release/*.sha256
|
|
|
|
- name: Upload release assets
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
TAG="${{ steps.create_release.outputs.tag }}"
|
|
|
|
echo "Uploading release assets..."
|
|
|
|
# Upload tarballs
|
|
gh release upload "${TAG}" release/*.tar.gz
|
|
|
|
# Upload Windows zip files
|
|
gh release upload "${TAG}" release/*.zip
|
|
|
|
# Upload Helm chart if it exists
|
|
if ls release/*.tgz 1> /dev/null 2>&1; then
|
|
echo "Uploading Helm chart..."
|
|
gh release upload "${TAG}" release/*.tgz
|
|
fi
|
|
|
|
# Upload install.sh
|
|
gh release upload "${TAG}" release/install.sh
|
|
|
|
# Upload standalone binaries (for direct download by installers)
|
|
echo "Uploading standalone binaries..."
|
|
# Upload binaries without .sha256 files (those were already uploaded)
|
|
for file in release/pulse-sensor-proxy-* release/pulse-host-agent-*; do
|
|
if [[ ! "$file" =~ \.sha256$ ]] && [[ ! "$file" =~ \.tar\.gz$ ]] && [[ ! "$file" =~ \.zip$ ]]; then
|
|
gh release upload "${TAG}" "$file"
|
|
fi
|
|
done
|
|
|
|
- name: Output release information
|
|
run: |
|
|
echo "✅ Release draft created successfully!"
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📦 Release: ${{ steps.create_release.outputs.tag }}"
|
|
echo "🔗 URL: ${{ steps.create_release.outputs.release_url }}"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "⚠️ IMPORTANT: This release is in DRAFT status"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo "1. Review the release at the URL above"
|
|
echo "2. Update the release notes with changes since last release"
|
|
echo "3. Publish the release manually when ready"
|
|
echo ""
|
|
echo "All artifacts have been uploaded and validated."
|
|
echo "Docker images are available at Docker Hub and GHCR."
|
|
echo "checksums.txt matches all uploaded binaries."
|
|
echo ""
|