diff --git a/.github/workflows/repository-management.yml b/.github/workflows/repository-management.yml new file mode 100644 index 000000000..29860b868 --- /dev/null +++ b/.github/workflows/repository-management.yml @@ -0,0 +1,249 @@ +name: Repository management + +on: + workflow_dispatch: + inputs: + branch_to_cut: + default: "rc" + description: "Branch to cut" + options: + - "rc" + - "hotfix-rc" + required: true + type: choice + target_ref: + default: "main" + description: "Branch/Tag to target for cut" + required: true + type: string + version_number_override: + description: "New version override (leave blank for automatic calculation, example: '2024.1.0')" + required: false + type: string + +jobs: + cut_branch: + name: Cut branch + runs-on: ubuntu-22.04 + steps: + - name: Check out target ref + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + ref: ${{ inputs.target_ref }} + + - name: Check if ${{ inputs.branch_to_cut }} branch exists + env: + BRANCH_NAME: ${{ inputs.branch_to_cut }} + run: | + if [[ $(git ls-remote --heads origin $BRANCH_NAME) ]]; then + echo "$BRANCH_NAME already exists! Please delete $BRANCH_NAME before running again." >> $GITHUB_STEP_SUMMARY + exit 1 + fi + + - name: Cut branch + env: + BRANCH_NAME: ${{ inputs.branch_to_cut }} + run: | + git switch --quiet --create $BRANCH_NAME + git push --quiet --set-upstream origin $BRANCH_NAME + + + bump_version: + name: Bump Version + runs-on: ubuntu-22.04 + needs: cut_branch + outputs: + version: ${{ steps.set-final-version-output.outputs.version }} + steps: + - name: Validate version input format + if: ${{ inputs.version_number_override != '' }} + uses: bitwarden/gh-actions/version-check@main + with: + version: ${{ inputs.version_number_override }} + + - name: Check out branch + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + ref: main + + - name: Install xmllint + run: | + sudo apt-get update + sudo apt-get install -y libxml2-utils + + - name: Get current version + id: current-version + run: | + CURRENT_VERSION=$(xmllint -xpath "/Project/PropertyGroup/Version/text()" Directory.Build.props) + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + + - name: Verify input version + if: ${{ inputs.version_number_override != '' }} + env: + CURRENT_VERSION: ${{ steps.current-version.outputs.version }} + NEW_VERSION: ${{ inputs.version_number_override }} + run: | + # Error if version has not changed. + if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then + echo "Specified override version is the same as the current version." >> $GITHUB_STEP_SUMMARY + exit 1 + fi + + # Check if version is newer. + printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V + if [ $? -eq 0 ]; then + echo "Version is newer than the current version." + else + echo "Version is older than the current version." >> $GITHUB_STEP_SUMMARY + exit 1 + fi + + - name: Calculate next release version + if: ${{ inputs.version_number_override == '' }} + id: calculate-next-version + uses: bitwarden/gh-actions/version-next@main + with: + version: ${{ steps.current-version.outputs.version }} + + - name: Bump version props - Version Override + if: ${{ inputs.version_number_override != '' }} + id: bump-version-override + uses: bitwarden/gh-actions/version-bump@main + with: + file_path: "Directory.Build.props" + version: ${{ inputs.version_number_override }} + + - name: Bump version props - Automatic Calculation + if: ${{ inputs.version_number_override == '' }} + id: bump-version-automatic + uses: bitwarden/gh-actions/version-bump@main + with: + file_path: "Directory.Build.props" + version: ${{ steps.calculate-next-version.outputs.version }} + + - name: Set final version output + id: set-final-version-output + run: | + if [[ "${{ steps.bump-version-override.outcome }}" = "success" ]]; then + echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT + elif [[ "${{ steps.bump-version-automatic.outcome }}" = "success" ]]; then + echo "version=${{ steps.calculate-next-version.outputs.version }}" >> $GITHUB_OUTPUT + fi + + - name: Configure Git + run: | + git config --local user.email "actions@github.com" + git config --local user.name "Github Actions" + + - name: Commit files + run: git commit -m "Bumped version to ${{ steps.set-final-version-output.outputs.version }}" -a + + - name: Push changes + run: | + git pull -pt + git push + + + cherry_pick: + name: Cherry-Pick Commit(s) + runs-on: ubuntu-22.04 + needs: bump_version + steps: + - name: Check out main branch + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + ref: main + + - name: Install xmllint + run: | + sudo apt-get update + sudo apt-get install -y libxml2-utils + + - name: Verify version has been updated + env: + NEW_VERSION: ${{ needs.bump_version.outputs.version }} + run: | + # Wait for version to change. + while : ; do + echo "Waiting for version to be updated..." + git pull --force + CURRENT_VERSION=$(xmllint -xpath "/Project/PropertyGroup/Version/text()" Directory.Build.props) + + # If the versions don't match we continue the loop, otherwise we break out of the loop. + [[ "$NEW_VERSION" != "$CURRENT_VERSION" ]] || break + sleep 10 + done + + - name: Get last version commit(s) + id: get-commits + run: | + git switch main + MAIN_COMMIT=$(git log --reverse --pretty=format:"%H" --max-count=1 Directory.Build.props) + echo "main_commit=$MAIN_COMMIT" >> $GITHUB_OUTPUT + + if [[ $(git ls-remote --heads origin rc) ]]; then + git switch rc + RC_COMMIT=$(git log --reverse --pretty=format:"%H" --max-count=1 Directory.Build.props) + echo "rc_commit=$RC_COMMIT" >> $GITHUB_OUTPUT + + RC_VERSION=$(xmllint -xpath "/Project/PropertyGroup/Version/text()" Directory.Build.props) + echo "rc_version=$RC_VERSION" >> $GITHUB_OUTPUT + fi + + - name: Configure Git + run: | + git config --local user.email "actions@github.com" + git config --local user.name "Github Actions" + + - name: Perform cherry-pick(s) + env: + CUT_BRANCH: ${{ inputs.branch_to_cut }} + MAIN_COMMIT: ${{ steps.get-commits.outputs.main_commit }} + RC_COMMIT: ${{ steps.get-commits.outputs.rc_commit }} + RC_VERSION: ${{ steps.get-commits.outputs.rc_version }} + run: | + # If we are cutting 'hotfix-rc': + if [[ "$CUT_BRANCH" == "hotfix-rc" ]]; then + + # If the 'rc' branch exists: + if [[ $(git ls-remote --heads origin rc) ]]; then + + # Chery-pick from 'rc' into 'hotfix-rc' + git switch hotfix-rc + HOTFIX_RC_VERSION=$(xmllint -xpath "/Project/PropertyGroup/Version/text()" Directory.Build.props) + if [[ "$HOTFIX_RC_VERSION" != "$RC_VERSION" ]]; then + git cherry-pick --strategy-option=theirs -x $RC_COMMIT + git push -u origin hotfix-rc + fi + + # Cherry-pick from 'main' into 'rc' + git switch rc + git cherry-pick --strategy-option=theirs -x $MAIN_COMMIT + git push -u origin rc + + # If the 'rc' branch does not exist: + else + + # Cherry-pick from 'main' into 'hotfix-rc' + git switch hotfix-rc + git cherry-pick --strategy-option=theirs -x $MAIN_COMMIT + git push -u origin hotfix-rc + + fi + + # If we are cutting 'rc': + elif [[ "$CUT_BRANCH" == "rc" ]]; then + + # Cherry-pick from 'main' into 'rc' + git switch rc + git cherry-pick --strategy-option=theirs -x $MAIN_COMMIT + git push -u origin rc + + fi + + + move_future_db_scripts: + name: Move finalization database scripts + needs: cherry_pick + uses: ./.github/workflows/_move_finalization_db_scripts.yml + secrets: inherit diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml deleted file mode 100644 index e1d96ee4d..000000000 --- a/.github/workflows/version-bump.yml +++ /dev/null @@ -1,266 +0,0 @@ ---- -name: Version Bump - -on: - workflow_dispatch: - inputs: - version_number_override: - description: "New version override (leave blank for automatic calculation, example: '2024.1.0')" - required: false - type: string - cut_rc_branch: - description: "Cut RC branch?" - default: true - type: boolean - enable_slack_notification: - description: "Enable Slack notifications for upcoming release?" - default: false - type: boolean - -jobs: - bump_version: - name: Bump Version - runs-on: ubuntu-22.04 - outputs: - version: ${{ steps.set-final-version-output.outputs.version }} - steps: - - name: Validate version input - if: ${{ inputs.version_number_override != '' }} - uses: bitwarden/gh-actions/version-check@main - with: - version: ${{ inputs.version_number_override }} - - - name: Slack Notification Check - run: | - if [[ "${{ inputs.enable_slack_notification }}" == true ]]; then - echo "Slack notifications enabled." - else - echo "Slack notifications disabled." - fi - - - name: Check out branch - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - - - name: Check if RC branch exists - if: ${{ inputs.cut_rc_branch == true }} - run: | - remote_rc_branch_check=$(git ls-remote --heads origin rc | wc -l) - if [[ "${remote_rc_branch_check}" -gt 0 ]]; then - echo "Remote RC branch exists." - echo "Please delete current RC branch before running again." - exit 1 - fi - - - name: Log in to Azure - CI subscription - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 - with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} - - - name: Retrieve secrets - id: retrieve-secrets - uses: bitwarden/gh-actions/get-keyvault-secrets@main - with: - keyvault: "bitwarden-ci" - secrets: "github-gpg-private-key, - github-gpg-private-key-passphrase" - - - name: Import GPG key - uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0 - with: - gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }} - passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }} - git_user_signingkey: true - git_commit_gpgsign: true - - - name: Set up Git - run: | - git config --local user.email "106330231+bitwarden-devops-bot@users.noreply.github.com" - git config --local user.name "bitwarden-devops-bot" - - - name: Create version branch - id: create-branch - run: | - NAME=version_bump_${{ github.ref_name }}_$(date +"%Y-%m-%d") - git switch -c $NAME - echo "name=$NAME" >> $GITHUB_OUTPUT - - - name: Install xmllint - run: | - sudo apt-get update - sudo apt-get install -y libxml2-utils - - - name: Get current version - id: current-version - run: | - CURRENT_VERSION=$(xmllint -xpath "/Project/PropertyGroup/Version/text()" Directory.Build.props) - echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT - - - name: Verify input version - if: ${{ inputs.version_number_override != '' }} - env: - CURRENT_VERSION: ${{ steps.current-version.outputs.version }} - NEW_VERSION: ${{ inputs.version_number_override }} - run: | - # Error if version has not changed. - if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then - echo "Version has not changed." - exit 1 - fi - - # Check if version is newer. - printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V - if [ $? -eq 0 ]; then - echo "Version check successful." - else - echo "Version check failed." - exit 1 - fi - - - name: Calculate next release version - if: ${{ inputs.version_number_override == '' }} - id: calculate-next-version - uses: bitwarden/gh-actions/version-next@main - with: - version: ${{ steps.current-version.outputs.version }} - - - name: Bump version props - Version Override - if: ${{ inputs.version_number_override != '' }} - id: bump-version-override - uses: bitwarden/gh-actions/version-bump@main - with: - file_path: "Directory.Build.props" - version: ${{ inputs.version_number_override }} - - - name: Bump version props - Automatic Calculation - if: ${{ inputs.version_number_override == '' }} - id: bump-version-automatic - uses: bitwarden/gh-actions/version-bump@main - with: - file_path: "Directory.Build.props" - version: ${{ steps.calculate-next-version.outputs.version }} - - - name: Set final version output - id: set-final-version-output - run: | - if [[ "${{ steps.bump-version-override.outcome }}" = "success" ]]; then - echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT - elif [[ "${{ steps.bump-version-automatic.outcome }}" = "success" ]]; then - echo "version=${{ steps.calculate-next-version.outputs.version }}" >> $GITHUB_OUTPUT - fi - - - name: Check if version changed - id: version-changed - run: | - if [ -n "$(git status --porcelain)" ]; then - echo "changes_to_commit=TRUE" >> $GITHUB_OUTPUT - else - echo "changes_to_commit=FALSE" >> $GITHUB_OUTPUT - echo "No changes to commit!"; - fi - - - name: Commit files - if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} - run: git commit -m "Bumped version to ${{ steps.set-final-version-output.outputs.version }}" -a - - - name: Push changes - if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} - env: - PR_BRANCH: ${{ steps.create-branch.outputs.name }} - run: git push -u origin $PR_BRANCH - - - name: Generate GH App token - uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 - id: app-token - with: - app-id: ${{ secrets.BW_GHAPP_ID }} - private-key: ${{ secrets.BW_GHAPP_KEY }} - owner: ${{ github.repository_owner }} - - - name: Create version PR - if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} - id: create-pr - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - PR_BRANCH: ${{ steps.create-branch.outputs.name }} - TITLE: "Bump version to ${{ steps.set-final-version-output.outputs.version }}" - run: | - PR_URL=$(gh pr create --title "$TITLE" \ - --base "main" \ - --head "$PR_BRANCH" \ - --label "version update" \ - --label "automated pr" \ - --body " - ## Type of change - - [ ] Bug fix - - [ ] New feature development - - [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc) - - [ ] Build/deploy pipeline (DevOps) - - [X] Other - - ## Objective - Automated version bump to ${{ steps.set-final-version-output.outputs.version }}") - echo "pr_number=${PR_URL##*/}" >> $GITHUB_OUTPUT - - - name: Approve PR - if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }} - run: gh pr review $PR_NUMBER --approve - - - name: Merge PR - if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }} - run: gh pr merge $PR_NUMBER --squash --auto --delete-branch - - - name: Report upcoming release version to Slack - if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' && inputs.enable_slack_notification == true }} - uses: bitwarden/gh-actions/report-upcoming-release-version@main - with: - version: ${{ steps.set-final-version-output.outputs.version }} - project: ${{ github.repository }} - AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} - - cut_rc: - name: Cut RC branch - if: ${{ inputs.cut_rc_branch == true }} - needs: bump_version - runs-on: ubuntu-22.04 - steps: - - name: Check out branch - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - with: - ref: main - - - name: Install xmllint - run: | - sudo apt-get update - sudo apt-get install -y libxml2-utils - - - name: Verify version has been updated - env: - NEW_VERSION: ${{ needs.bump_version.outputs.version }} - run: | - # Wait for version to change. - while : ; do - echo "Waiting for version to be updated..." - git pull --force - CURRENT_VERSION=$(xmllint -xpath "/Project/PropertyGroup/Version/text()" Directory.Build.props) - - # If the versions don't match we continue the loop, otherwise we break out of the loop. - [[ "$NEW_VERSION" != "$CURRENT_VERSION" ]] || break - sleep 10 - done - - - name: Cut RC branch - run: | - git switch --quiet --create rc - git push --quiet --set-upstream origin rc - - move-future-db-scripts: - name: Move finalization database scripts - needs: cut_rc - uses: ./.github/workflows/_move_finalization_db_scripts.yml - secrets: inherit