Prepare Release (Dry Run) #12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Prepare Release | |
| run-name: ${{ inputs.dry_run == true && 'Prepare Release (Dry Run)' || 'Prepare Release' }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| bump_type: | |
| description: 'Version bump type' | |
| required: true | |
| type: choice | |
| options: | |
| - major | |
| - minor | |
| - patch | |
| custom_version: | |
| description: 'Custom version (optional, overrides bump_type). Format: X.Y.Z' | |
| required: false | |
| type: string | |
| target_branch: | |
| description: 'Target branch for release preparation' | |
| required: false | |
| default: 'dev' | |
| type: choice | |
| options: | |
| - dev | |
| - main | |
| dry_run: | |
| description: 'Dry run mode (only show what would happen, do not push)' | |
| required: false | |
| default: false | |
| type: boolean | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| env: | |
| REGISTRY: quay.io | |
| ORG: ecosystem-appeng | |
| IMAGE_PREFIX: aiobs | |
| jobs: | |
| compute-next-version: | |
| name: Compute next version | |
| runs-on: ubuntu-latest | |
| outputs: | |
| expected_version: ${{ steps.calculate.outputs.expected_version }} | |
| commit_message: ${{ steps.calculate.outputs.commit_message }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.target_branch }} | |
| fetch-depth: 0 | |
| - name: Configure Git | |
| run: | | |
| git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git config --local user.name "github-actions[bot]" | |
| - name: Calculate expected version and commit message | |
| id: calculate | |
| run: | | |
| # Get current version from Makefile | |
| CURRENT_VERSION=$(grep "^VERSION.*=" Makefile | sed 's/VERSION.*= //' | head -1) | |
| echo "Current version: $CURRENT_VERSION" | |
| # Check if custom version is provided | |
| if [ -n "${{ inputs.custom_version }}" ]; then | |
| # Validate custom version format | |
| if ! echo "${{ inputs.custom_version }}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "Error: Custom version must be in format X.Y.Z (e.g., 1.2.3)" | |
| exit 1 | |
| fi | |
| EXPECTED_VERSION="${{ inputs.custom_version }}" | |
| COMMIT_PREFIX="chore" | |
| echo "Using custom version: $EXPECTED_VERSION" | |
| else | |
| # Calculate version based on bump type | |
| IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION" | |
| case "${{ inputs.bump_type }}" in | |
| major) | |
| MAJOR=$((MAJOR + 1)) | |
| MINOR=0 | |
| PATCH=0 | |
| COMMIT_PREFIX="major" | |
| ;; | |
| minor) | |
| MINOR=$((MINOR + 1)) | |
| PATCH=0 | |
| COMMIT_PREFIX="minor" | |
| ;; | |
| patch) | |
| PATCH=$((PATCH + 1)) | |
| COMMIT_PREFIX="patch" | |
| ;; | |
| esac | |
| EXPECTED_VERSION="${MAJOR}.${MINOR}.${PATCH}" | |
| echo "Calculated version for ${{ inputs.bump_type }} bump: $EXPECTED_VERSION" | |
| fi | |
| # Construct commit message | |
| COMMIT_MSG="$COMMIT_PREFIX: prepare release $EXPECTED_VERSION" | |
| echo "expected_version=$EXPECTED_VERSION" >> $GITHUB_OUTPUT | |
| echo "commit_message=$COMMIT_MSG" >> $GITHUB_OUTPUT | |
| echo "Expected version: $EXPECTED_VERSION" | |
| echo "Commit message: $COMMIT_MSG" | |
| update-version: | |
| name: Update version files | |
| needs: compute-next-version | |
| if: ${{ !inputs.dry_run }} | |
| uses: ./.github/workflows/update-versions.yml | |
| with: | |
| version: ${{ needs.compute-next-version.outputs.expected_version }} | |
| commit_message: ${{ needs.compute-next-version.outputs.commit_message }} | |
| push_changes: true | |
| target_branch: ${{ inputs.target_branch }} | |
| secrets: inherit | |
| version-bump-commit: | |
| name: Verify version bump commit | |
| runs-on: ubuntu-latest | |
| needs: [compute-next-version, update-version] | |
| if: always() && (needs.update-version.result == 'success' || needs.update-version.result == 'skipped') | |
| outputs: | |
| expected_version: ${{ needs.compute-next-version.outputs.expected_version }} | |
| commit_sha: ${{ steps.verify.outputs.commit_sha }} | |
| steps: | |
| - name: Checkout repository | |
| if: ${{ !inputs.dry_run }} | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.target_branch }} | |
| fetch-depth: 0 | |
| - name: Verify commit was created | |
| if: ${{ !inputs.dry_run }} | |
| id: verify | |
| run: | | |
| # Get the latest commit SHA | |
| COMMIT_SHA=$(git rev-parse HEAD) | |
| echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT | |
| echo "Verified commit: $COMMIT_SHA" | |
| # Show commit details | |
| echo "::group::Commit Details" | |
| git log -1 --format=fuller | |
| echo "::endgroup::" | |
| - name: Dry run - show commit details | |
| if: ${{ inputs.dry_run }} | |
| run: | | |
| echo "=== DRY RUN MODE ===" | |
| echo "The following files would be updated:" | |
| echo "" | |
| echo "Version: ${{ needs.compute-next-version.outputs.expected_version }}" | |
| echo "Commit message: ${{ needs.compute-next-version.outputs.commit_message }}" | |
| echo "" | |
| echo "Files that would be updated:" | |
| echo " - deploy/helm/alerting/values.yaml" | |
| echo " - deploy/helm/mcp-server/values.yaml" | |
| echo " - deploy/helm/openshift-console-plugin/values.yaml" | |
| echo " - deploy/helm/react-ui-app/values.yaml" | |
| echo " - Makefile" | |
| echo "" | |
| echo "Commit would be pushed to: origin/${{ inputs.target_branch }}" | |
| echo "" | |
| echo "This would trigger the build workflow to create images with version: ${{ needs.compute-next-version.outputs.expected_version }}" | |
| build-image: | |
| name: Build and Push container image | |
| needs: version-bump-commit | |
| if: ${{ !inputs.dry_run }} | |
| uses: ./.github/workflows/build-images.yml | |
| with: | |
| version: ${{ needs.version-bump-commit.outputs.expected_version }} | |
| registry: quay.io | |
| org: ecosystem-appeng | |
| image_prefix: aiobs | |
| secrets: inherit | |
| build-operator: | |
| name: Build and Push operator images | |
| needs: version-bump-commit | |
| if: ${{ !inputs.dry_run }} | |
| uses: ./.github/workflows/build-operator-images.yml | |
| with: | |
| version: ${{ needs.version-bump-commit.outputs.expected_version }} | |
| registry: quay.io | |
| org: ecosystem-appeng | |
| push_changes: true | |
| secrets: inherit | |
| create-pr: | |
| name: Create PR from dev to main | |
| runs-on: ubuntu-latest | |
| needs: [version-bump-commit, build-image, build-operator] | |
| if: ${{ !inputs.dry_run && inputs.target_branch == 'dev' }} | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Create PR from dev to main | |
| run: | | |
| set +e # Don't exit on error - we'll handle permissions gracefully | |
| VERSION_NUMBER="${{ needs.version-bump-commit.outputs.expected_version }}" | |
| echo "Checking for existing PR from dev to main..." | |
| # Check if PR already exists | |
| EXISTING_PR=$(gh pr list --base main --head dev --json number --jq '.[0].number' 2>&1 || echo "") | |
| if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ] && [ "$EXISTING_PR" != "" ]; then | |
| echo "✅ PR already exists: #$EXISTING_PR" | |
| PR_URL="https://github.com/${{ github.repository }}/pull/$EXISTING_PR" | |
| else | |
| echo "Creating PR from dev to main for version $VERSION_NUMBER" | |
| # Build PR body using a temporary file to avoid shell escaping issues | |
| PR_BODY_FILE=$(mktemp) | |
| cat > "$PR_BODY_FILE" <<EOF | |
| ## Release Preparation $VERSION_NUMBER | |
| This PR merges the release preparation changes from \`dev\` to \`main\`. | |
| ### Release Details | |
| - **Version:** $VERSION_NUMBER | |
| - **Commit:** ${{ needs.version-bump-commit.outputs.commit_sha }} | |
| ### Container Images | |
| **Application Components:** | |
| - \`${{ env.IMAGE_PREFIX }}-metrics-alerting:$VERSION_NUMBER\` | |
| - \`${{ env.IMAGE_PREFIX }}-mcp-server:$VERSION_NUMBER\` | |
| - \`${{ env.IMAGE_PREFIX }}-console-plugin:$VERSION_NUMBER\` | |
| - \`${{ env.IMAGE_PREFIX }}-react-ui:$VERSION_NUMBER\` | |
| **Operator:** | |
| - \`${{ env.IMAGE_PREFIX }}-operator:v$VERSION_NUMBER\` | |
| - \`${{ env.IMAGE_PREFIX }}-operator-bundle:v$VERSION_NUMBER\` | |
| - \`${{ env.IMAGE_PREFIX }}-operator-catalog:v$VERSION_NUMBER\` | |
| ### Checklist | |
| - [ ] All images verified in Quay.io | |
| - [ ] Version files updated correctly | |
| - [ ] Ready to merge to main | |
| EOF | |
| echo "Attempting to create PR..." | |
| # Capture both stdout and stderr | |
| PR_OUTPUT=$(gh pr create \ | |
| --base main \ | |
| --head dev \ | |
| --title "Release Preparation $VERSION_NUMBER" \ | |
| --body-file "$PR_BODY_FILE" \ | |
| 2>&1) || PR_EXIT_CODE=$? | |
| rm -f "$PR_BODY_FILE" | |
| # Check if PR creation succeeded (URL should contain /pull/) | |
| if echo "$PR_OUTPUT" | grep -qE "(https://.*/pull/[0-9]+|http://.*/pull/[0-9]+)"; then | |
| PR_URL=$(echo "$PR_OUTPUT" | grep -oE "(https://.*/pull/[0-9]+|http://.*/pull/[0-9]+)" | head -1) | |
| echo "✅ PR created successfully: $PR_URL" | |
| else | |
| # Check if it's a permissions error | |
| if echo "$PR_OUTPUT" | grep -qi "not permitted to create"; then | |
| echo "⚠️ PR creation skipped due to repository permissions" | |
| echo "" | |
| echo "The workflow does not have permission to create pull requests." | |
| echo "This is a repository-level setting that needs to be enabled:" | |
| echo "" | |
| echo "To fix this:" | |
| echo "1. Go to Repository Settings → Actions → General" | |
| echo "2. Under 'Workflow permissions', select 'Read and write permissions'" | |
| echo "3. Check 'Allow GitHub Actions to create and approve pull requests'" | |
| echo "" | |
| echo "For now, please create the PR manually:" | |
| echo " - Base: main" | |
| echo " - Head: dev" | |
| echo " - Title: Release Preparation $VERSION_NUMBER" | |
| echo "" | |
| PR_URL="" # Set empty so summary knows PR wasn't created | |
| else | |
| echo "❌ Failed to create PR" | |
| echo "Exit code: ${PR_EXIT_CODE:-unknown}" | |
| echo "Output:" | |
| echo "$PR_OUTPUT" | |
| echo "" | |
| echo "Debugging info:" | |
| echo "- Repository: ${{ github.repository }}" | |
| echo "- Base branch: main" | |
| echo "- Head branch: dev" | |
| echo "- Version: $VERSION_NUMBER" | |
| exit 1 | |
| fi | |
| fi | |
| fi | |
| echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| summary: | |
| name: Summary | |
| runs-on: ubuntu-latest | |
| needs: [compute-next-version, version-bump-commit, build-image, build-operator, create-pr] | |
| if: always() && (needs.create-pr.result == 'success' || needs.create-pr.result == 'skipped') | |
| steps: | |
| - name: Summary | |
| run: | | |
| if [ "${{ inputs.dry_run }}" = "true" ]; then | |
| echo "## Dry Run - Release Preparation Preview :mag:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "> **This was a DRY RUN - no changes were pushed**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Expected Version:** \`${{ needs.compute-next-version.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**Commit Message:** \`${{ needs.compute-next-version.outputs.commit_message }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**Target Branch:** \`${{ inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### What Would Happen:" >> $GITHUB_STEP_SUMMARY | |
| echo "1. Version files would be updated to \`${{ needs.compute-next-version.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "2. Commit would be created with message: \`${{ needs.compute-next-version.outputs.commit_message }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "3. Commit would be pushed to \`${{ inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "4. Images would be built with version \`${{ needs.compute-next-version.outputs.expected_version }}\`:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo " **Application Components:**" >> $GITHUB_STEP_SUMMARY | |
| echo " - \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-metrics-alerting:${{ needs.compute-next-version.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo " - \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-mcp-server:${{ needs.compute-next-version.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo " - \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-console-plugin:${{ needs.compute-next-version.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo " - \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-react-ui:${{ needs.compute-next-version.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo " **Operator:**" >> $GITHUB_STEP_SUMMARY | |
| echo " - \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator:v${{ needs.compute-next-version.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo " - \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator-bundle:v${{ needs.compute-next-version.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo " - \`${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator-catalog:v${{ needs.compute-next-version.outputs.expected_version }}\`" >> $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 Preparation Complete! :rocket:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Expected Version:** \`${{ needs.version-bump-commit.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**Commit SHA:** \`${{ needs.version-bump-commit.outputs.commit_sha }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**Target Branch:** \`${{ inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Next Steps:" >> $GITHUB_STEP_SUMMARY | |
| echo "1. Verify images are built with version \`${{ needs.version-bump-commit.outputs.expected_version }}\`:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo " **Application Components:**" >> $GITHUB_STEP_SUMMARY | |
| echo " - [${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-metrics-alerting:${{ needs.version-bump-commit.outputs.expected_version }}](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:${{ needs.version-bump-commit.outputs.expected_version }}](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:${{ needs.version-bump-commit.outputs.expected_version }}](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:${{ needs.version-bump-commit.outputs.expected_version }}](https://${{ env.REGISTRY }}/repository/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-react-ui?tab=tags)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo " **Operator:**" >> $GITHUB_STEP_SUMMARY | |
| echo " - [${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator:v${{ needs.version-bump-commit.outputs.expected_version }}](https://${{ env.REGISTRY }}/repository/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator?tab=tags)" >> $GITHUB_STEP_SUMMARY | |
| echo " - [${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator-bundle:v${{ needs.version-bump-commit.outputs.expected_version }}](https://${{ env.REGISTRY }}/repository/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator-bundle?tab=tags)" >> $GITHUB_STEP_SUMMARY | |
| echo " - [${{ env.REGISTRY }}/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator-catalog:v${{ needs.version-bump-commit.outputs.expected_version }}](https://${{ env.REGISTRY }}/repository/${{ env.ORG }}/${{ env.IMAGE_PREFIX }}-operator-catalog?tab=tags)" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ inputs.target_branch }}" = "dev" ]; then | |
| # Check if PR was created (create-pr job succeeded) | |
| if [ "${{ needs.create-pr.result }}" = "success" ]; then | |
| echo "2. Review and merge the PR from \`dev\` to \`main\`" >> $GITHUB_STEP_SUMMARY | |
| echo "3. Once PR is merged, run the [Create Release workflow](https://github.com/${{ github.repository }}/actions/workflows/create-release.yml) with version \`v${{ needs.version-bump-commit.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "2. ⚠️ PR creation was skipped or failed. You may need to create a PR manually from \`dev\` to \`main\`" >> $GITHUB_STEP_SUMMARY | |
| echo "3. Once PR is merged, run the [Create Release workflow](https://github.com/${{ github.repository }}/actions/workflows/create-release.yml) with version \`v${{ needs.version-bump-commit.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "2. Run the [Create Release workflow](https://github.com/${{ github.repository }}/actions/workflows/create-release.yml) with version \`v${{ needs.version-bump-commit.outputs.expected_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| fi |