Skip to content

Create Release (Dry Run) #2

Create Release (Dry Run)

Create Release (Dry Run) #2

name: Create Release
run-name: ${{ inputs.dry_run == true && 'Create Release (Dry Run)' || 'Create Release' }}
on:
workflow_dispatch:
inputs:
target_branch:
description: 'Branch to create release from'
required: false
default: 'main'
type: choice
options:
- dev
- main
release_notes:
description: 'Custom release notes (optional, will auto-generate if empty). Supports markdown formatting (headers, bold, lists, code blocks). Line breaks and long text are supported.'
required: false
type: string
prerelease:
description: 'Mark as pre-release'
required: false
default: false
type: boolean
create_pr_to_main:
description: 'Create PR from dev to main after release (only if target is dev)'
required: false
default: false
type: boolean
dry_run:
description: 'Dry run mode (validate and show what would happen, do not create release/tag)'
required: false
default: false
type: boolean
permissions:
contents: write
pull-requests: write
env:
REGISTRY: quay.io
ORG: ecosystem-appeng
IMAGE_PREFIX: aiobs
jobs:
validate-and-create-release:
name: Validate version and create GitHub release
runs-on: ubuntu-latest
outputs:
release_url: ${{ steps.create_release.outputs.html_url }}
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
ref: ${{ inputs.target_branch }}
fetch-depth: 0
- name: Get version from Makefile
id: get_version
run: |
# Read version from Makefile and add v prefix
MAKEFILE_VERSION=$(grep "^VERSION.*=" Makefile | sed 's/VERSION.*= //' | head -1)
if [ -z "$MAKEFILE_VERSION" ]; then
echo "Error: Makefile does not contain VERSION"
echo "Please ensure the Makefile has a VERSION variable set (e.g., VERSION ?= 1.0.0)"
exit 1
fi
VERSION="v${MAKEFILE_VERSION}"
echo "Version from Makefile: $MAKEFILE_VERSION"
echo "Release version: $VERSION"
# Validate version format
if ! echo "$VERSION" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Error: Version in Makefile must be in format X.Y.Z (e.g., 1.0.0)"
echo "Got: $MAKEFILE_VERSION"
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "version_number=$MAKEFILE_VERSION" >> $GITHUB_OUTPUT
echo "Version format is valid: $VERSION"
- name: Check if tag already exists
run: |
VERSION="${{ steps.get_version.outputs.version }}"
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "Error: Tag $VERSION already exists!"
echo "Please use a different version or delete the existing tag first."
exit 1
fi
echo "Tag $VERSION does not exist, proceeding..."
- name: Verify images exist in registry
run: |
VERSION="${{ steps.get_version.outputs.version }}"
VERSION_NUMBER="${VERSION#v}"
echo "Checking if images exist with tag: $VERSION_NUMBER"
# Note: This is a basic check. For stricter validation, you could use:
# - skopeo inspect docker://$IMAGE_URL
# - curl to query Quay.io API
# For now, we'll rely on the Makefile version check as the source of truth
echo "Images expected at:"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-metrics-alerting:$VERSION_NUMBER"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-mcp-server:$VERSION_NUMBER"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-console-plugin:$VERSION_NUMBER"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-react-ui:$VERSION_NUMBER"
echo ""
echo "Please verify these images exist in Quay.io before proceeding."
- name: Generate release notes
id: release_notes
env:
RELEASE_NOTES: ${{ inputs.release_notes }}
run: |
if [ -n "$RELEASE_NOTES" ]; then
echo "Using custom release notes"
NOTES="$RELEASE_NOTES"
else
echo "Auto-generating release notes from commits"
# Get the last tag
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
echo "No previous tag found, using all commits"
COMMITS=$(git log --pretty=format:"- %s (%h)" --no-merges)
else
echo "Generating notes since last tag: $LAST_TAG"
COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges)
fi
VERSION="${{ steps.get_version.outputs.version }}"
VERSION_NUMBER="${VERSION#v}"
# Build release notes using echo to avoid YAML parsing issues
NOTES_FILE=$(mktemp)
{
echo "## What's Changed"
echo ""
echo "${COMMITS}"
echo ""
echo "## Container Images"
echo ""
echo "All images are available at \`${{ env.REGISTRY }}/${{ env.ORG }}\` with tag \`${VERSION_NUMBER}\`:"
echo ""
echo "- \`${{ env.IMAGE_PREFIX }}-metrics-alerting:${VERSION_NUMBER}\`"
echo "- \`${{ env.IMAGE_PREFIX }}-mcp-server:${VERSION_NUMBER}\`"
echo "- \`${{ env.IMAGE_PREFIX }}-console-plugin:${VERSION_NUMBER}\`"
echo "- \`${{ env.IMAGE_PREFIX }}-react-ui:${VERSION_NUMBER}\`"
echo ""
echo "## Deployment"
echo ""
echo "\`\`\`bash"
echo "# Deploy using Helm"
echo "make install NAMESPACE=your-namespace VERSION=${VERSION_NUMBER}"
echo "\`\`\`"
echo ""
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LAST_TAG}...${VERSION}"
} > "$NOTES_FILE"
NOTES=$(cat "$NOTES_FILE")
rm "$NOTES_FILE"
echo "Release notes generated successfully"
fi
# Save notes to file for create-release action
echo "$NOTES" > release_notes.md
- name: Dry run - show release details
if: ${{ inputs.dry_run }}
run: |
VERSION="${{ steps.get_version.outputs.version }}"
echo "=== DRY RUN MODE ==="
echo "The following release would be created:"
echo ""
echo "Tag: $VERSION"
echo "Release Name: OpenShift AI Observability Summarizer $VERSION"
echo "Target: ${{ inputs.target_branch }}"
echo "Pre-release: ${{ inputs.prerelease }}"
echo ""
echo "Release Notes:"
cat release_notes.md
- name: Set up Docker Buildx
if: ${{ !inputs.dry_run }}
uses: docker/setup-buildx-action@v3
- name: Log in to Quay.io
if: ${{ !inputs.dry_run }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Tag images with v-prefix and latest
if: ${{ !inputs.dry_run }}
run: |
VERSION="${{ steps.get_version.outputs.version }}"
VERSION_NUMBER="${VERSION#v}"
VERSION_WITH_V="$VERSION"
echo "Tagging images with v-prefix (official release) and latest tag"
# Array of image components
COMPONENTS=("metrics-alerting" "mcp-server" "console-plugin" "react-ui")
for COMPONENT in "${COMPONENTS[@]}"; do
IMAGE_BASE="${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-${COMPONENT}"
SOURCE_TAG="${IMAGE_BASE}:${VERSION_NUMBER}"
RELEASE_TAG="${IMAGE_BASE}:${VERSION_WITH_V}"
LATEST_TAG="${IMAGE_BASE}:latest"
echo "Processing ${COMPONENT}..."
echo " Source: ${SOURCE_TAG}"
echo " Creating: ${RELEASE_TAG}"
echo " Creating: ${LATEST_TAG}"
# Pull the source image (already built by build-image job)
docker pull "${SOURCE_TAG}"
# Tag with v-prefix (e.g., v1.0.0) - official release (protected from cleanup)
docker tag "${SOURCE_TAG}" "${RELEASE_TAG}"
docker push "${RELEASE_TAG}"
# Tag with latest
docker tag "${SOURCE_TAG}" "${LATEST_TAG}"
docker push "${LATEST_TAG}"
echo " ✅ ${COMPONENT} tagged successfully"
done
echo "All images tagged with v-prefix and latest"
- name: Dry run - show image tagging details
if: ${{ inputs.dry_run }}
run: |
VERSION="${{ steps.get_version.outputs.version }}"
VERSION_WITH_V="$VERSION"
echo ""
echo "=== IMAGE TAGGING (DRY RUN) ==="
echo "The following image tags would be created:"
echo ""
echo "metrics-alerting:"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-metrics-alerting:${VERSION_WITH_V} (official release - protected)"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-metrics-alerting:latest"
echo ""
echo "mcp-server:"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-mcp-server:${VERSION_WITH_V} (official release - protected)"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-mcp-server:latest"
echo ""
echo "console-plugin:"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-console-plugin:${VERSION_WITH_V} (official release - protected)"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-console-plugin:latest"
echo ""
echo "react-ui:"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-react-ui:${VERSION_WITH_V} (official release - protected)"
echo " - ${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-react-ui:latest"
- name: Create GitHub Release
if: ${{ !inputs.dry_run }}
id: create_release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.get_version.outputs.version }}"
PRERELEASE_FLAG=""
if [ "${{ inputs.prerelease }}" = "true" ]; then
PRERELEASE_FLAG="--prerelease"
fi
RELEASE_URL=$(gh release create "$VERSION" \
--repo "${{ github.repository }}" \
--title "OpenShift AI Observability Summarizer $VERSION" \
--notes-file release_notes.md \
--target "${{ inputs.target_branch }}" \
$PRERELEASE_FLAG)
echo "Release created: $RELEASE_URL"
echo "html_url=$RELEASE_URL" >> $GITHUB_OUTPUT
- name: Summary
run: |
VERSION="${{ steps.get_version.outputs.version }}"
VERSION_NUMBER="${VERSION#v}"
if [ "${{ inputs.dry_run }}" = "true" ]; then
echo "## Dry Run - Release Preview :mag:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "> **This was a DRY RUN - no release or tag was created**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** \`$VERSION\`" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** \`${{ inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Pre-release:** \`${{ inputs.prerelease }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Validation Results" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Version format is valid" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Version matches Makefile" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Tag does not already exist" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Release notes generated" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### What Would Be Created" >> $GITHUB_STEP_SUMMARY
echo "**Release:**" >> $GITHUB_STEP_SUMMARY
echo "- Tag: \`$VERSION\`" >> $GITHUB_STEP_SUMMARY
echo "- Name: OpenShift AI Observability Summarizer $VERSION" >> $GITHUB_STEP_SUMMARY
echo "- Target: \`${{ inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Container Images:**" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-metrics-alerting:$VERSION_NUMBER\`" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-mcp-server:$VERSION_NUMBER\`" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-console-plugin:$VERSION_NUMBER\`" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-react-ui:$VERSION_NUMBER\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### To Execute for Real:" >> $GITHUB_STEP_SUMMARY
echo "Run this workflow again with the same settings but **uncheck the dry_run option**" >> $GITHUB_STEP_SUMMARY
else
echo "## Release Created Successfully! :tada:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** \`$VERSION\`" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** \`${{ inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Pre-release:** \`${{ inputs.prerelease }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Release Details" >> $GITHUB_STEP_SUMMARY
echo "- **Release URL:** ${{ steps.create_release.outputs.html_url }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Container Images" >> $GITHUB_STEP_SUMMARY
echo "- [${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-metrics-alerting:$VERSION_NUMBER](https://${{ env.REGISTRY }}/repository/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-metrics-alerting?tab=tags)" >> $GITHUB_STEP_SUMMARY
echo "- [${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-mcp-server:$VERSION_NUMBER](https://${{ env.REGISTRY }}/repository/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-mcp-server?tab=tags)" >> $GITHUB_STEP_SUMMARY
echo "- [${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-console-plugin:$VERSION_NUMBER](https://${{ env.REGISTRY }}/repository/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-console-plugin?tab=tags)" >> $GITHUB_STEP_SUMMARY
echo "- [${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-react-ui:$VERSION_NUMBER](https://${{ env.REGISTRY }}/repository/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-react-ui?tab=tags)" >> $GITHUB_STEP_SUMMARY
fi