PR release #170
This file contains 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
# 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: Report release status | |
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
await github.rest.repos.createCommitStatus({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
sha: "${{ steps.workflow-info.outputs.sourceHeadSha }}", | |
state: "success", | |
context: "PR toolchain", | |
description: "${{ github.repository_owner }}/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}", | |
}); | |
- 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 | |
- name: Report mathlib base | |
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }} && steps.ready.outputs.mathlib_ready == 'true' | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
const description = | |
process.env.MOST_RECENT_NIGHTLY ? | |
"nightly-" + process.env.MOST_RECENT_NIGHTLY : | |
"not branched off nightly"; | |
await github.rest.repos.createCommitStatus({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
sha: "${{ steps.workflow-info.outputs.sourceHeadSha }}", | |
state: "success", | |
context: "PR branched off:", | |
description: description, | |
}); | |
# 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 }} |