diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 9c9caa3b6..85778b2af 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -2,8 +2,8 @@ name: CLI Release on: push: - tags: - - 'cli/v*' # Trigger on tags like cli/v1.2.3 + branches: + - main # Trigger when PR from staging (or any other) is merged to main # Add permissions for creating releases permissions: @@ -11,8 +11,47 @@ permissions: # pull-requests: write # Not typically needed for a tag-triggered release workflow jobs: - build: - # No specific if condition needed here based on event, tag push is the trigger + prepare_cli_release_info: + name: Prepare CLI Release Information + runs-on: ubuntu-latest + outputs: + cli_version: ${{ steps.version_info.outputs.cli_version }} + cli_tag_name: ${{ steps.version_info.outputs.cli_tag_name }} + steps: + - name: Checkout code from main + uses: actions/checkout@v4 + with: + ref: ${{ github.sha }} # Checkout the specific commit on main (merge commit) + + - name: Read CLI Version and Determine Tag + id: version_info + shell: bash + run: | + CLI_VERSION="" + if [ -f cli/cli/Cargo.toml ]; then + CLI_VERSION=$(grep '^version' cli/cli/Cargo.toml | head -n 1 | sed 's/version = \"\(.*\)\"/\1/') + echo "Read CLI version '$CLI_VERSION' from cli/cli/Cargo.toml" + else + echo "Error: cli/cli/Cargo.toml not found!" + exit 1 + fi + + if [ -z "$CLI_VERSION" ]; then + echo "Error: Could not determine CLI version from Cargo.toml." + exit 1 + fi + + CLI_TAG_NAME="cli/v$CLI_VERSION" + echo "Determined CLI Version: $CLI_VERSION" + echo "Determined CLI Tag Name: $CLI_TAG_NAME" + echo "cli_version=$CLI_VERSION" >> $GITHUB_OUTPUT + echo "cli_tag_name=$CLI_TAG_NAME" >> $GITHUB_OUTPUT + +# Separate Build Job (similar to original) + build_cli: + name: Build CLI Binaries + needs: prepare_cli_release_info # Does not strictly need outputs, but runs after version is confirmed + runs-on: ${{ matrix.os }} strategy: matrix: include: @@ -32,13 +71,11 @@ jobs: target: x86_64-pc-windows-msvc artifact_name: buster-cli-windows-x86_64.zip use_tar: false - runs-on: ${{ matrix.os }} steps: - - name: Checkout code at the specific tag + - name: Checkout code from main uses: actions/checkout@v4 with: - ref: ${{ github.ref }} # Checks out the specific tag that triggered the workflow - fetch-depth: 0 # Useful for some build processes or if release notes need history + ref: ${{ github.sha }} - name: Install Rust uses: actions-rs/toolchain@v1 @@ -63,60 +100,51 @@ jobs: - name: Build optimized release working-directory: ./cli # Assuming this is the workspace root for the cli crate - # If your CLI project is in cli/cli, adjust working-directory to ./cli/cli run: cargo build --release --target ${{ matrix.target }} --manifest-path ./cli/Cargo.toml - name: Determine Binary Name and Path id: binary_info shell: bash run: | - # Ensure cli/target directory exists before find, in case of clean builds or different structures mkdir -p cli/target/${{ matrix.target }}/release - CRATE_NAME_OUTPUT=$(basename $(find cli/target/${{ matrix.target }}/release -maxdepth 1 -type f -executable ! -name '*.dSYM' ! -name '*.pdb' 2>/dev/null || echo "buster")) # Default to buster if not found - # If find returns nothing (e.g. build failed or path is wrong), CRATE_NAME_OUTPUT could be empty or an error message. - # Fallback to a known name or fail if necessary. For now, using "buster" as a placeholder. - if [ -z "$CRATE_NAME_OUTPUT" ] || ! [ -f "cli/target/${{ matrix.target }}/release/$CRATE_NAME_OUTPUT" ]; then - echo "Warning: Could not automatically determine binary name. Assuming 'buster'." - # Attempt to find 'buster' or 'buster.exe' directly if primary find fails - if [[ "${{ matrix.os }}" == "windows-latest" ]]; then - CRATE_NAME_CANDIDATE="buster.exe" - else - CRATE_NAME_CANDIDATE="buster" - fi - if [ -f "cli/target/${{ matrix.target }}/release/$CRATE_NAME_CANDIDATE" ]; then - CRATE_NAME_OUTPUT=$CRATE_NAME_CANDIDATE - else - # If even the fallback isn't found, this will cause issues later. - # Consider failing the step: echo "Error: Binary not found."; exit 1 - # For now, proceeding with a default name and letting later steps handle missing file - echo "Fallback binary '$CRATE_NAME_CANDIDATE' also not found. Proceeding with this name." - CRATE_NAME_OUTPUT=${CRATE_NAME_CANDIDATE%.exe} # Store without .exe for consistency if needed elsewhere - fi + # Default to 'buster' if find command fails or returns empty + CRATE_NAME_OUTPUT=$(basename $(find cli/target/${{ matrix.target }}/release -maxdepth 1 -type f -executable ! -name '*.dSYM' ! -name '*.pdb' 2>/dev/null) || echo "buster") + if [ "$CRATE_NAME_OUTPUT" == "." ] || [ -z "$CRATE_NAME_OUTPUT" ]; then CRATE_NAME_OUTPUT="buster"; fi # Further fallback for empty/dot + + # Check if the determined/fallback name actually exists as a file + if [[ "${{ matrix.os }}" == "windows-latest" ]] && [[ "$CRATE_NAME_OUTPUT" != *.exe ]]; then + EXECUTABLE_NAME="${CRATE_NAME_OUTPUT}.exe" + else + EXECUTABLE_NAME="$CRATE_NAME_OUTPUT" fi - echo "CRATE_NAME=$CRATE_NAME_OUTPUT" - echo "Binary name: $CRATE_NAME_OUTPUT" - echo "binary_name=$CRATE_NAME_OUTPUT" >> $GITHUB_OUTPUT - echo "binary_path=cli/target/${{ matrix.target }}/release/$CRATE_NAME_OUTPUT" - echo "binary_path_val=cli/target/${{ matrix.target }}/release/$CRATE_NAME_OUTPUT" >> $GITHUB_OUTPUT + + if ! [ -f "cli/target/${{ matrix.target }}/release/$EXECUTABLE_NAME" ]; then + echo "Warning: Binary '$EXECUTABLE_NAME' not found after build. Defaulting to 'buster' or 'buster.exe'." + if [[ "${{ matrix.os }}" == "windows-latest" ]]; then CRATE_NAME_FINAL="buster.exe"; else CRATE_NAME_FINAL="buster"; fi + else + CRATE_NAME_FINAL=$EXECUTABLE_NAME + fi + echo "Final binary name for packaging: $CRATE_NAME_FINAL" + echo "binary_name=$CRATE_NAME_FINAL" >> $GITHUB_OUTPUT + # GITHUB_OUTPUT for binary_path_val is not strictly needed by subsequent steps if using artifact names directly + # echo "binary_path_val=cli/target/${{ matrix.target }}/release/$CRATE_NAME_FINAL" >> $GITHUB_OUTPUT - name: Compress binary (Unix) if: matrix.use_tar shell: bash run: | cd cli/target/${{ matrix.target }}/release + # Use the exact binary name determined (could be buster or buster.exe from binary_info) tar czf ${{ matrix.artifact_name }} ${{ steps.binary_info.outputs.binary_name }} - if [[ "${{ runner.os }}" == "macOS" ]]; then - shasum -a 256 ${{ matrix.artifact_name }} > ${{ matrix.artifact_name }}.sha256 - else - sha256sum ${{ matrix.artifact_name }} > ${{ matrix.artifact_name }}.sha256 - fi + if [[ "${{ runner.os }}" == "macOS" ]]; then shasum -a 256 ${{ matrix.artifact_name }} > ${{ matrix.artifact_name }}.sha256; else sha256sum ${{ matrix.artifact_name }} > ${{ matrix.artifact_name }}.sha256; fi - name: Compress binary (Windows) if: matrix.use_tar == false shell: pwsh run: | cd cli/target/${{ matrix.target }}/release - Compress-Archive -Path ${{ steps.binary_info.outputs.binary_name }}.exe -DestinationPath ${{ matrix.artifact_name }} + # Use the exact binary name, which should include .exe on Windows from binary_info + Compress-Archive -Path ${{ steps.binary_info.outputs.binary_name }} -DestinationPath ${{ matrix.artifact_name }} Get-FileHash -Algorithm SHA256 ${{ matrix.artifact_name }} | Select-Object -ExpandProperty Hash > ${{ matrix.artifact_name }}.sha256 - name: Upload artifacts @@ -128,75 +156,88 @@ jobs: cli/target/${{ matrix.target }}/release/${{ matrix.artifact_name }}.sha256 retention-days: 1 - release: - needs: build + # This job now handles tagging and creating the GitHub release + tag_and_release_cli: + name: Create Git Tag and GitHub Release for CLI + needs: [prepare_cli_release_info, build_cli] runs-on: ubuntu-latest - # No specific if condition needed here based on event, tag push is the trigger - outputs: - release_tag: ${{ steps.get_tag_info.outputs.cli_tag_name }} - release_version: ${{ steps.get_tag_info.outputs.cli_version }} + outputs: + cli_version: ${{ needs.prepare_cli_release_info.outputs.cli_version }} + cli_tag_name: ${{ needs.prepare_cli_release_info.outputs.cli_tag_name }} steps: - - name: Checkout code at the specific tag + - name: Checkout code from main (for tagging context) uses: actions/checkout@v4 with: - ref: ${{ github.ref }} # Checks out the specific tag that triggered the workflow - fetch-depth: 0 - - - name: Extract CLI Tag and Version from Git Ref - id: get_tag_info - shell: bash + ref: ${{ github.sha }} + fetch-depth: 0 + # IMPORTANT: Use a PAT with repo scope to push tags, especially if main is protected + # or if the default GITHUB_TOKEN doesn't have tag push permissions. + # token: ${{ secrets.REPO_ACCESS_PAT }} + + - name: Configure Git User run: | - CLI_TAG_NAME="${{ github.ref_name }}" - # Validate tag format if necessary (e.g., ensure it starts with cli/v) - if [[ ! "$CLI_TAG_NAME" =~ ^cli/v[0-9]+\.[0-9]+\.[0-9]+(.*)$ ]]; then - echo "Error: Tag $CLI_TAG_NAME does not match the expected format 'cli/vX.Y.Z'" - # exit 1 # Optionally fail the job - # For now, we'll proceed and let release creation fail if tag is not suitable - fi + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Create and Push Git Tag + env: + # Get tag name from the prepare_cli_release_info job + CLI_TAG_NAME: ${{ needs.prepare_cli_release_info.outputs.cli_tag_name }} + # Ensure PAT is used if GITHUB_TOKEN is insufficient for pushing tags: + # GH_TOKEN: ${{ secrets.REPO_ACCESS_PAT }} # Uncomment and use your PAT secret + run: | + echo "Creating Git tag: $CLI_TAG_NAME on commit ${{ github.sha }}" + # Create tag pointing to the current commit on main (merge commit) + git tag "$CLI_TAG_NAME" ${{ github.sha }} + echo "Pushing Git tag: $CLI_TAG_NAME" + # If using PAT for push, uncomment the following lines after setting GH_TOKEN env var: + # git remote set-url origin https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }} + # git push origin "refs/tags/$CLI_TAG_NAME" - CLI_VERSION=$(echo "$CLI_TAG_NAME" | sed 's#^cli/v##') + # For now, using default GITHUB_TOKEN. THIS MIGHT NOT WORK FOR PROTECTED BRANCHES/TAGS + # OR IF THE TOKEN LACKS PERMISSION. REPLACE WITH PAT PUSH. + git push origin "refs/tags/$CLI_TAG_NAME" - echo "cli_tag_name=$CLI_TAG_NAME" >> $GITHUB_OUTPUT - echo "cli_version=$CLI_VERSION" >> $GITHUB_OUTPUT - echo "Extracted from Git Ref - CLI Tag: $CLI_TAG_NAME, CLI Version: $CLI_VERSION" - - - name: Download build artifacts + - name: Download all build artifacts uses: actions/download-artifact@v4 - # No specific path needed, it downloads all to a directory named after the artifact + with: + path: downloaded-artifacts # Download all artifacts to this directory + + - name: List downloaded artifacts (for debugging) + run: ls -R downloaded-artifacts - - name: Create Release - # if: steps.get_tag_info.outputs.cli_tag_name != '' # This check is implicitly handled by the tag trigger pattern + - name: Create GitHub Release uses: softprops/action-gh-release@v1 with: - tag_name: ${{ steps.get_tag_info.outputs.cli_tag_name }} # Should be same as github.ref_name - name: CLI Release v${{ steps.get_tag_info.outputs.cli_version }} + tag_name: ${{ needs.prepare_cli_release_info.outputs.cli_tag_name }} + name: CLI Release v${{ needs.prepare_cli_release_info.outputs.cli_version }} files: | - **/buster-cli-linux-x86_64.tar.gz - **/buster-cli-linux-x86_64.tar.gz.sha256 - **/buster-cli-darwin-x86_64.tar.gz - **/buster-cli-darwin-x86_64.tar.gz.sha256 - **/buster-cli-darwin-arm64.tar.gz - **/buster-cli-darwin-arm64.tar.gz.sha256 - **/buster-cli-windows-x86_64.zip - **/buster-cli-windows-x86_64.zip.sha256 + downloaded-artifacts/**/buster-cli-linux-x86_64.tar.gz + downloaded-artifacts/**/buster-cli-linux-x86_64.tar.gz.sha256 + downloaded-artifacts/**/buster-cli-darwin-x86_64.tar.gz + downloaded-artifacts/**/buster-cli-darwin-x86_64.tar.gz.sha256 + downloaded-artifacts/**/buster-cli-darwin-arm64.tar.gz + downloaded-artifacts/**/buster-cli-darwin-arm64.tar.gz.sha256 + downloaded-artifacts/**/buster-cli-windows-x86_64.zip + downloaded-artifacts/**/buster-cli-windows-x86_64.zip.sha256 draft: false prerelease: false - generate_release_notes: true + generate_release_notes: true env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Default token is usually fine for softprops action if tag exists - update-homebrew-tap: + update_homebrew_tap: name: Update Homebrew Tap - needs: release + needs: tag_and_release_cli # Trigger after tag_and_release_cli which now outputs version and tag runs-on: ubuntu-latest - if: needs.release.outputs.release_tag != '' # Run only if a CLI tag was processed and release was attempted + if: needs.tag_and_release_cli.outputs.cli_tag_name != '' steps: - name: Get release version and tag from previous job id: release_info run: | - echo "RELEASE_VERSION=${{ needs.release.outputs.release_version }}" >> $GITHUB_ENV - echo "RELEASE_TAG=${{ needs.release.outputs.release_tag }}" >> $GITHUB_ENV - echo "Using version: ${{ needs.release.outputs.release_version }} from tag: ${{ needs.release.outputs.release_tag }}" + echo "RELEASE_VERSION=${{ needs.tag_and_release_cli.outputs.cli_version }}" >> $GITHUB_ENV + echo "RELEASE_TAG=${{ needs.tag_and_release_cli.outputs.cli_tag_name }}" >> $GITHUB_ENV + echo "Using version: ${{ needs.tag_and_release_cli.outputs.cli_version }} from tag: ${{ needs.tag_and_release_cli.outputs.cli_tag_name }}" - name: Set up GitHub CLI uses: actions/setup-node@v4 # gh is often bundled, but this ensures it's available or can be installed diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index 97cdaffc7..798669ff0 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -2,9 +2,8 @@ name: Docker Release on: push: - tags: - - 'api/v*' - - 'web/v*' + branches: + - main # Trigger when PR from staging is merged to main env: # Placeholder for Docker Hub username/organization or GHCR owner @@ -13,15 +12,72 @@ env: WEB_IMAGE_NAME: web-service jobs: - build_and_push_api: - name: Build and Push API Image - if: startsWith(github.ref, 'refs/tags/api/v') # Trigger only for API tags - runs-on: blacksmith-32vcpu-ubuntu-2204 # Updated runner + prepare_docker_release_info: + name: Prepare Docker Release Information + runs-on: ubuntu-latest + outputs: + api_version: ${{ steps.version_info.outputs.api_version }} + web_version: ${{ steps.version_info.outputs.web_version }} + api_version_found: ${{ steps.version_info.outputs.api_version_found }} + web_version_found: ${{ steps.version_info.outputs.web_version_found }} steps: - - name: Checkout code at the specific tag + - name: Checkout code from main uses: actions/checkout@v4 with: - ref: ${{ github.ref }} # Checks out the specific API tag + ref: ${{ github.sha }} # Checkout the specific commit on main (merge commit) + + - name: Read API and Web Versions + id: version_info + shell: bash + run: | + API_VERSION="" + WEB_VERSION="" + API_VERSION_FOUND="false" + WEB_VERSION_FOUND="false" + + # Read API version from api/server/Cargo.toml + if [ -f api/server/Cargo.toml ]; then + API_VERSION=$(grep '^version' api/server/Cargo.toml | head -n 1 | sed 's/version = \"\(.*\)\"/\1/') + if [ -n "$API_VERSION" ]; then + echo "Read API version '$API_VERSION' from api/server/Cargo.toml" + API_VERSION_FOUND="true" + else + echo "API version string not found in api/server/Cargo.toml despite file existing." + fi + else + echo "Warning: api/server/Cargo.toml not found. Cannot determine API version." + fi + + # Read Web version from web/package.json + if [ -f web/package.json ]; then + WEB_VERSION=$(jq -r '.version // empty' web/package.json) + if [ -n "$WEB_VERSION" ]; then + echo "Read Web version '$WEB_VERSION' from web/package.json" + WEB_VERSION_FOUND="true" + else + echo "Web version string not found in web/package.json despite file existing." + fi + else + echo "Warning: web/package.json not found. Cannot determine Web version." + fi + + echo "api_version=$API_VERSION" >> $GITHUB_OUTPUT + echo "web_version=$WEB_VERSION" >> $GITHUB_OUTPUT + echo "api_version_found=$API_VERSION_FOUND" >> $GITHUB_OUTPUT + echo "web_version_found=$WEB_VERSION_FOUND" >> $GITHUB_OUTPUT + + build_and_push_api: + name: Build and Push API Image + needs: prepare_docker_release_info + if: needs.prepare_docker_release_info.outputs.api_version_found == 'true' + runs-on: blacksmith-32vcpu-ubuntu-2204 + env: + API_VERSION: ${{ needs.prepare_docker_release_info.outputs.api_version }} + steps: + - name: Checkout code from main + uses: actions/checkout@v4 + with: + ref: ${{ github.sha }} - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -29,20 +85,6 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Extract API version from Git tag - id: api_version_extractor # Renamed for clarity - run: | - # github.ref_name will be like "api/v1.2.3" - VERSION=$(echo "${{ github.ref_name }}" | sed 's#^api/v##') - if [ -z "$VERSION" ]; then # Should not happen due to startsWith condition - echo "Could not extract version from tag: ${{ github.ref_name }}" - VERSION="unknown" - fi - echo "API_VERSION_ENV=$VERSION" >> $GITHUB_ENV # Set for current job - echo "api_version_output=$VERSION" >> $GITHUB_OUTPUT # Output for other steps if needed - echo "Extracted API version: $VERSION" - shell: bash - - name: Log in to Docker Registry uses: docker/login-action@v3 with: @@ -54,24 +96,27 @@ jobs: uses: useblacksmith/build-push-action@v1 with: context: ./api - file: ./api/Dockerfile # Assuming this Dockerfile is for api/server + file: ./api/Dockerfile push: true tags: | - ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }}:${{ env.API_VERSION_ENV }} - ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }}:${{ github.sha }} # SHA of the tag commit + ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }}:${{ env.API_VERSION }} + ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }}:${{ github.sha }} ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }}:latest cache-from: type=gha cache-to: type=gha,mode=max build_and_push_web: name: Build and Push Web Image - if: startsWith(github.ref, 'refs/tags/web/v') # Trigger only for Web tags - runs-on: blacksmith-32vcpu-ubuntu-2204 # Updated runner + needs: prepare_docker_release_info + if: needs.prepare_docker_release_info.outputs.web_version_found == 'true' + runs-on: blacksmith-32vcpu-ubuntu-2204 + env: + WEB_VERSION: ${{ needs.prepare_docker_release_info.outputs.web_version }} steps: - - name: Checkout code at the specific tag + - name: Checkout code from main uses: actions/checkout@v4 with: - ref: ${{ github.ref }} # Checks out the specific Web tag + ref: ${{ github.sha }} - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -79,20 +124,6 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Extract Web version from Git tag - id: web_version_extractor # Renamed for clarity - run: | - # github.ref_name will be like "web/v1.2.3" - VERSION=$(echo "${{ github.ref_name }}" | sed 's#^web/v##') - if [ -z "$VERSION" ]; then # Should not happen due to startsWith condition - echo "Could not extract version from tag: ${{ github.ref_name }}" - VERSION="unknown" - fi - echo "WEB_VERSION_ENV=$VERSION" >> $GITHUB_ENV # Set for current job - echo "web_version_output=$VERSION" >> $GITHUB_OUTPUT # Output for other steps if needed - echo "Extracted Web version: $VERSION" - shell: bash - - name: Log in to Docker Registry uses: docker/login-action@v3 with: @@ -107,8 +138,8 @@ jobs: file: ./web/Dockerfile push: true tags: | - ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }}:${{ env.WEB_VERSION_ENV }} - ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }}:${{ github.sha }} # SHA of the tag commit + ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }}:${{ env.WEB_VERSION }} + ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }}:${{ github.sha }} ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }}:latest build-args: | NEXT_PUBLIC_API_URL=${{ secrets.NEXT_PUBLIC_API_URL }} diff --git a/.github/workflows/manage-versions.yml b/.github/workflows/manage-versions.yml index e42aae880..cbbbf86dd 100644 --- a/.github/workflows/manage-versions.yml +++ b/.github/workflows/manage-versions.yml @@ -2,63 +2,66 @@ name: Manage Versions on: pull_request: - types: [closed] + types: [opened] branches: - - main + - staging workflow_dispatch: inputs: component: - description: 'Component to version bump' + description: 'Component to version bump (if running manually)' required: true default: 'all' type: choice - options: - - all - - api - - web - - cli + options: [all, api, web, cli] version_spec: - description: 'Version bump type (patch, minor, major) or specific version (e.g., 1.2.3)' + description: 'Version bump type or specific version (if running manually)' required: true default: 'patch' type: string + pr_branch: + description: 'Name of the PR source branch (required if dispatching for a PR)' + required: false + type: string permissions: - contents: write # To push commits and tags + contents: write # To push commits back to the PR branch jobs: - bump_versions: + bump_versions_in_pr: runs-on: blacksmith - if: (github.event_name == 'pull_request' && github.event.pull_request.merged == true) || github.event_name == 'workflow_dispatch' + if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' outputs: new_api_version: ${{ steps.bump.outputs.new_api_version }} new_web_version: ${{ steps.bump.outputs.new_web_version }} new_cli_version: ${{ steps.bump.outputs.new_cli_version }} - api_tag_created: ${{ steps.tag.outputs.api_tag_created }} - web_tag_created: ${{ steps.tag.outputs.web_tag_created }} - cli_tag_created: ${{ steps.tag.outputs.cli_tag_created }} + versions_bumped: ${{ steps.bump.outputs.versions_bumped }} steps: - - name: Determine Branch Name and SHA - id: branch_info + - name: Determine Target Branch for Checkout and Push + id: pr_branch_info shell: bash run: | + TARGET_BRANCH="" if [[ "${{ github.event_name }}" == "pull_request" ]]; then - echo "branch_name=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT - echo "checkout_sha=${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT + TARGET_BRANCH="${{ github.head_ref }}" + echo "Detected PR event. Will operate on PR source branch: $TARGET_BRANCH" elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - echo "branch_name=${{ github.ref_name }}" >> $GITHUB_OUTPUT - echo "checkout_sha=${{ github.sha }}" >> $GITHUB_OUTPUT + if [[ -z "${{ github.event.inputs.pr_branch }}" ]]; then + echo "Error: 'pr_branch' input is required for manual dispatch to update a PR." + exit 1 + fi + TARGET_BRANCH="${{ github.event.inputs.pr_branch }}" + echo "Detected workflow_dispatch event. Will operate on specified PR branch: $TARGET_BRANCH" else - echo "branch_name=${{ github.ref_name }}" >> $GITHUB_OUTPUT - echo "checkout_sha=${{ github.sha }}" >> $GITHUB_OUTPUT + echo "Error: Unhandled event type '${{ github.event_name }}'" + exit 1 fi + echo "target_branch_name=$TARGET_BRANCH" >> $GITHUB_OUTPUT - - name: Checkout code + - name: Checkout PR source branch uses: actions/checkout@v4 with: - ref: ${{ github.sha }} + ref: ${{ steps.pr_branch_info.outputs.target_branch_name }} token: ${{ secrets.GITHUB_TOKEN }} - fetch-depth: 0 - name: Set up Node.js uses: actions/setup-node@v4 @@ -79,74 +82,42 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Determine Version Spec and Component from Event + - name: Determine Version Spec and Component id: event_params shell: bash run: | VERSION_SPEC="" COMPONENT="" - COMMIT_MESSAGE_TEXT="" - - echo "Event name: ${{ github.event_name }}" if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then VERSION_SPEC="${{ github.event.inputs.version_spec }}" COMPONENT="${{ github.event.inputs.component }}" echo "Using workflow_dispatch inputs: version_spec='$VERSION_SPEC', component='$COMPONENT'" - elif [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.merged }}" == "true" ]]; then + elif [[ "${{ github.event_name }}" == "pull_request" ]]; then PR_TITLE=$(echo "${{ github.event.pull_request.title }}" | tr '[:upper:]' '[:lower:]') - echo "Pull Request title (lowercase): $PR_TITLE" COMPONENT="all" - if echo "$PR_TITLE" | grep -q -E "breaking change|feat!:"; then - VERSION_SPEC="major" - elif echo "$PR_TITLE" | grep -q -E "^feat\\([^)]+\\)!:"; then - VERSION_SPEC="major" - elif echo "$PR_TITLE" | grep -q -E "^feat:"; then - VERSION_SPEC="minor" - elif echo "$PR_TITLE" | grep -q -E "^fix:"; then - VERSION_SPEC="patch" + if echo "$PR_TITLE" | grep -q -E "breaking change|feat!:"; then VERSION_SPEC="major"; + elif echo "$PR_TITLE" | grep -q -E "^feat\\([^)]+\\)!:"; then VERSION_SPEC="major"; + elif echo "$PR_TITLE" | grep -q -E "^feat:"; then VERSION_SPEC="minor"; + elif echo "$PR_TITLE" | grep -q -E "^fix:"; then VERSION_SPEC="patch"; else - echo "No major/minor/fix keyword found in PR title. Defaulting to patch for merged PR." + echo "No conventional commit keyword (major/minor/patch) found in PR title '$PR_TITLE'." + echo "Version bumping will not occur automatically for this push to the PR." VERSION_SPEC="patch" fi - echo "Determined for PR merge: version_spec='$VERSION_SPEC', component='$COMPONENT'" - elif [[ "${{ github.event_name }}" == "push" ]]; then - COMMIT_MESSAGE_TEXT=$(echo "${{ github.event.head_commit.message }}" | tr '[:upper:]' '[:lower:]') - echo "Push event. Analyzing commit message (lowercase): $COMMIT_MESSAGE_TEXT" - COMPONENT="all" - - if echo "$COMMIT_MESSAGE_TEXT" | grep -q -E "breaking change|feat!:"; then - VERSION_SPEC="major" - elif echo "$COMMIT_MESSAGE_TEXT" | grep -q -E "^feat\\([^)]+\\)!:"; then - VERSION_SPEC="major" - elif echo "$COMMIT_MESSAGE_TEXT" | grep -q -E "^feat:"; then - VERSION_SPEC="minor" - elif echo "$COMMIT_MESSAGE_TEXT" | grep -q -E "^fix:"; then - VERSION_SPEC="patch" - else - echo "No major/minor/fix keyword found in commit message. Defaulting to patch." - VERSION_SPEC="patch" - fi - echo "Determined for push: version_spec='$VERSION_SPEC', component='$COMPONENT'" - else - echo "Unhandled event type: ${{ github.event_name }}. Defaulting to patch and all." - VERSION_SPEC="patch" - COMPONENT="all" + echo "Determined for PR to staging: version_spec='$VERSION_SPEC', component='$COMPONENT'" fi - + if [[ -z "$VERSION_SPEC" ]]; then - echo "Warning: VERSION_SPEC is empty after evaluation. Defaulting to patch." + echo "Warning: VERSION_SPEC is empty. Defaulting to patch." VERSION_SPEC="patch" fi if [[ -z "$COMPONENT" ]]; then - echo "Warning: COMPONENT is empty after evaluation. Defaulting to all." + echo "Warning: COMPONENT is empty. Defaulting to all." COMPONENT="all" fi - echo "Final determined version_spec: $VERSION_SPEC" - echo "Final determined component: $COMPONENT" - echo "version_spec=$VERSION_SPEC" >> $GITHUB_OUTPUT echo "component=$COMPONENT" >> $GITHUB_OUTPUT @@ -231,85 +202,83 @@ jobs: if [[ "$COMMIT_CHANGES" == true ]]; then FINAL_COMMIT_MESSAGE=$(echo "$COMMIT_MESSAGE_PREFIX" | sed 's/;$//') - echo "Final Commit Message: $FINAL_COMMIT_MESSAGE [skip ci]" - echo "COMMIT_MESSAGE_CONTENT=$FINAL_COMMIT_MESSAGE [skip ci]" >> $GITHUB_ENV - echo "commit_message=$FINAL_COMMIT_MESSAGE [skip ci]" >> $GITHUB_OUTPUT + echo "Final Commit Message for version files: $FINAL_COMMIT_MESSAGE [skip ci]" + echo "commit_message=$FINAL_COMMIT_MESSAGE [skip ci]" >> $GITHUB_OUTPUT # For the version files commit + echo "versions_bumped=true" >> $GITHUB_OUTPUT else - echo "No version changes detected." - echo "COMMIT_MESSAGE_CONTENT=" >> $GITHUB_ENV + echo "No version changes detected for source files." echo "commit_message=" >> $GITHUB_OUTPUT + echo "versions_bumped=false" >> $GITHUB_OUTPUT fi + echo "New API Version Output: $NEW_API_VERSION" echo "New Web Version Output: $NEW_WEB_VERSION" echo "New CLI Version Output: $NEW_CLI_VERSION" - - name: Commit version changes - if: steps.bump.outputs.commit_message != '' + - name: Commit and Push Version File Changes to PR Branch + if: steps.bump.outputs.versions_bumped == 'true' env: - COMMIT_MESSAGE_TO_USE: ${{ steps.bump.outputs.commit_message }} + TARGET_BRANCH: ${{ steps.pr_branch_info.outputs.target_branch_name }} + COMMIT_MESSAGE_CONTENT: ${{ steps.bump.outputs.commit_message }} # This is the commit message for version files run: | - git commit -m "$COMMIT_MESSAGE_TO_USE" + echo "Committing version file changes with message: $COMMIT_MESSAGE_CONTENT" + git commit -m "$COMMIT_MESSAGE_CONTENT" # Files were already added by the 'bump' step + echo "Pushing version file changes to PR branch: $TARGET_BRANCH" + git push origin HEAD:"$TARGET_BRANCH" - - name: Create and Push Tags - if: steps.bump.outputs.commit_message != '' + - name: Prepare, Commit, and Push Tag Information File + if: steps.bump.outputs.versions_bumped == 'true' # Only run if versions were actually bumped + id: prepare_tag_info_file + env: + TARGET_BRANCH: ${{ steps.pr_branch_info.outputs.target_branch_name }} run: | - echo "Creating and pushing tags..." + echo "Preparing tag_info.json file..." TAG_INFO_FILE="tag_info.json" echo "{" > $TAG_INFO_FILE - FIRST_TAG=true + FIRST_ENTRY=true NEW_API_VERSION="${{ steps.bump.outputs.new_api_version }}" NEW_WEB_VERSION="${{ steps.bump.outputs.new_web_version }}" NEW_CLI_VERSION="${{ steps.bump.outputs.new_cli_version }}" if [[ -n "$NEW_API_VERSION" ]]; then - TAG_NAME="api/v$NEW_API_VERSION" - echo "Tagging API: $TAG_NAME" - git tag "$TAG_NAME" - if [ "$FIRST_TAG" = false ]; then echo "," >> $TAG_INFO_FILE; fi - echo " \"api_tag\": \"$TAG_NAME\"" >> $TAG_INFO_FILE - FIRST_TAG=false + POTENTIAL_TAG_NAME="api/v$NEW_API_VERSION" + if [ "$FIRST_ENTRY" = false ]; then echo "," >> $TAG_INFO_FILE; fi + echo " \"api_tag\": \"$POTENTIAL_TAG_NAME\", \"api_version\": \"$NEW_API_VERSION\"" >> $TAG_INFO_FILE + FIRST_ENTRY=false fi if [[ -n "$NEW_WEB_VERSION" ]]; then - TAG_NAME="web/v$NEW_WEB_VERSION" - echo "Tagging Web: $TAG_NAME" - git tag "$TAG_NAME" - if [ "$FIRST_TAG" = false ]; then echo "," >> $TAG_INFO_FILE; fi - echo " \"web_tag\": \"$TAG_NAME\"" >> $TAG_INFO_FILE - FIRST_TAG=false + POTENTIAL_TAG_NAME="web/v$NEW_WEB_VERSION" + if [ "$FIRST_ENTRY" = false ]; then echo "," >> $TAG_INFO_FILE; fi + echo " \"web_tag\": \"$POTENTIAL_TAG_NAME\", \"web_version\": \"$NEW_WEB_VERSION\"" >> $TAG_INFO_FILE + FIRST_ENTRY=false fi if [[ -n "$NEW_CLI_VERSION" ]]; then - TAG_NAME="cli/v$NEW_CLI_VERSION" - echo "Tagging CLI: $TAG_NAME" - git tag "$TAG_NAME" - if [ "$FIRST_TAG" = false ]; then echo "," >> $TAG_INFO_FILE; fi - echo " \"cli_tag\": \"$TAG_NAME\"" >> $TAG_INFO_FILE - FIRST_TAG=false + POTENTIAL_TAG_NAME="cli/v$NEW_CLI_VERSION" + if [ "$FIRST_ENTRY" = false ]; then echo "," >> $TAG_INFO_FILE; fi + echo " \"cli_tag\": \"$POTENTIAL_TAG_NAME\", \"cli_version\": \"$NEW_CLI_VERSION\"" >> $TAG_INFO_FILE + FIRST_ENTRY=false fi echo "}" >> $TAG_INFO_FILE - echo "Created tag info file:" + echo "Created tag_info.json:" cat $TAG_INFO_FILE + + echo "Committing and pushing tag_info.json to $TARGET_BRANCH..." + git add $TAG_INFO_FILE + # Check if there are changes to commit for tag_info.json to avoid empty commit + if ! git diff --staged --quiet; then + git commit -m "chore: update tag_info.json with potential release versions [skip ci]" + git push origin HEAD:"$TARGET_BRANCH" + echo "tag_info.json pushed to $TARGET_BRANCH." + else + echo "No changes to tag_info.json to commit." + fi - BRANCH_TO_PUSH="${{ steps.branch_info.outputs.branch_name }}" - echo "Pushing commit and tags to branch: $BRANCH_TO_PUSH" - git push origin HEAD:"refs/heads/$BRANCH_TO_PUSH" --follow-tags - - echo "api_tag_created=$API_TAG_CREATED" >> $GITHUB_OUTPUT - echo "web_tag_created=$WEB_TAG_CREATED" >> $GITHUB_OUTPUT - echo "cli_tag_created=$CLI_TAG_CREATED" >> $GITHUB_OUTPUT - - - name: Upload Tag Information Artifact - if: steps.tag.outputs.api_tag_created == 'true' || steps.tag.outputs.web_tag_created == 'true' || steps.tag.outputs.cli_tag_created == 'true' + - name: Upload Tag Information Artifact (for reference) + if: steps.bump.outputs.versions_bumped == 'true' # Or based on whether tag_info.json was actually changed/committed uses: actions/upload-artifact@v4 with: - name: version-tag-info - path: tag_info.json - retention-days: 1 - - - name: Push changes (if only commit, no tags yet or if tag push failed) - if: steps.bump.outputs.commit_message != '' && (steps.bump.outputs.new_api_version == '' && steps.bump.outputs.new_web_version == '' && steps.bump.outputs.new_cli_version == '') - run: | - BRANCH_TO_PUSH="${{ steps.branch_info.outputs.branch_name }}" - echo "Pushing commit to branch: $BRANCH_TO_PUSH (changes made but no version tags generated)." - git push origin HEAD:"refs/heads/$BRANCH_TO_PUSH" \ No newline at end of file + name: version-tag-info-potential + path: tag_info.json # This will upload the latest version from the workspace + retention-days: 7 \ No newline at end of file