Skip to content

Commit

Permalink
build: Move "Test plugin upgrades" to a post-build workflow
Browse files Browse the repository at this point in the history
GitHub has an unfortunate behavior in that workflow artifacts are not
available via the API until the entire workflow has completed. This
means that the "Test plugin upgrades" job in the build workflow
unnecessarily delays the availability of the build artifact for Jetpack
Live Branches and future wpcom automated testing for 6 or so minutes.

To get around this, we create a new "Post-Build" workflow that is
triggered by `workflow_run` after the Build workflow completes. But
since this new workflow isn't automatically attached to the PR, we have
to make API calls to get it to show up there.

This is a second attempt at Automattic#25892, which had to be reverted as using
the Actions app put the checks into the "suite" of a random workflow.
  • Loading branch information
anomiex committed Jan 9, 2023
1 parent 2b11b97 commit 9e498d4
Show file tree
Hide file tree
Showing 4 changed files with 307 additions and 50 deletions.
70 changes: 70 additions & 0 deletions .github/actions/check-run/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: "Check Run"
description: "Create or update a check run. This is a simple wrapper around GitHub's checks API, https://docs.github.com/en/rest/checks/runs."
inputs:
id:
description: "Check run ID to update. If not given, a new run will be created"
sha:
description: "The SHA of the commit."
name:
description: "The name of the check. For example, \"code-coverage\"."
status:
description: "The current status. Can be one of: `queued`, `in_progress`, `completed`"
conclusion:
description: "The final conclusion of the check. Can be one of: `action_required`, `cancelled`, `failure`, `neutral`, `success`, `skipped`, `timed_out`"
title:
description: "Title of the check. Shown in the PR's checks list."
summary:
description: "Summary of the check. Can contain Markdown."
token:
description: "App access token. See https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app for how to get one."
outputs:
id:
description: "Check run ID."
value: ${{ steps.run.outputs.id }}
runs:
using: composite
steps:
- id: run
shell: bash
env:
ID: ${{ inputs.id }}
SHA: ${{ inputs.sha }}
NAME: ${{ inputs.name }}
STATUS: ${{ inputs.status }}
CONCLUSION: ${{ inputs.conclusion }}
TITLE: ${{ inputs.title }}
SUMMARY: ${{ inputs.summary }}
TOKEN: ${{ inputs.token }}
run: |
if [[ -n "$ID" ]]; then
METHOD=PATCH
URL="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/check-runs/$ID"
else
METHOD=POST
URL="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/check-runs"
fi
DATA="{}"
if [[ -n "$NAME" ]]; then
DATA="$(jq --arg v "$NAME" '.name |= $v' <<<"$DATA")"
fi
if [[ -n "$SHA" ]]; then
DATA="$(jq --arg v "$SHA" '.head_sha |= $v' <<<"$DATA")"
fi
if [[ -n "$STATUS" ]]; then
DATA="$(jq --arg v "$STATUS" '.status |= $v' <<<"$DATA")"
fi
if [[ -n "$CONCLUSION" ]]; then
DATA="$(jq --arg v "$CONCLUSION" '.conclusion |= $v' <<<"$DATA")"
fi
if [[ -n "$TITLE" ]]; then
DATA="$(jq --arg v "$TITLE" '.output.title |= $v' <<<"$DATA")"
fi
if [[ -n "$SUMMARY" ]]; then
DATA="$(jq --arg v "$SUMMARY" '.output.summary |= $v' <<<"$DATA")"
fi
echo "Data: $DATA"
JSON="$(curl -v -X "$METHOD" --header "authorization: Bearer $TOKEN" --url "$URL" --data "$DATA")"
echo "$JSON"
echo "id=$(jq -r .id <<<"$JSON")" >> "$GITHUB_OUTPUT"
50 changes: 0 additions & 50 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,56 +132,6 @@ jobs:
comment_id: +COMMENT_ID,
} );
upgrade_test:
name: Test plugin upgrades
runs-on: ubuntu-latest
needs: build
if: needs.build.outputs.any_plugins == 'true'
timeout-minutes: 10 # 2022-03-04: Successful runs seem to take about 3 minutes, but give some extra time for the downloads.
services:
db:
image: mariadb:latest
env:
MARIADB_ROOT_PASSWORD: wordpress
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
container:
image: ghcr.io/automattic/jetpack-wordpress-dev:latest
env:
WP_DOMAIN: localhost
WP_ADMIN_USER: wordpress
WP_ADMIN_EMAIL: wordpress@example.com
WP_ADMIN_PASSWORD: wordpress
WP_TITLE: Hello World
MYSQL_HOST: db:3306
MYSQL_DATABASE: wordpress
MYSQL_USER: root
MYSQL_PASSWORD: wordpress
HOST_PORT: 80
ports:
- 80:80
steps:
- uses: actions/checkout@v3
with:
path: monorepo

- name: Download build artifact
uses: actions/download-artifact@v3
with:
name: jetpack-build
- name: Extract build archive
run: tar --xz -xvvf build.tar.xz

- name: Setup WordPress
run: monorepo/.github/files/test-plugin-update/setup.sh

- name: Prepare plugin zips
run: monorepo/.github/files/test-plugin-update/prepare-zips.sh

- name: Test upgrades
run: monorepo/.github/files/test-plugin-update/test.sh

jetpack_beta:
name: Create artifact for Jetpack Beta plugin
runs-on: ubuntu-latest
Expand Down
236 changes: 236 additions & 0 deletions .github/workflows/post-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
name: Post-Build
on:
workflow_run:
types: [ 'completed' ]
workflows:
- Build
concurrency:
# Cancel concurrent jobs on pull_request but not push, by including the run_id in the concurrency group for the latter.
group: post-build-${{ github.event.workflow_run.event == 'push' && github.run_id || 'pr' }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true

env:
COMPOSER_ROOT_VERSION: "dev-trunk"
SUMMARY: Post-Build run [#${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for Build run [#${{ github.event.workflow_run.id }}](${{ github.event.workflow_run.html_url }})

# Note the job logic here is a bit unusual. That's because this workflow is triggered by `workflow_run`, and so is not shown on the PR by default.
# Instead we have to manually report back, including where we could normally just skip or let a failure be handled.
# - If the "Build" job failed, we need to set our status as failed too (build_failed).
# - If the find_artifact job fails for some reason, we need a step to explicitly report that back.
# - If no plugins are found, we need to explicitly report back a "skipped" status.
# - And the upgrade_test job both explicitly sets "in progress" at its start and updates at its end.

jobs:
setup:
name: Setup
runs-on: ubuntu-latest
timeout-minutes: 2 # 2022-12-20: Seems like it should be fast.
outputs:
token: ${{ steps.get_token.outputs.token }}
upgrade_check: ${{ steps.upgrade_check.outputs.id }}
steps:
- name: Get token
id: get_token
uses: getsentry/action-github-app-token@v2.0.0
with:
app_id: ${{ secrets.JP_LAUNCH_CONTROL_ID }}
private_key: ${{ secrets.JP_LAUNCH_CONTROL_KEY }}

- uses: actions/checkout@v3

- name: 'Create "Test plugin upgrades" check'
id: upgrade_check
uses: ./.github/actions/check-run
with:
name: Test plugin upgrades
sha: ${{ github.event.workflow_run.head_sha }}
status: queued
summary: |
${{ env.SUMMARY }}
token: ${{ steps.get_token.outputs.token }}

build_failed:
name: Handle build failure
runs-on: ubuntu-latest
needs: setup
if: github.event.workflow_run.conclusion != 'success'
timeout-minutes: 2 # 2022-08-26: Seems like it should be fast.
steps:
- uses: actions/checkout@v3
- name: 'Mark "Test plugin upgrades" cancelled'
uses: ./.github/actions/check-run
with:
id: ${{ needs.setup.outputs.upgrade_check }}
conclusion: cancelled
title: Build failed
summary: |
${{ env.SUMMARY }}
Post-build run aborted because the build did not succeed.
token: ${{ needs.setup.outputs.token }}

find_artifact:
name: Find artifact
runs-on: ubuntu-latest
needs: setup
if: github.event.workflow_run.conclusion == 'success'
timeout-minutes: 2 # 2022-08-26: Seems like it should be fast.
outputs:
zip_url: ${{ steps.run.outputs.zip_url }}
any_plugins: ${{ steps.run.outputs.any_plugins }}
steps:
- uses: actions/checkout@v3
- name: Find artifact
id: run
env:
TOKEN: ${{ github.token }}
URL: ${{ github.event.workflow_run.artifacts_url }}
run: |
for (( i=1; i<=5; i++ )); do
[[ $i -gt 1 ]] && sleep 10
echo "::group::Fetch list of artifacts (attempt $i/5)"
JSON="$(curl -v -L --get \
--header "Authorization: token $TOKEN" \
--url "$URL"
)"
echo "$JSON"
echo "::endgroup::"
ZIPURL="$(jq -r '.artifacts[] | select( .name == "jetpack-build" ) | .archive_download_url' <<<"$JSON")"
PLUGINS="$(jq -r '.artifacts[] | select( .name == "plugins" )' <<<"$JSON")"
if [[ -n "$ZIPURL" ]]; then
break
fi
done
[[ -z "$ZIPURL" ]] && { echo "::error::Failed to find artifact."; exit 1; }
echo "Zip URL: $ZIPURL"
echo "::set-output name=zip_url::${ZIPURL}"
if [[ -z "$PLUGINS" ]]; then
echo "Any plugins? No"
echo "::set-output name=any_plugins::false"
else
echo "Any plugins? Yes"
echo "::set-output name=any_plugins::true"
fi
- name: 'Mark "Test plugin upgrades" failed'
if: ${{ ! success() }}
uses: ./.github/actions/check-run
with:
id: ${{ needs.setup.outputs.upgrade_check }}
conclusion: failure
title: Failed to find build artifact
summary: |
${{ env.SUMMARY }}
Post-build run aborted because the "Find artifact" step failed.
token: ${{ needs.setup.outputs.token }}

no_plugins:
name: Handle no-plugins
runs-on: ubuntu-latest
needs: [ setup, find_artifact ]
if: needs.find_artifact.outputs.any_plugins == 'false'
timeout-minutes: 2 # 2022-08-26: Seems like it should be fast.
steps:
- uses: actions/checkout@v3
- name: 'Mark "Test plugin upgrades" skipped'
uses: ./.github/actions/check-run
with:
id: ${{ needs.setup.outputs.upgrade_check }}
conclusion: skipped
title: No plugins were built
summary: |
${{ env.SUMMARY }}
Post-build run skipped because no plugins were built.
token: ${{ needs.setup.outputs.token }}

upgrade_test:
name: Test plugin upgrades
runs-on: ubuntu-latest
needs: [ setup, find_artifact ]
if: needs.find_artifact.outputs.any_plugins == 'true'
timeout-minutes: 15 # 2022-08-26: Successful runs seem to take about 6 minutes, but give some extra time for the downloads.
services:
db:
image: mariadb:latest
env:
MARIADB_ROOT_PASSWORD: wordpress
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
container:
image: ghcr.io/automattic/jetpack-wordpress-dev:latest
env:
WP_DOMAIN: localhost
WP_ADMIN_USER: wordpress
WP_ADMIN_EMAIL: wordpress@example.com
WP_ADMIN_PASSWORD: wordpress
WP_TITLE: Hello World
MYSQL_HOST: db:3306
MYSQL_DATABASE: wordpress
MYSQL_USER: root
MYSQL_PASSWORD: wordpress
HOST_PORT: 80
ports:
- 80:80
steps:
- uses: actions/checkout@v3
with:
path: monorepo

- name: Notify check in progress
uses: ./monorepo/.github/actions/check-run
with:
id: ${{ needs.setup.outputs.upgrade_check }}
status: in_progress
title: Test started...
summary: |
${{ env.SUMMARY }}
See run [#${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.
token: ${{ needs.setup.outputs.token }}

- name: Download build artifact
env:
TOKEN: ${{ github.token }}
ZIPURL: ${{ needs.find_artifact.outputs.zip_url }}
shell: bash
run: |
for (( i=1; i<=2; i++ )); do
[[ $i -gt 1 ]] && sleep 10
echo "::group::Downloading artifact (attempt $i/2)"
curl -v -L --get \
--header "Authorization: token $TOKEN" \
--url "$ZIPURL" \
--output "artifact.zip"
echo "::endgroup::"
if [[ -e "artifact.zip" ]] && zipinfo artifact.zip &>/dev/null; then
break
fi
done
[[ ! -e "artifact.zip" ]] && { echo "::error::Failed to download artifact."; exit 1; }
unzip artifact.zip
tar --xz -xvvf build.tar.xz
- name: Setup WordPress
run: monorepo/.github/files/test-plugin-update/setup.sh

- name: Prepare plugin zips
run: monorepo/.github/files/test-plugin-update/prepare-zips.sh

- name: Test upgrades
run: monorepo/.github/files/test-plugin-update/test.sh

- name: Notify final status
if: always()
uses: ./monorepo/.github/actions/check-run
with:
id: ${{ needs.setup.outputs.upgrade_check }}
conclusion: ${{ job.status }}
title: ${{ job.status == 'success' && 'Tests passed' || job.status == 'cancelled' && 'Cancelled' || 'Tests failed' }}
summary: |
${{ env.SUMMARY }}
See run [#${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.
token: ${{ needs.setup.outputs.token }}
1 change: 1 addition & 0 deletions .github/workflows/slack-workflow-failed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- Build Docker
- Tests
- Gardening
- Post-Build
- PR is up-to-date
branches: [ 'trunk', 'prerelease', '*/branch-*' ]

Expand Down

0 comments on commit 9e498d4

Please sign in to comment.