Add process duplication transaction phases #6861
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: SemverChecks | |
| # Run on pull requests or merge groups | |
| on: | |
| pull_request: | |
| types: | |
| - opened | |
| - synchronize | |
| - reopened | |
| - edited | |
| issue_comment: | |
| types: | |
| - created | |
| - edited | |
| - deleted | |
| merge_group: | |
| # If a new commit is pushed to the branch before ongoing runs finish, cancel the ongoing runs | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref || github.run_id }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| rerun_fork_check: | |
| name: Re-run fork semver check | |
| if: >- | |
| github.event_name == 'issue_comment' && | |
| github.event.issue.pull_request && | |
| (github.event.action == 'deleted' || | |
| contains(github.event.comment.body, ':robot: SemverChecks :robot:')) | |
| permissions: | |
| actions: write | |
| contents: read | |
| pull-requests: read | |
| issues: read | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Re-run the pull request check | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| API_URL: ${{ github.api_url }} | |
| REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.issue.number }} | |
| run: | | |
| set -euo pipefail | |
| PR=$(curl --fail-with-body -sS \ | |
| -H "Authorization: Bearer $GH_TOKEN" \ | |
| -H 'Accept: application/vnd.github+json' \ | |
| "$API_URL/repos/$REPOSITORY/pulls/$PR_NUMBER") | |
| IS_OPEN=$(jq -r '.state == "open"' <<<"$PR") | |
| IS_FORK=$(jq -r '.head.repo.fork == true' <<<"$PR") | |
| COMMENTER_IS_AUTHOR=$(jq -r --arg login "${{ github.event.comment.user.login }}" '.user.login == $login' <<<"$PR") | |
| COMMENTER_IS_MAINTAINER=$(case '${{ github.event.comment.author_association }}' in OWNER|MEMBER|COLLABORATOR) echo true;; *) echo false;; esac) | |
| if [ "$IS_OPEN" != true ] || [ "$IS_FORK" != true ] || \ | |
| { [ "$COMMENTER_IS_AUTHOR" != true ] && [ "$COMMENTER_IS_MAINTAINER" != true ]; }; then | |
| echo 'Ignoring comment from an unauthorized user or on a non-open fork PR.' | |
| exit 0 | |
| fi | |
| HEAD_SHA=$(jq -r '.head.sha' <<<"$PR") | |
| RUN_ID=$(curl --fail-with-body -sS \ | |
| -H "Authorization: Bearer $GH_TOKEN" \ | |
| -H 'Accept: application/vnd.github+json' \ | |
| "$API_URL/repos/$REPOSITORY/actions/workflows/semver-checks.yml/runs?event=pull_request&head_sha=$HEAD_SHA&per_page=10" | \ | |
| jq -r --argjson pr_number "$PR_NUMBER" '[.workflow_runs[] | select(any(.pull_requests[]?; .number == $pr_number))] | first | .id // empty') | |
| if [ -z "$RUN_ID" ]; then | |
| echo 'No pull_request semver-checks run exists for this commit yet.' >&2 | |
| exit 1 | |
| fi | |
| curl --fail-with-body -sS -X POST \ | |
| -H "Authorization: Bearer $GH_TOKEN" \ | |
| -H 'Accept: application/vnd.github+json' \ | |
| "$API_URL/repos/$REPOSITORY/actions/runs/$RUN_ID/rerun" | |
| semver_checks: | |
| name: Check SemVer Correctness | |
| if: ${{ github.event_name != 'issue_comment' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out repo | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Determine baseline ref | |
| id: baseline | |
| run: | | |
| BASE_REF="${{ github.event.pull_request.base.ref }}" | |
| MERGE_GROUP_BASE_REF="${{ github.event.merge_group.base_ref }}" | |
| MERGE_GROUP_BASE_REF="${MERGE_GROUP_BASE_REF#refs/heads/}" | |
| BASE_REF="${BASE_REF:-$MERGE_GROUP_BASE_REF}" | |
| echo "ref=$BASE_REF" >> "$GITHUB_OUTPUT" | |
| - name: Fetch baseline branch | |
| run: git fetch origin "${{ steps.baseline.outputs.ref }}:${{ steps.baseline.outputs.ref }}" | |
| - name: Set up Rust | |
| run: | | |
| rustup toolchain install $(awk -F'"' '/channel/{print $2}' rust-toolchain.toml) --profile minimal --no-self-update | |
| - name: Determine packages to check | |
| id: packages | |
| run: | | |
| git diff --name-only "${{ steps.baseline.outputs.ref }}" HEAD > /tmp/semver-checks-changed-files | |
| python3 .github/tools/determine_semver_packages.py --changed-files /tmp/semver-checks-changed-files > /tmp/semver-checks-packages | |
| if [ -s /tmp/semver-checks-packages ]; then | |
| echo "has_packages=true" >> "$GITHUB_OUTPUT" | |
| echo "Packages selected for semver checks:" | |
| sed 's/^/ - /' /tmp/semver-checks-packages | |
| else | |
| echo "has_packages=false" >> "$GITHUB_OUTPUT" | |
| echo "No semver-relevant crate changes detected." | |
| fi | |
| - name: Set up cargo-semver-checks | |
| if: steps.packages.outputs.has_packages == 'true' | |
| run: | | |
| curl -L --proto '=https' --tlsv1.2 -sSf https://github.com/obi1kenobi/cargo-semver-checks/releases/latest/download/cargo-semver-checks-x86_64-unknown-linux-gnu.tar.gz | tar xzvf - | |
| mv cargo-semver-checks ~/.cargo/bin | |
| - name: Check semver match against the baseline branch | |
| id: semver_check | |
| run: | | |
| # TODO(jayb): we are temporarily preventing a failure in semver-checks | |
| # from showing up as a `X`, but instead triggering a comment on the | |
| # PR. Once things go public, we will likely switch this out to make it | |
| # actually complain as usual, possibly still keeping in the comment bot? | |
| if [ "${{ steps.packages.outputs.has_packages }}" != "true" ]; then | |
| : > /tmp/semver-checks-stdout | |
| echo "Semver check skipped because no semver-relevant crate changes were detected." | |
| echo "reaction=hooray" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| PACKAGE_ARGS=() | |
| while IFS= read -r PACKAGE; do | |
| PACKAGE_ARGS+=("-p" "$PACKAGE") | |
| done < /tmp/semver-checks-packages | |
| if cargo semver-checks "${PACKAGE_ARGS[@]}" --baseline-rev "${{ steps.baseline.outputs.ref }}" --color=never >/tmp/semver-checks-stdout; then | |
| cat /tmp/semver-checks-stdout | |
| echo "Semver check succeeded." | |
| echo "reaction=hooray" >> "$GITHUB_OUTPUT" | |
| else | |
| cat /tmp/semver-checks-stdout | |
| echo "Semver check failed." | |
| echo "reaction=eyes" >> "$GITHUB_OUTPUT" | |
| fi | |
| # - name: React to the PR based on semver-checks | |
| # if: ${{ github.event.pull_request }} | |
| # run: | | |
| # curl -L \ | |
| # -X POST \ | |
| # -H "Accept: application/vnd.github+json" \ | |
| # -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| # -H "X-GitHub-Api-Version: 2022-11-28" \ | |
| # https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/issues/${{ github.event.number }}/reactions \ | |
| # -d '{"content":"${{ steps.semver_check.outputs.reaction }}"}' | |
| - name: Delete old semver checks comments, if any | |
| if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork }} | |
| run: | | |
| # Get the old comments | |
| COMMENT_IDS=$(curl -L \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "X-GitHub-Api-Version: 2022-11-28" \ | |
| https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/issues/${{ github.event.number }}/comments | \ | |
| jq '.[] | select(.body | contains(":robot: SemverChecks :robot:")) | .id') | |
| # Delete them all | |
| for ID in $COMMENT_IDS; do | |
| curl -L \ | |
| -X DELETE \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "X-GitHub-Api-Version: 2022-11-28" \ | |
| https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/issues/comments/$ID | |
| done | |
| - name: Add a new issue comment if needed | |
| if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork }} | |
| run: | | |
| BASE_NOTE="" | |
| if [ "${{ steps.baseline.outputs.ref }}" != "main" ] && [ "${{ steps.baseline.outputs.ref }}" != "ulitebox" ]; then | |
| BASE_NOTE=":information_source: **Note:** This semver check was run against the \`${{ steps.baseline.outputs.ref }}\` branch, not \`main\` or \`ulitebox\`.\n\n" | |
| fi | |
| if [ "${{ steps.packages.outputs.has_packages }}" != "true" ]; then | |
| BODY="$(echo -e "${BASE_NOTE}"':robot: SemverChecks :robot: No semver-relevant crate changes detected; skipped cargo-semver-checks.')" | |
| elif [ -s /tmp/semver-checks-stdout ]; then | |
| BODY="$(echo -e "${BASE_NOTE}"':robot: SemverChecks :robot: :warning: Potential breaking API changes detected :warning:\n\n<details><summary>Click for details</summary>\n\n```'"$(cat /tmp/semver-checks-stdout)"'\n```\n</details>')" | |
| else | |
| BODY="$(echo -e "${BASE_NOTE}"':robot: SemverChecks :robot: No breaking API changes detected\n\nNote: this does not mean API is unchanged, or even that there are no breaking changes; simply, none of the detections triggered.')" | |
| fi | |
| curl -L \ | |
| -X POST \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "X-GitHub-Api-Version: 2022-11-28" \ | |
| https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/issues/${{ github.event.number }}/comments \ | |
| -d "$(printf '%s' "$BODY" | jq -sR '{body: .}')" | |
| - name: Require documentation from fork | |
| if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork }} | |
| env: | |
| API_URL: ${{ github.api_url }} | |
| REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| set -euo pipefail | |
| BASE_NOTE="" | |
| if [ "${{ steps.baseline.outputs.ref }}" != "main" ] && [ "${{ steps.baseline.outputs.ref }}" != "ulitebox" ]; then | |
| BASE_NOTE=":information_source: **Note:** This semver check was run against the \`${{ steps.baseline.outputs.ref }}\` branch, not \`main\` or \`ulitebox\`.\n\n" | |
| fi | |
| if [ "${{ steps.packages.outputs.has_packages }}" != "true" ]; then | |
| BODY="$(echo -e "${BASE_NOTE}"':robot: SemverChecks :robot: No semver-relevant crate changes detected; skipped cargo-semver-checks.')" | |
| elif [ -s /tmp/semver-checks-stdout ]; then | |
| BODY="$(echo -e "${BASE_NOTE}"':robot: SemverChecks :robot: :warning: Potential breaking API changes detected :warning:\n\n<details><summary>Click for details</summary>\n\n```'"$(cat /tmp/semver-checks-stdout)"'\n```\n</details>')" | |
| else | |
| BODY="$(echo -e "${BASE_NOTE}"':robot: SemverChecks :robot: No breaking API changes detected\n\nNote: this does not mean API is unchanged, or even that there are no breaking changes; simply, none of the detections triggered.')" | |
| fi | |
| PREFIX='Documenting semver-checks CI text here:' | |
| COMMENTS=$(curl --fail-with-body -sS \ | |
| -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H 'Accept: application/vnd.github+json' \ | |
| "$API_URL/repos/$REPOSITORY/issues/$PR_NUMBER/comments?per_page=100&sort=created&direction=desc") | |
| HAS_SEMVER_COMMENT=$(jq -r '[.[] | select(.body | contains(":robot: SemverChecks :robot:"))] | length > 0' <<<"$COMMENTS") | |
| if [ "$HAS_SEMVER_COMMENT" = "false" ] && [ ! -s /tmp/semver-checks-stdout ]; then | |
| echo 'No breaking changes and no prior semver-checks comment; documentation is unnecessary.' | |
| exit 0 | |
| fi | |
| LAST=$(jq -r --arg prefix "$PREFIX" '[.[] | select(.body | startswith($prefix))] | last | if . then .body else "" end' <<<"$COMMENTS") | |
| EXPECTED=$(printf '%s\n\n%s' "$PREFIX" "$BODY") | |
| if [ "$LAST" != "$EXPECTED" ]; then | |
| echo 'The latest semver documentation comment is missing or out of date.' >&2 | |
| { | |
| printf '## Semver-checks documentation required\n\n' | |
| printf 'Copy and paste the following as a comment on the PR (not in the PR description):\n\n' | |
| printf '````markdown\n%s\n````\n' "$EXPECTED" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| printf '\nCopy and paste this as a comment on the PR (not in the PR description):\n\n```markdown\n%s\n```\n' "$EXPECTED" | |
| exit 1 | |
| fi |