Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
633: prepare for migration to GitHub merge queue r=alaviss a=alaviss

## Summary
Prepare workflows and documentations for migrating from bors-ng to GitHub Merge Queue.

## Details
Other than some reformatting here and there, the main changes centers
around making our workflows aware of merge_group event and to make
them pass on PRs even when they're skipped.

For publisher, it will now operate under an environment to allow for
stricter deployment rules and signed releases in the future.

Documentation has also been updated, and a new /merge command has been
added for trimming PR description and queuing a merge.



Co-authored-by: Leorize <[email protected]>
  • Loading branch information
bors[bot] and alaviss authored Apr 25, 2023
2 parents 0e01a4b + 73388ec commit 1957b2d
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 23 deletions.
19 changes: 16 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ on:
- staging.tmp
- trying.tmp
- staging-squash-merge.tmp
# Github Merge Queue temporary branches
- gh-readonly-queue/**

pull_request:
# Only take PRs to devel
Expand All @@ -22,6 +24,9 @@ on:
- reopened
- ready_for_review

merge_group:
# Test all additions to merge queue

# Run every script actions in bash
defaults:
run:
Expand Down Expand Up @@ -141,7 +146,7 @@ jobs:
# an array due to how Github Actions process matrices.
total_batch: [2]

name: 'Test the compiler and stdlib (${{ matrix.target.name }}, batch #${{ matrix.batch }})'
name: "Test the compiler and stdlib (${{ matrix.target.name }}, batch #${{ matrix.batch }})"
runs-on: ${{ matrix.target.runner }}

steps:
Expand All @@ -154,7 +159,7 @@ jobs:
- name: Install NodeJS
uses: actions/setup-node@v3
with:
node-version: '16'
node-version: "16"

- name: Install dependencies (Linux)
if: runner.os == 'Linux'
Expand Down Expand Up @@ -499,7 +504,15 @@ jobs:

passed:
name: All check passed
needs: [binaries, test, tooling, source, source_binaries, package, test_package, orc]
needs:
- binaries
- test
- tooling
- source
- source_binaries
- package
- test_package
- orc
if: always()
runs-on: ubuntu-latest

Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/publisher.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ jobs:
publisher:
runs-on: ubuntu-latest

permissions:
actions: read
contents: write

environment:
name: release
url: ${{ steps.release.outputs.url }}

steps:
# Publish action needs a checkout
- uses: actions/checkout@v3
Expand Down Expand Up @@ -85,7 +93,8 @@ jobs:
echo "version=$(./release_manifest version)" >> $GITHUB_OUTPUT
working-directory: release-staging

- name: Create pre-release
- id: release
name: Create pre-release
uses: softprops/[email protected]
with:
prerelease: true
Expand Down
21 changes: 14 additions & 7 deletions .github/workflows/reproducible.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
- staging
- trying

# This is for passing required checks
pull_request:
merge_group:

jobs:
reprotest:
# This job is meant for testing whether the compiler can be built
Expand All @@ -25,27 +29,30 @@ jobs:
# figure out what of their changes caused the build to
# varies based on outside environment.

# Skip this for PRs
if: github.event_name != 'pull_request'

strategy:
fail-fast: false

matrix:
test:
- name: Source archive
command: './koch.py boot -d:danger && ./koch.py csource -d:danger && ./koch.py archive'
pattern: 'build/*.tar.zst'
command: "./koch.py boot -d:danger && ./koch.py csource -d:danger && ./koch.py archive"
pattern: "build/*.tar.zst"

- name: Unix binary archive
command: './koch.py boot -d:danger && ./koch.py docs --docCmd:skip && ./koch.py unixrelease'
pattern: 'build/*.tar.zst'
command: "./koch.py boot -d:danger && ./koch.py docs --docCmd:skip && ./koch.py unixrelease"
pattern: "build/*.tar.zst"

# Note: this tests the zip generation and not exe generation determinism.
#
# Testing exe generation will be done when cross-bootstrap is possible.
- name: Windows binary archive
command: './koch.py boot -d:danger && ./koch.py docs --docCmd:skip && ./koch.py winrelease'
pattern: 'build/*.zip'
command: "./koch.py boot -d:danger && ./koch.py docs --docCmd:skip && ./koch.py winrelease"
pattern: "build/*.zip"

name: '${{ matrix.test.name }} reproducibility tests'
name: "${{ matrix.test.name }} reproducibility tests"
runs-on: ubuntu-latest

steps:
Expand Down
137 changes: 137 additions & 0 deletions .github/workflows/slash-command-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
name: /merge handler

on:
repository_dispatch:
types: [merge-command]

permissions:
pull-requests: write

concurrency: merge-handler-${{ github.event.client_payload.pull_request.node_id || github.run_id }}

jobs:
merge:
if: github.event.client_payload.pull_request != null
name: Trim description and merge
runs-on: ubuntu-latest
steps:
- id: pr-data
name: Get PR data and trim PR body
uses: actions/github-script@v6
with:
script: |
const pull_id = context.payload.client_payload.pull_request.node_id;
core.debug(`Pull request ID: ${pull_id}.`);
const query = `query($id: ID!) {
node(id: $id) {
... on PullRequest {
autoMergeRequest {
mergeMethod
}
mergeQueueEntry {
state
}
closed
body
}
}
}`;
const { node: pr_info } = await github.graphql(query, { id: pull_id });
core.debug(`PR data: ${JSON.stringify(pr_info)}`);
if (pr_info.closed) {
core.notice('PR is already merged or closed.');
return;
}
if (pr_info.autoMergeRequest || pr_info.mergeQueueEntry) {
core.notice('PR is already queued for merging.');
return;
}
let [ body, body_tail ] = pr_info.body.split(/^---\s*$/m, 2);
body = body.trimEnd();
body_tail = body_tail?.trimEnd() || '';
// Only runs when the PR is still open and is not staged for merging.
core.setOutput('run', 'true');
core.setOutput('body', body);
core.setOutput('body-tail', body_tail);
if (pr_info.body !== body) {
// Only attempt PR description update if there are changes to be made
core.setOutput('update-body', 'true');
}
- if: steps.pr-data.outputs.run
id: find-comment
name: Find previously generated informational comment
uses: peter-evans/find-comment@v2
with:
issue-number: ${{ github.event.client_payload.pull_request.number }}
comment-author: github-actions[bot]
body-includes: <!-- /merge info comment -->
direction: last

# Only update the comment if there's a tail. This prevents the
# tail from being replaced due to multiple /merge calls.
- if: >-
steps.pr-data.outputs.run
&& !(steps.find-comment.outputs.comment-id
&& steps.pr-data.outputs.body-tail == '')
name: Create or update informational comment
uses: peter-evans/create-or-update-comment@v3
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.client_payload.pull_request.number }}
body: |
<!-- /merge info comment -->
<!-- Autogenerated by merge-command. DO NOT EDIT -->
Merge requested by: @${{ github.event.client_payload.github.payload.comment.user.login }}
Contents after the first section break of the PR description has been removed and preserved below:
---
<blockquote>
${{ steps.pr-data.outputs.body-tail }}
</blockquote>
edit-mode: replace
- if: steps.pr-data.outputs.run && steps.pr-data.outputs.update-body
name: Update PR description
env:
PR_URL: ${{ github.event.client_payload.pull_request.html_url }}
NEW_PR_BODY: ${{ steps.pr-data.outputs.body }}
GH_TOKEN: ${{ github.token }}
run: gh pr edit "$PR_URL" --body "$NEW_PR_BODY"

# An app token is required for CI to trigger
- if: steps.pr-data.outputs.run
id: token
name: Create app token for merges
uses: tibdex/github-app-token@v1
with:
app_id: ${{ secrets.CHORE_APP_ID }}
private_key: ${{ secrets.CHORE_APP_KEY }}

# TODO: Switch to GitHub CLI once
# https://github.com/cli/cli/issues/7213 is solved.
- if: steps.pr-data.outputs.run
name: Queue for merging
uses: actions/github-script@v6
with:
script: |
const pull_id = context.payload.client_payload.pull_request.node_id;
const queue = `mutation ($input: EnablePullRequestAutoMergeInput!) {
enablePullRequestAutoMerge(input: $input) {
clientMutationId
}
}`;
await github.graphql(queue, {
input: {
pullRequestId: pull_id
}
});
github-token: ${{ steps.token.outputs.token }}
27 changes: 27 additions & 0 deletions .github/workflows/slash-commands.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Dispatch slash commands

on:
issue_comment:
types:
- created

jobs:
dispatch_pr:
if: github.event.issue.pull_request
name: Dispatch on Pull Request comments
runs-on: ubuntu-latest
steps:
- id: token
uses: tibdex/github-app-token@v1
with:
app_id: ${{ secrets.CHORE_APP_ID }}
private_key: ${{ secrets.CHORE_APP_KEY }}

- uses: peter-evans/slash-command-dispatch@v3
with:
token: ${{ steps.token.outputs.token }}
reaction-token: ${{ steps.token.outputs.token }}
commands: |
merge
issue-type: pull-request
permission: write
29 changes: 17 additions & 12 deletions doc/ci.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,15 @@ was developed to leverage this.

1. PR is staged for merging.

2. The PR enters the merge queue and is merged to a ``staging`` branch. Multiple
PRs might be staged in this period to increase efficiency.
2. The PR enters the merge queue and is merged to a staging branch with
``gh-readonly-queue/`` prefix. Multiple PRs might be staged in this period
to increase efficiency.

3. The testing pipelines test the code, generate binaries and render
documentation.

4. Assuming that the ``staging`` branch passes all tests, ``devel`` is
fast-forwarded to the ``staging`` head commit.
4. Assuming that the staging branch passes all tests, ``devel`` is
fast-forwarded to the staging branch head commit.

5. The "Publish" pipeline deploys the rendered documentation and binaries
generated by the testing pipeline earlier in the staging branch.
Expand All @@ -103,16 +104,16 @@ Assumptions in CI design

This lifecycle has a number of useful properties which we use in our approach to CI as follows:

* Code entering ``devel`` must have passed through ``staging``, and that
``staging`` will become the new ``devel``:
* Code entering ``devel`` must have passed through the staging branch, and that
``devel`` will be fast-forwarded to this branch:

* This allows us to run crucial evaluation tasks on ``staging`` only, and
when that passes and ``devel`` is fast-forwarded to ``staging``, we can
access prior runs and obtain build results.
* This allows us to run crucial evaluation tasks on the staging branch only,
and when that passes and ``devel`` is fast-forwarded, we can access prior
runs and obtain build results.

* Only "light" tests have to be run on PRs to help developers debug their code
before it is reviewed by a human. More time-consuming tests that are not
likely to fail can be run later when the PR enters ``staging``.
likely to fail can be run later when the PR enters the merge queue.

Pipelines
=========
Expand Down Expand Up @@ -220,7 +221,11 @@ the `Reproducible builds project <https://reproducible-builds.org/>`_ for more
information on the testing criteria.

This pipeline has a rather long runtime, and rarely fails, so it is only run
once a PR enters ``staging``.
once a PR enters the merge queue.

As a workaround for GitHub's lack of support for different criteria for merge
versus entering the queue, this pipeline will be skipped and always report
success for PRs.

This pipeline is developed with a rather standard matrix and does not perform
any data sharing. Working with this pipeline only requires understanding on
Expand All @@ -230,7 +235,7 @@ the `reprotest <https://pypi.org/project/reprotest/>`_ tool.
---------

Publishes build results from prior run of the "Build and test" pipeline on
``staging`` branch. Changes to the public API of "Build and test" must be
the staging branch. Changes to the public API of "Build and test" must be
tested against "Publish".

This pipeline will perform pushes to the repository, so a lot of care must be
Expand Down

0 comments on commit 1957b2d

Please sign in to comment.