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 with: fetch-depth: 0 # Fetch all history for tags - name: Fetch all tags run: git fetch --tags --force - 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<> $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}..." # Write release notes directly from GitHub output to file # This avoids bash interpreting backticks in the markdown NOTES_FILE=$(mktemp) cat <<'NOTES_EOF' > "$NOTES_FILE" ${{ steps.generate_notes.outputs.RELEASE_NOTES }} NOTES_EOF # Create draft release with generated notes gh release create "${TAG}" \ --draft \ --title "Pulse ${TAG}" \ --notes-file "$NOTES_FILE" rm -f "$NOTES_FILE" echo "release_url=$(gh release view ${TAG} --json url -q .url)" >> $GITHUB_OUTPUT echo "tag=${TAG}" >> $GITHUB_OUTPUT - name: Upload checksums.txt env: GH_TOKEN: ${{ github.token }} run: | TAG="${{ steps.create_release.outputs.tag }}" echo "Uploading checksums.txt..." gh release upload "${TAG}" release/checksums.txt # Upload individual .sha256 files for backward compatibility echo "Uploading .sha256 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 - 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 ""