# Push a release to the lean4-pr-releases repository, whenever someone pushes to a PR branch. # This needs to run with the `secrets.PR_RELEASES_TOKEN` token available, # but PR branches will generally come from forks, # so it is not possible to run this using the `pull_request` or `pull_request_target` workflows. # Instead we use `workflow_run`, which essentially allows us to escalate privileges # (but only runs the CI as described in the `master` branch, not in the PR branch). name: PR release on: workflow_run: # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run workflows: [CI] types: [completed] jobs: on-success: runs-on: ubuntu-latest if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' && github.repository == 'leanprover/lean4' steps: - name: Retrieve information about the original workflow uses: potiuk/get-workflow-origin@v1_1 # https://github.com/marketplace/actions/get-workflow-origin # This action is deprecated and archived, but it seems hard to find a better solution for getting the PR number # see https://github.com/orgs/community/discussions/25220 for some discussion id: workflow-info with: token: ${{ secrets.GITHUB_TOKEN }} sourceRunId: ${{ github.event.workflow_run.id }} - name: Download artifact from the previous workflow. if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} id: download-artifact uses: dawidd6/action-download-artifact@v2 # https://github.com/marketplace/actions/download-workflow-artifact with: run_id: ${{ github.event.workflow_run.id }} path: artifacts name: build-.* name_is_regexp: true - name: Push branch and tag if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} run: | git init --bare lean4.git git -C lean4.git remote add origin https://github.com/${{ github.repository_owner }}/lean4.git git -C lean4.git fetch -n origin master git -C lean4.git fetch -n origin "${{ steps.workflow-info.outputs.sourceHeadSha }}" git -C lean4.git tag -f pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} "${{ steps.workflow-info.outputs.sourceHeadSha }}" git -C lean4.git remote add pr-releases https://foo:'${{ secrets.PR_RELEASES_TOKEN }}'@github.com/${{ github.repository_owner }}/lean4-pr-releases.git git -C lean4.git push -f pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} - name: Delete existing release if present if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} run: | # Try to delete any existing release for the current PR. gh release delete --repo ${{ github.repository_owner }}/lean4-pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} -y || true env: GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }} - name: Release if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} uses: softprops/action-gh-release@v1 with: name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} # There are coredumps files here as well, but all in deeper subdirectories. files: artifacts/*/* fail_on_unmatched_files: true draft: false tag_name: pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} repository: ${{ github.repository_owner }}/lean4-pr-releases env: # The token used here must have `workflow` privileges. GITHUB_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }} - name: Add label if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} uses: actions/github-script@v7 with: script: | await github.rest.issues.addLabels({ issue_number: ${{ steps.workflow-info.outputs.pullRequestNumber }}, owner: context.repo.owner, repo: context.repo.repo, labels: ['toolchain-available'] }) # Next, determine the most recent nightly release in this PR's history. - name: Find most recent nightly in feature branch id: most-recent-nightly-tag if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} run: | git -C lean4.git remote add nightly https://github.com/leanprover/lean4-nightly.git git -C lean4.git fetch nightly '+refs/tags/nightly-*:refs/tags/nightly-*' git -C lean4.git tag --merged "${{ steps.workflow-info.outputs.sourceHeadSha }}" --list "nightly-*" \ | sort -rV | head -n 1 | sed "s/^nightly-*/MOST_RECENT_NIGHTLY=/" | tee -a $GITHUB_ENV - name: 'Setup jq' if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} uses: dcarbone/install-jq-action@v1.0.1 # Check that the most recently nightly coincides with 'git merge-base HEAD master' - name: Check merge-base and nightly-testing-YYYY-MM-DD if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} id: ready run: | echo "Most recent nightly in your branch: $MOST_RECENT_NIGHTLY" NIGHTLY_SHA=$(git -C lean4.git rev-parse "nightly-$MOST_RECENT_NIGHTLY^{commit}") echo "SHA of most recent nightly: $NIGHTLY_SHA" MERGE_BASE_SHA=$(git -C lean4.git merge-base origin/master "${{ steps.workflow-info.outputs.sourceHeadSha }}") echo "SHA of merge-base: $MERGE_BASE_SHA" if [ "$NIGHTLY_SHA" = "$MERGE_BASE_SHA" ]; then echo "Most recent nightly tag agrees with the merge base." REMOTE_BRANCHES=$(git ls-remote -h https://github.com/leanprover-community/mathlib4.git nightly-testing-$MOST_RECENT_NIGHTLY) if [[ -n "$REMOTE_BRANCHES" ]]; then echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' branch." MESSAGE="" else echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' branch." MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the 'nightly-testing-$MOST_RECENT_NIGHTLY' branch does not exist there yet. We will retry when you push more commits. It may be necessary to rebase onto 'nightly' tomorrow." fi else echo "The most recently nightly tag on this branch has SHA: $NIGHTLY_SHA" echo "but 'git merge-base origin/master HEAD' reported: $MERGE_BASE_SHA" git -C lean4.git log -10 origin/master MESSAGE="- ❗ Mathlib CI will not be attempted unless you rebase your PR onto the 'nightly' branch." fi if [[ -n "$MESSAGE" ]]; then echo "Checking existing messages" # Use GitHub API to check if a comment already exists existing_comment=$(curl -L -s -H "Authorization: token ${{ secrets.MATHLIB4_BOT }}" \ -H "Accept: application/vnd.github.v3+json" \ "https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments" \ | jq '.[] | select(.body | startswith("- ❗ Mathlib") or startswith("- ✅ Mathlib") or startswith("- ❌ Mathlib") or startswith("- 💥 Mathlib") or startswith("- 🟡 Mathlib"))') existing_comment_id=$(echo "$existing_comment" | jq -r .id) existing_comment_body=$(echo "$existing_comment" | jq -r .body) if [[ "$existing_comment_body" != *"$MESSAGE"* ]]; then MESSAGE="$MESSAGE ($(date "+%Y-%m-%d %H:%M:%S"))" echo "Posting message to the comments: $MESSAGE" # Append new result to the existing comment or post a new comment # It's essential we use the MATHLIB4_BOT token here, so that Mathlib CI can subsequently edit the comment. if [ -z "$existing_comment_id" ]; then # Post new comment with a bullet point echo "Posting as new comment at leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments" curl -L -s \ -X POST \ -H "Authorization: token ${{ secrets.MATHLIB4_BOT }}" \ -H "Accept: application/vnd.github.v3+json" \ -d "$(jq --null-input --arg val "$MESSAGE" '{"body": $val}')" \ "https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments" else # Append new result to the existing comment echo "Appending to existing comment at leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments" curl -L -s \ -X PATCH \ -H "Authorization: token ${{ secrets.MATHLIB4_BOT }}" \ -H "Accept: application/vnd.github.v3+json" \ -d "$(jq --null-input --arg existing "$existing_comment_body" --arg message "$MESSAGE" '{"body":($existing + "\n" + $message)}')" \ "https://api.github.com/repos/leanprover/lean4/issues/comments/$existing_comment_id" fi else echo "The message already exists in the comment body." fi echo "mathlib_ready=false" >> $GITHUB_OUTPUT else echo "mathlib_ready=true" >> $GITHUB_OUTPUT fi # We next automatically create a Mathlib branch using this toolchain. # Mathlib CI will be responsible for reporting back success or failure # to the PR comments asynchronously. - name: Cleanup workspace if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' run: | sudo rm -rf * # Checkout the mathlib4 repository with all branches - name: Checkout mathlib4 repository if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' uses: actions/checkout@v3 with: repository: leanprover-community/mathlib4 token: ${{ secrets.MATHLIB4_BOT }} ref: nightly-testing fetch-depth: 0 # This ensures we check out all tags and branches. - name: Check if branch exists if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' id: check_branch run: | git config user.name "leanprover-community-mathlib4-bot" git config user.email "leanprover-community-mathlib4-bot@users.noreply.github.com" if git branch -r | grep -q "nightly-testing-${MOST_RECENT_NIGHTLY}"; then BASE=nightly-testing-${MOST_RECENT_NIGHTLY} else echo "This shouldn't be possible: couldn't find a 'nightly-testing-${MOST_RECENT_NIGHTLY}' branch at Mathlib. Falling back to 'nightly-testing'." BASE=nightly-testing fi echo "Using base branch: $BASE" git checkout $BASE EXISTS=$(git ls-remote --heads origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} | wc -l) echo "Branch exists: $EXISTS" if [ "$EXISTS" = "0" ]; then echo "Branch does not exist, creating it." git checkout -b lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain git add lean-toolchain git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}" else echo "Branch already exists, pushing an empty commit." git checkout lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} # The Mathlib `nightly-testing` or `nightly-testing-YYYY-MM-DD` branch may have moved since this branch was created, so merge their changes. git merge $BASE --strategy-option ours --no-commit --allow-unrelated-histories git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}" fi - name: Push changes if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' run: | git push origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}