diff --git a/.github/workflows/enforce-toolchain-synchronization.yml b/.github/workflows/enforce-toolchain-synchronization.yml new file mode 100644 index 000000000000..fdca68bb7020 --- /dev/null +++ b/.github/workflows/enforce-toolchain-synchronization.yml @@ -0,0 +1,121 @@ +# Enforce rebasing Pull Requests if Toolchain was modified on target branch +# +# If new commits, which modifies toolchain files was pushed to given branch, find all PRs targeting +# this branch, which also change toolchain files. Then, enforce rebasing them by changing +# CI/Jenkins/toolchain check to FAILURE. +# This prevents race condition issue when new toolchain bundle has to be built after PR is merged. +# +# Toolchain files: +# * scripts/requirements-fixed.txt +# * scripts/tools-versions-darwin.yml +# * scripts/tools-versions-win10.yml +# * scripts/tools-versions-linux.yml + +name: Enforce rebasing Pull Requests if Toolchain was modified on target branch + +on: + push: + branches: + - '**' # Triggers on pushes to any branch + +jobs: + check-prs: + runs-on: ubuntu-latest + + steps: + - name: Define list of files to check + id: define_files + run: | + echo "TOOLCHAIN_FILES=scripts/requirements-fixed.txt,scripts/tools-versions-linux.yml,scripts/tools-versions-darwin.yml,scripts/tools-versions-win10.yml" >> $GITHUB_ENV + + - name: Checkout the repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Get files modified by recent commits + id: get_files + run: | + echo "Modified files in this commit:" + git diff --name-only ${{ github.event.before }} ${{ github.sha }} > modified_files.txt + cat modified_files.txt + + - name: Check if any watched files are modified + id: check_files + run: | + modified_files=$(cat modified_files.txt) + IFS=',' read -r -a watched_files <<< "${{ env.TOOLCHAIN_FILES }}" + modified=false + for file in "${watched_files[@]}"; do + if echo "$modified_files" | grep -q "$file"; then + echo "$file was modified." + modified=true + fi + done + echo "modified=$modified" >> $GITHUB_ENV + + # App token is required to update Check Status + - name: Get jenkins-ncs App token + if: env.modified == 'true' + uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.JENKINS_NCS_APP_ID }} + private-key: ${{ secrets.JENKINS_NCS_APP_PRIVATE_KEY }} + + - name: Find open pull requests targeting this branch and modyfing Toolchain files + if: env.modified == 'true' + id: find_prs + run: | + PRs=$(gh pr list --base ${{ github.ref_name }} --state open --json url,headRefName,files --jq '[.[] | select(.files[]? | .path as $file | [$file] | inside([env.TOOLCHAIN_FILES]))]') + echo "Found PRs: $PRs" + echo "prs=$PRs" >> $GITHUB_ENV + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + + - name: Set CI/Jenkins/toolchain status check to failure + if: env.modified == 'true' && steps.find_prs.outputs.prs != '[]' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + for pr in $(echo "$prs" | jq -r '.[].url'); do + pr_url=$(echo $pr | sed 's|https://github.com/||') + pr_owner=$(echo $pr_url | cut -d'/' -f1) + pr_repo=$(echo $pr_url | cut -d'/' -f2) + pr_number=$(echo $pr_url | cut -d'/' -f4) + + echo "Setting CI/Jenkins/toolchain status to failure for PR: $pr" + + # Get the SHA of the last commit in the PR branch + commit_sha=$(gh pr view $pr_number --json headRefOid --jq '.headRefOid') + + # Get the Check Run ID by listing the check runs for the PR's head commit + check_run_id=$(gh api \ + -H "Accept: application/vnd.github.v3+json" \ + /repos/$pr_owner/$pr_repo/commits/$commit_sha/check-runs \ + --jq '.check_runs[] | select(.name == "CI/Jenkins/toolchain") | .id') + + # If no check run exists, create a new one; otherwise, update the existing one + if [ -z "$check_run_id" ]; then + echo "Creating new check run for PR: $pr" + gh api \ + -H "Accept: application/vnd.github.v3+json" \ + --method POST /repos/$pr_owner/$pr_repo/check-runs \ + -f name="CI/Jenkins/toolchain" \ + -f head_sha="$commit_sha" \ + -f status="completed" \ + -f conclusion="failure" \ + -f output[title]="Rebase needed - Toolchain changed on '${{ github.ref_name }}' branch" \ + -f output[summary]="Toolchain was modified on '${{ github.ref_name }}' and this PR has to be rebased" + else + echo "Updating existing check run with ID $check_run_id" + gh api \ + -H "Accept: application/vnd.github.v3+json" \ + --method PATCH /repos/$pr_owner/$pr_repo/check-runs/$check_run_id \ + -f conclusion="failure" \ + -f status="completed" \ + -f output[title]="Rebase needed - Toolchain changed on '${{ github.ref_name }}' branch" \ + -f output[summary]="Toolchain was modified on '${{ github.ref_name }}' and this PR has to be rebased" + fi + done