Prepare Release for Prowler 5.14.1 #4
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: 'Tools: Prepare Release' | |
| run-name: 'Prepare Release for Prowler ${{ inputs.prowler_version }}' | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| prowler_version: | |
| description: 'Prowler version to release (e.g., 5.9.0)' | |
| required: true | |
| type: string | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ inputs.prowler_version }} | |
| cancel-in-progress: false | |
| env: | |
| PROWLER_VERSION: ${{ inputs.prowler_version }} | |
| jobs: | |
| prepare-release: | |
| if: github.event_name == 'workflow_dispatch' && github.repository == 'prowler-cloud/prowler' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} | |
| - name: Set up Python | |
| uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 | |
| with: | |
| python-version: '3.12' | |
| - name: Install Poetry | |
| run: | | |
| python3 -m pip install --user poetry==2.1.1 | |
| echo "$HOME/.local/bin" >> $GITHUB_PATH | |
| - name: Configure Git | |
| run: | | |
| git config --global user.name 'prowler-bot' | |
| git config --global user.email '[email protected]' | |
| - name: Parse version and determine branch | |
| run: | | |
| # Validate version format (reusing pattern from sdk-bump-version.yml) | |
| if [[ $PROWLER_VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then | |
| MAJOR_VERSION=${BASH_REMATCH[1]} | |
| MINOR_VERSION=${BASH_REMATCH[2]} | |
| PATCH_VERSION=${BASH_REMATCH[3]} | |
| # Export version components to environment | |
| echo "MAJOR_VERSION=${MAJOR_VERSION}" >> "${GITHUB_ENV}" | |
| echo "MINOR_VERSION=${MINOR_VERSION}" >> "${GITHUB_ENV}" | |
| echo "PATCH_VERSION=${PATCH_VERSION}" >> "${GITHUB_ENV}" | |
| # Determine branch name (format: v5.9) | |
| BRANCH_NAME="v${MAJOR_VERSION}.${MINOR_VERSION}" | |
| echo "BRANCH_NAME=${BRANCH_NAME}" >> "${GITHUB_ENV}" | |
| echo "Prowler version: $PROWLER_VERSION" | |
| echo "Branch name: $BRANCH_NAME" | |
| echo "Is minor release: $([ $PATCH_VERSION -eq 0 ] && echo 'true' || echo 'false')" | |
| else | |
| echo "Invalid version syntax: '$PROWLER_VERSION' (must be N.N.N)" >&2 | |
| exit 1 | |
| fi | |
| - name: Checkout release branch | |
| run: | | |
| echo "Checking out branch $BRANCH_NAME for release $PROWLER_VERSION..." | |
| if git show-ref --verify --quiet "refs/heads/$BRANCH_NAME"; then | |
| echo "Branch $BRANCH_NAME exists locally, checking out..." | |
| git checkout "$BRANCH_NAME" | |
| elif git show-ref --verify --quiet "refs/remotes/origin/$BRANCH_NAME"; then | |
| echo "Branch $BRANCH_NAME exists remotely, checking out..." | |
| git checkout -b "$BRANCH_NAME" "origin/$BRANCH_NAME" | |
| else | |
| echo "ERROR: Branch $BRANCH_NAME does not exist. For minor releases (X.Y.0), create it manually first. For patch releases (X.Y.Z), the branch should already exist." | |
| exit 1 | |
| fi | |
| - name: Read changelog versions from release branch | |
| run: | | |
| # Function to extract the latest version from changelog | |
| extract_latest_version() { | |
| local changelog_file="$1" | |
| if [ -f "$changelog_file" ]; then | |
| # Extract the first version entry (most recent) from changelog | |
| # Format: ## [version] (1.2.3) or ## [vversion] (v1.2.3) | |
| local version=$(grep -m 1 '^## \[' "$changelog_file" | sed 's/^## \[\(.*\)\].*/\1/' | sed 's/^v//' | tr -d '[:space:]') | |
| echo "$version" | |
| else | |
| echo "" | |
| fi | |
| } | |
| # Read actual versions from changelogs (source of truth) | |
| UI_VERSION=$(extract_latest_version "ui/CHANGELOG.md") | |
| API_VERSION=$(extract_latest_version "api/CHANGELOG.md") | |
| SDK_VERSION=$(extract_latest_version "prowler/CHANGELOG.md") | |
| MCP_VERSION=$(extract_latest_version "mcp_server/CHANGELOG.md") | |
| echo "UI_VERSION=${UI_VERSION}" >> "${GITHUB_ENV}" | |
| echo "API_VERSION=${API_VERSION}" >> "${GITHUB_ENV}" | |
| echo "SDK_VERSION=${SDK_VERSION}" >> "${GITHUB_ENV}" | |
| echo "MCP_VERSION=${MCP_VERSION}" >> "${GITHUB_ENV}" | |
| if [ -n "$UI_VERSION" ]; then | |
| echo "Read UI version from changelog: $UI_VERSION" | |
| else | |
| echo "Warning: No UI version found in ui/CHANGELOG.md" | |
| fi | |
| if [ -n "$API_VERSION" ]; then | |
| echo "Read API version from changelog: $API_VERSION" | |
| else | |
| echo "Warning: No API version found in api/CHANGELOG.md" | |
| fi | |
| if [ -n "$SDK_VERSION" ]; then | |
| echo "Read SDK version from changelog: $SDK_VERSION" | |
| else | |
| echo "Warning: No SDK version found in prowler/CHANGELOG.md" | |
| fi | |
| if [ -n "$MCP_VERSION" ]; then | |
| echo "Read MCP version from changelog: $MCP_VERSION" | |
| else | |
| echo "Warning: No MCP version found in mcp_server/CHANGELOG.md" | |
| fi | |
| echo "UI version: $UI_VERSION" | |
| echo "API version: $API_VERSION" | |
| echo "SDK version: $SDK_VERSION" | |
| echo "MCP version: $MCP_VERSION" | |
| - name: Extract and combine changelog entries | |
| run: | | |
| set -e | |
| # Function to extract changelog for a specific version | |
| extract_changelog() { | |
| local file="$1" | |
| local version="$2" | |
| local output_file="$3" | |
| if [ ! -f "$file" ]; then | |
| echo "Warning: $file not found, skipping..." | |
| touch "$output_file" | |
| return | |
| fi | |
| # Extract changelog section for this version | |
| awk -v version="$version" ' | |
| /^## \[v?'"$version"'\]/ { found=1; next } | |
| found && /^## \[v?[0-9]+\.[0-9]+\.[0-9]+\]/ { found=0 } | |
| found && !/^## \[v?'"$version"'\]/ { print } | |
| ' "$file" > "$output_file" | |
| # Remove --- separators | |
| sed -i '/^---$/d' "$output_file" | |
| # Remove only trailing empty lines (not all empty lines) | |
| sed -i -e :a -e '/^\s*$/d;N;ba' "$output_file" | |
| } | |
| # Calculate expected versions for this release | |
| if [[ $PROWLER_VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then | |
| EXPECTED_UI_VERSION="1.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}" | |
| EXPECTED_API_VERSION="1.$((${BASH_REMATCH[2]} + 1)).${BASH_REMATCH[3]}" | |
| echo "Expected UI version for this release: $EXPECTED_UI_VERSION" | |
| echo "Expected API version for this release: $EXPECTED_API_VERSION" | |
| fi | |
| # Determine if components have changes for this specific release | |
| # UI has changes if its current version matches what we expect for this release | |
| if [ -n "$UI_VERSION" ] && [ "$UI_VERSION" = "$EXPECTED_UI_VERSION" ]; then | |
| echo "HAS_UI_CHANGES=true" >> $GITHUB_ENV | |
| echo "✓ UI changes detected - version matches expected: $UI_VERSION" | |
| extract_changelog "ui/CHANGELOG.md" "$UI_VERSION" "ui_changelog.md" | |
| else | |
| echo "HAS_UI_CHANGES=false" >> $GITHUB_ENV | |
| echo "ℹ No UI changes for this release (current: $UI_VERSION, expected: $EXPECTED_UI_VERSION)" | |
| touch "ui_changelog.md" | |
| fi | |
| # API has changes if its current version matches what we expect for this release | |
| if [ -n "$API_VERSION" ] && [ "$API_VERSION" = "$EXPECTED_API_VERSION" ]; then | |
| echo "HAS_API_CHANGES=true" >> $GITHUB_ENV | |
| echo "✓ API changes detected - version matches expected: $API_VERSION" | |
| extract_changelog "api/CHANGELOG.md" "$API_VERSION" "api_changelog.md" | |
| else | |
| echo "HAS_API_CHANGES=false" >> $GITHUB_ENV | |
| echo "ℹ No API changes for this release (current: $API_VERSION, expected: $EXPECTED_API_VERSION)" | |
| touch "api_changelog.md" | |
| fi | |
| # SDK has changes if its current version matches the input version | |
| if [ -n "$SDK_VERSION" ] && [ "$SDK_VERSION" = "$PROWLER_VERSION" ]; then | |
| echo "HAS_SDK_CHANGES=true" >> $GITHUB_ENV | |
| echo "✓ SDK changes detected - version matches input: $SDK_VERSION" | |
| extract_changelog "prowler/CHANGELOG.md" "$PROWLER_VERSION" "prowler_changelog.md" | |
| else | |
| echo "HAS_SDK_CHANGES=false" >> $GITHUB_ENV | |
| echo "ℹ No SDK changes for this release (current: $SDK_VERSION, input: $PROWLER_VERSION)" | |
| touch "prowler_changelog.md" | |
| fi | |
| # MCP has changes if the changelog references this Prowler version | |
| # Check if the changelog contains "(Prowler X.Y.Z)" or "(Prowler UNRELEASED)" | |
| if [ -f "mcp_server/CHANGELOG.md" ]; then | |
| MCP_PROWLER_REF=$(grep -m 1 "^## \[.*\] (Prowler" mcp_server/CHANGELOG.md | sed -E 's/.*\(Prowler ([^)]+)\).*/\1/' | tr -d '[:space:]') | |
| if [ "$MCP_PROWLER_REF" = "$PROWLER_VERSION" ] || [ "$MCP_PROWLER_REF" = "UNRELEASED" ]; then | |
| echo "HAS_MCP_CHANGES=true" >> $GITHUB_ENV | |
| echo "✓ MCP changes detected - Prowler reference: $MCP_PROWLER_REF (version: $MCP_VERSION)" | |
| extract_changelog "mcp_server/CHANGELOG.md" "$MCP_VERSION" "mcp_changelog.md" | |
| else | |
| echo "HAS_MCP_CHANGES=false" >> $GITHUB_ENV | |
| echo "ℹ No MCP changes for this release (Prowler reference: $MCP_PROWLER_REF, input: $PROWLER_VERSION)" | |
| touch "mcp_changelog.md" | |
| fi | |
| else | |
| echo "HAS_MCP_CHANGES=false" >> $GITHUB_ENV | |
| echo "ℹ No MCP changelog found" | |
| touch "mcp_changelog.md" | |
| fi | |
| # Combine changelogs in order: UI, API, SDK, MCP | |
| > combined_changelog.md | |
| if [ "$HAS_UI_CHANGES" = "true" ] && [ -s "ui_changelog.md" ]; then | |
| echo "## UI" >> combined_changelog.md | |
| echo "" >> combined_changelog.md | |
| cat ui_changelog.md >> combined_changelog.md | |
| echo "" >> combined_changelog.md | |
| fi | |
| if [ "$HAS_API_CHANGES" = "true" ] && [ -s "api_changelog.md" ]; then | |
| echo "## API" >> combined_changelog.md | |
| echo "" >> combined_changelog.md | |
| cat api_changelog.md >> combined_changelog.md | |
| echo "" >> combined_changelog.md | |
| fi | |
| if [ "$HAS_SDK_CHANGES" = "true" ] && [ -s "prowler_changelog.md" ]; then | |
| echo "## SDK" >> combined_changelog.md | |
| echo "" >> combined_changelog.md | |
| cat prowler_changelog.md >> combined_changelog.md | |
| echo "" >> combined_changelog.md | |
| fi | |
| if [ "$HAS_MCP_CHANGES" = "true" ] && [ -s "mcp_changelog.md" ]; then | |
| echo "## MCP" >> combined_changelog.md | |
| echo "" >> combined_changelog.md | |
| cat mcp_changelog.md >> combined_changelog.md | |
| echo "" >> combined_changelog.md | |
| fi | |
| # Add fallback message if no changelogs were added | |
| if [ ! -s combined_changelog.md ]; then | |
| echo "No component changes detected for this release." >> combined_changelog.md | |
| fi | |
| echo "Combined changelog preview:" | |
| cat combined_changelog.md | |
| - name: Verify SDK version in pyproject.toml | |
| run: | | |
| CURRENT_VERSION=$(grep '^version = ' pyproject.toml | sed -E 's/version = "([^"]+)"/\1/' | tr -d '[:space:]') | |
| PROWLER_VERSION_TRIMMED=$(echo "$PROWLER_VERSION" | tr -d '[:space:]') | |
| if [ "$CURRENT_VERSION" != "$PROWLER_VERSION_TRIMMED" ]; then | |
| echo "ERROR: Version mismatch in pyproject.toml (expected: '$PROWLER_VERSION_TRIMMED', found: '$CURRENT_VERSION')" | |
| exit 1 | |
| fi | |
| echo "✓ pyproject.toml version: $CURRENT_VERSION" | |
| - name: Verify SDK version in prowler/config/config.py | |
| run: | | |
| CURRENT_VERSION=$(grep '^prowler_version = ' prowler/config/config.py | sed -E 's/prowler_version = "([^"]+)"/\1/' | tr -d '[:space:]') | |
| PROWLER_VERSION_TRIMMED=$(echo "$PROWLER_VERSION" | tr -d '[:space:]') | |
| if [ "$CURRENT_VERSION" != "$PROWLER_VERSION_TRIMMED" ]; then | |
| echo "ERROR: Version mismatch in prowler/config/config.py (expected: '$PROWLER_VERSION_TRIMMED', found: '$CURRENT_VERSION')" | |
| exit 1 | |
| fi | |
| echo "✓ prowler/config/config.py version: $CURRENT_VERSION" | |
| - name: Verify API version in api/pyproject.toml | |
| if: ${{ env.HAS_API_CHANGES == 'true' }} | |
| run: | | |
| CURRENT_API_VERSION=$(grep '^version = ' api/pyproject.toml | sed -E 's/version = "([^"]+)"/\1/' | tr -d '[:space:]') | |
| API_VERSION_TRIMMED=$(echo "$API_VERSION" | tr -d '[:space:]') | |
| if [ "$CURRENT_API_VERSION" != "$API_VERSION_TRIMMED" ]; then | |
| echo "ERROR: API version mismatch in api/pyproject.toml (expected: '$API_VERSION_TRIMMED', found: '$CURRENT_API_VERSION')" | |
| exit 1 | |
| fi | |
| echo "✓ api/pyproject.toml version: $CURRENT_API_VERSION" | |
| - name: Verify API prowler dependency in api/pyproject.toml | |
| if: ${{ env.PATCH_VERSION != '0' && env.HAS_API_CHANGES == 'true' }} | |
| run: | | |
| CURRENT_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]') | |
| BRANCH_NAME_TRIMMED=$(echo "$BRANCH_NAME" | tr -d '[:space:]') | |
| if [ "$CURRENT_PROWLER_REF" != "$BRANCH_NAME_TRIMMED" ]; then | |
| echo "ERROR: Prowler dependency mismatch in api/pyproject.toml (expected: '$BRANCH_NAME_TRIMMED', found: '$CURRENT_PROWLER_REF')" | |
| exit 1 | |
| fi | |
| echo "✓ api/pyproject.toml prowler dependency: $CURRENT_PROWLER_REF" | |
| - name: Verify API version in api/src/backend/api/v1/views.py | |
| if: ${{ env.HAS_API_CHANGES == 'true' }} | |
| run: | | |
| CURRENT_API_VERSION=$(grep 'spectacular_settings.VERSION = ' api/src/backend/api/v1/views.py | sed -E 's/.*spectacular_settings.VERSION = "([^"]+)".*/\1/' | tr -d '[:space:]') | |
| API_VERSION_TRIMMED=$(echo "$API_VERSION" | tr -d '[:space:]') | |
| if [ "$CURRENT_API_VERSION" != "$API_VERSION_TRIMMED" ]; then | |
| echo "ERROR: API version mismatch in views.py (expected: '$API_VERSION_TRIMMED', found: '$CURRENT_API_VERSION')" | |
| exit 1 | |
| fi | |
| echo "✓ api/src/backend/api/v1/views.py version: $CURRENT_API_VERSION" | |
| - name: Update API prowler dependency for minor release | |
| if: ${{ env.PATCH_VERSION == '0' }} | |
| run: | | |
| CURRENT_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]') | |
| BRANCH_NAME_TRIMMED=$(echo "$BRANCH_NAME" | tr -d '[:space:]') | |
| # Minor release: update the dependency to use the release branch | |
| echo "Updating prowler dependency from '$CURRENT_PROWLER_REF' to '$BRANCH_NAME_TRIMMED'" | |
| sed -i "s|prowler @ git+https://github.com/prowler-cloud/prowler.git@[^\"]*\"|prowler @ git+https://github.com/prowler-cloud/prowler.git@$BRANCH_NAME_TRIMMED\"|" api/pyproject.toml | |
| # Verify the change was made | |
| UPDATED_PROWLER_REF=$(grep 'prowler @ git+https://github.com/prowler-cloud/prowler.git@' api/pyproject.toml | sed -E 's/.*@([^"]+)".*/\1/' | tr -d '[:space:]') | |
| if [ "$UPDATED_PROWLER_REF" != "$BRANCH_NAME_TRIMMED" ]; then | |
| echo "ERROR: Failed to update prowler dependency in api/pyproject.toml" | |
| exit 1 | |
| fi | |
| # Update poetry lock file | |
| echo "Updating poetry.lock file..." | |
| cd api | |
| poetry lock | |
| cd .. | |
| echo "✓ Prepared prowler dependency update to: $UPDATED_PROWLER_REF" | |
| - name: Create PR for API dependency update | |
| if: ${{ env.PATCH_VERSION == '0' }} | |
| uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 | |
| with: | |
| token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} | |
| commit-message: 'chore(api): update prowler dependency to ${{ env.BRANCH_NAME }} for release ${{ env.PROWLER_VERSION }}' | |
| branch: update-api-dependency-${{ env.BRANCH_NAME }}-${{ github.run_number }} | |
| base: ${{ env.BRANCH_NAME }} | |
| add-paths: | | |
| api/pyproject.toml | |
| api/poetry.lock | |
| title: "chore(api): Update prowler dependency to ${{ env.BRANCH_NAME }} for release ${{ env.PROWLER_VERSION }}" | |
| body: | | |
| ### Description | |
| Updates the API prowler dependency for release ${{ env.PROWLER_VERSION }}. | |
| **Changes:** | |
| - Updates `api/pyproject.toml` prowler dependency from `@master` to `@${{ env.BRANCH_NAME }}` | |
| - Updates `api/poetry.lock` file with resolved dependencies | |
| This PR should be merged into the `${{ env.BRANCH_NAME }}` release branch. | |
| ### License | |
| By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. | |
| author: prowler-bot <[email protected]> | |
| labels: | | |
| component/api | |
| no-changelog | |
| - name: Create draft release | |
| uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1 | |
| with: | |
| tag_name: ${{ env.PROWLER_VERSION }} | |
| name: Prowler ${{ env.PROWLER_VERSION }} | |
| body_path: combined_changelog.md | |
| draft: true | |
| target_commitish: ${{ env.BRANCH_NAME }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Clean up temporary files | |
| if: always() | |
| run: | | |
| rm -f prowler_changelog.md api_changelog.md ui_changelog.md mcp_changelog.md combined_changelog.md |