esp-hal/.github/workflows/dispatch.yml
Kirill Mikhailov b5aca4e69e
deduplicate huge bash code-blocks in dispatch.yml (#4937)
* deduplicate huge bash code-blocks in `dispatch.yml`

* fix function name after change

* format
2026-02-09 07:47:44 +00:00

596 lines
21 KiB
YAML

name: Dispatch
on:
# labels on PRs
pull_request_target:
types: [labeled]
# slash commands & trust commands
issue_comment:
types: [created, edited]
permissions:
actions: write
pull-requests: write
contents: read
jobs:
# ---------------------------------------------------------------------------
# LABEL: TRUSTED AUTHOR
# ---------------------------------------------------------------------------
label-trusted-author:
if: github.event_name == 'pull_request_target' &&
github.event.label.name == 'trusted-author'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Get PR author login
id: pr
uses: actions/github-script@v7
with:
script: |
const login = (context.payload.pull_request.user.login || '').toLowerCase();
if (!login) {
core.setFailed('Could not determine PR author login');
return;
}
core.setOutput('login', login);
- id: find
uses: peter-evans/find-comment@v3
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: github-actions[bot]
body-includes: "[HIL trust list]"
- name: Upsert trust list for author
id: upsert
uses: actions/github-script@v7
with:
script: |
const { upsertTrusted } = require('./.github/scripts/hil-trust.js');
const existing = `${{ toJson(steps.find.outputs.comment-body || '') }}`;
const login = '${{ steps.pr.outputs.login }}'.toLowerCase();
const { body } = upsertTrusted(existing, login);
core.setOutput('body', body);
- uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
comment-id: ${{ steps.find.outputs.comment-id }}
body: ${{ steps.upsert.outputs.body }}
edit-mode: replace
- uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Author **@${{ steps.pr.outputs.login }}** was trusted for this PR via the `trusted-author` label.
They can now use `/hil quick`, `/hil full` and `/hil <CHIPS>` and their features.
# ---------------------------------------------------------------------------
# TRUST MANAGEMENT (/trust, /revoke)
# ---------------------------------------------------------------------------
trust:
if: >
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
(github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'OWNER') &&
startsWith(github.event.comment.body, '/trust ')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Parse login
id: parse
uses: actions/github-script@v7
with:
script: |
const { parseTrustCommand } = require('./.github/scripts/hil-trust.js');
const res = parseTrustCommand(context.payload.comment.body, 'trust');
if (res.error) core.setFailed(res.error);
core.setOutput('login', res.login);
- id: find
uses: peter-evans/find-comment@v3
with:
issue-number: ${{ github.event.issue.number }}
comment-author: github-actions[bot]
body-includes: "[HIL trust list]"
- name: Upsert trust list
id: upsert
uses: actions/github-script@v7
with:
script: |
const { upsertTrusted } = require('./.github/scripts/hil-trust.js');
const existing = `${{ toJson(steps.find.outputs.comment-body || '') }}`;
const login = '${{ steps.parse.outputs.login }}'.toLowerCase();
const { body } = upsertTrusted(existing, login);
core.setOutput('body', body);
- uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
comment-id: ${{ steps.find.outputs.comment-id }}
body: ${{ steps.upsert.outputs.body }}
edit-mode: replace
- uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
# separate short confirmation comment
body: "Trusted **@${{ steps.parse.outputs.login }}** for this PR. They can now use `/hil quick`, `/hil full` and `/hil <CHIPS>` and their features."
revoke:
if: >
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
(github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'OWNER') &&
startsWith(github.event.comment.body, '/revoke ')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Parse login
id: parse
uses: actions/github-script@v7
with:
script: |
const { parseTrustCommand } = require('./.github/scripts/hil-trust.js');
const res = parseTrustCommand(context.payload.comment.body, 'revoke');
if (res.error) core.setFailed(res.error);
core.setOutput('login', res.login);
- id: find
uses: peter-evans/find-comment@v3
with:
issue-number: ${{ github.event.issue.number }}
comment-author: github-actions[bot]
body-includes: "[HIL trust list]"
- name: Remove from trust list
id: update
uses: actions/github-script@v7
with:
script: |
const { revokeTrusted } = require('./.github/scripts/hil-trust.js');
const existing = `${{ toJson(steps.find.outputs.comment-body || '') }}`;
const login = '${{ steps.parse.outputs.login }}'.toLowerCase();
const { body } = revokeTrusted(existing, login);
core.setOutput('body', body);
- uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
comment-id: ${{ steps.find.outputs.comment-id }}
body: ${{ steps.update.outputs.body }}
edit-mode: replace
- uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
body: "Revoked **@${{ steps.parse.outputs.login }}** for this PR."
# ---------------------------------------------------------------------------
# SLASH-BASED DISPATCHES (/hil quick, /hil full, /hil <chips...>)
# ---------------------------------------------------------------------------
auth:
# Only PR comments need auth
if: github.event_name == 'issue_comment' && github.event.issue.pull_request
runs-on: ubuntu-latest
outputs:
allowed: ${{ steps.check.outputs.allowed }}
steps:
- id: check
uses: actions/github-script@v7
with:
script: |
const assoc = context.payload.comment.author_association;
const commenter = context.payload.comment.user.login.toLowerCase();
const pr = context.payload.issue.number;
if (assoc === 'MEMBER' || assoc === 'OWNER') {
core.setOutput('allowed', 'true');
return;
}
const { owner, repo } = context.repo;
const comments = await github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number: pr, per_page: 100 }
);
const trust = comments.find(c =>
c.user?.login === 'github-actions[bot]' &&
typeof c.body === 'string' &&
c.body.includes('HIL_TRUST_JSON')
);
let allowed = false;
if (trust) {
const m = trust.body.match(/<!--\s*HIL_TRUST_JSON\s*([\s\S]*?)\s*HIL_TRUST_JSON\s*-->/);
if (m && m[1]) {
try {
const data = JSON.parse(m[1]);
const list = (data.trusted || []).map(s => String(s).toLowerCase());
allowed = list.includes(commenter);
} catch {}
}
}
core.setOutput('allowed', allowed ? 'true' : 'false');
hil-quick:
needs: auth
if: github.event_name == 'issue_comment' &&
needs.auth.outputs.allowed == 'true' &&
startsWith(github.event.comment.body, '/hil quick')
runs-on: ubuntu-latest
outputs:
run_id: ${{ steps.find-run.outputs.run_id }}
comment_id: ${{ steps.comment.outputs.comment-id }}
steps:
- uses: actions/checkout@v4 # for `require`
with:
fetch-depth: 1
- name: Parse tests
id: parse-tests
uses: actions/github-script@v7
with:
script: |
const { parseTests } = require('./.github/scripts/hil-parse.js');
core.setOutput('tests', parseTests(context.payload.comment.body));
- name: Dispatch HIL (quick)
uses: benc-uk/workflow-dispatch@v1
with:
workflow: hil.yml
ref: ${{ github.event.repository.default_branch }}
inputs: |
{
"repository": "${{ github.repository }}",
"branch": "refs/pull/${{ github.event.issue.number }}/head",
"matrix": "quick",
"pr_number": "${{ github.event.issue.number }}",
"chips": "",
"tests": "${{ steps.parse-tests.outputs.tests }}"
}
- name: Find HIL run URL (quick)
id: find-run
uses: actions/github-script@v7
with:
script: |
const { findHilRun } = require('./.github/scripts/hil-find-run.js');
const { runId, body } = await findHilRun({
github,
context,
pr: context.payload.issue.number,
selector: 'quick',
tests: '${{ steps.parse-tests.outputs.tests }}',
});
core.setOutput('run_id', runId);
core.setOutput('body', body);
- name: Confirm in PR
id: comment
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
body: ${{ steps.find-run.outputs.body }}
hil-quick-status:
needs: hil-quick
if: needs.hil-quick.outputs.run_id != '' && needs.hil-quick.outputs.comment_id != ''
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # for `require`
with:
fetch-depth: 1
- name: Wait for quick HIL run and update comment
uses: actions/github-script@v7
with:
script: |
const { pollRun } = require('./.github/scripts/hil-status.js');
await pollRun({
github,
context,
runId: Number('${{ needs.hil-quick.outputs.run_id }}'),
commentId: Number('${{ needs.hil-quick.outputs.comment_id }}'),
kind: 'HIL (quick)',
});
hil-full:
needs: auth
if: github.event_name == 'issue_comment' &&
needs.auth.outputs.allowed == 'true' &&
startsWith(github.event.comment.body, '/hil full')
runs-on: ubuntu-latest
outputs:
run_id: ${{ steps.find-run.outputs.run_id }}
comment_id: ${{ steps.comment.outputs.comment-id }}
steps:
- uses: actions/checkout@v4 # for `require`
with:
fetch-depth: 1
- name: Parse tests
id: parse-tests
uses: actions/github-script@v7
with:
script: |
const { parseTests } = require('./.github/scripts/hil-parse.js');
core.setOutput('tests', parseTests(context.payload.comment.body));
- name: Dispatch HIL (full)
uses: benc-uk/workflow-dispatch@v1
with:
workflow: hil.yml
ref: ${{ github.event.repository.default_branch }}
inputs: |
{
"repository": "${{ github.repository }}",
"branch": "refs/pull/${{ github.event.issue.number }}/head",
"matrix": "full",
"pr_number": "${{ github.event.issue.number }}",
"chips": "",
"tests": "${{ steps.parse-tests.outputs.tests }}"
}
- name: Find HIL run URL (full)
id: find-run
uses: actions/github-script@v7
with:
script: |
const { findHilRun } = require('./.github/scripts/hil-find-run.js');
const { runId, body } = await findHilRun({
github,
context,
pr: context.payload.issue.number,
selector: 'full',
tests: '${{ steps.parse-tests.outputs.tests }}',
});
core.setOutput('run_id', runId);
core.setOutput('body', body);
- name: Confirm in PR
id: comment
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
body: ${{ steps.find-run.outputs.body }}
hil-full-status:
needs: hil-full
if: needs.hil-full.outputs.run_id != '' && needs.hil-full.outputs.comment_id != ''
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # for `require`
with:
fetch-depth: 1
- name: Wait for full HIL run and update comment
uses: actions/github-script@v7
with:
script: |
const { pollRun } = require('./.github/scripts/hil-status.js');
await pollRun({
github,
context,
runId: Number('${{ needs.hil-full.outputs.run_id }}'),
commentId: Number('${{ needs.hil-full.outputs.comment_id }}'),
kind: 'HIL (full)',
});
# ---------------------------------------------------------------------------
# PER-CHIP HIL: /hil esp32c3 [esp32s3 ...] [--tests ...]
# ---------------------------------------------------------------------------
hil-chips:
needs: auth
if: github.event_name == 'issue_comment' &&
needs.auth.outputs.allowed == 'true' &&
startsWith(github.event.comment.body, '/hil ') &&
!startsWith(github.event.comment.body, '/hil quick') &&
!startsWith(github.event.comment.body, '/hil full')
runs-on: ubuntu-latest
outputs:
run_id: ${{ steps.find-run.outputs.run_id }}
comment_id: ${{ steps.comment.outputs.comment-id }}
steps:
- uses: actions/checkout@v4 # for `require`
with:
fetch-depth: 1
- name: Parse chips
id: parse
uses: actions/github-script@v7
with:
script: |
const { parseChips } = require('./.github/scripts/hil-parse.js');
const res = parseChips(context.payload.comment.body);
core.setOutput('chips', res.chips);
core.setOutput('chips_label', res.chipsLabel);
core.setOutput('error', res.error);
- name: Parse tests
id: parse-tests
uses: actions/github-script@v7
with:
script: |
const { parseTests } = require('./.github/scripts/hil-parse.js');
core.setOutput('tests', parseTests(context.payload.comment.body));
- name: Report invalid chips
if: steps.parse.outputs.chips == '' && steps.parse.outputs.error != ''
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
body: |
@${{ github.event.comment.user.login }}, HIL **per-chip** request failed: ${{ steps.parse.outputs.error }}
- name: Dispatch HIL (per-chip)
if: steps.parse.outputs.chips != ''
uses: benc-uk/workflow-dispatch@v1
with:
workflow: hil.yml
ref: ${{ github.event.repository.default_branch }}
inputs: |
{
"repository": "${{ github.repository }}",
"branch": "refs/pull/${{ github.event.issue.number }}/head",
"matrix": "chips",
"pr_number": "${{ github.event.issue.number }}",
"chips": "${{ steps.parse.outputs.chips }}",
"tests": "${{ steps.parse-tests.outputs.tests }}"
}
- name: Find HIL run URL (per-chip)
if: steps.parse.outputs.chips != ''
id: find-run
uses: actions/github-script@v7
with:
script: |
const { findHilRun } = require('./.github/scripts/hil-find-run.js');
const { runId, body } = await findHilRun({
github,
context,
pr: context.payload.issue.number,
selector: '${{ steps.parse.outputs.chips }}',
tests: '${{ steps.parse-tests.outputs.tests }}',
});
core.setOutput('run_id', runId);
core.setOutput('body', body);
- name: Confirm in PR
if: steps.parse.outputs.chips != ''
id: comment
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
body: ${{ steps.find-run.outputs.body }}
hil-chips-status:
needs: hil-chips
if: needs.hil-chips.outputs.run_id != '' && needs.hil-chips.outputs.comment_id != ''
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # for `require`
with:
fetch-depth: 1
- name: Wait for per-chip HIL run and update comment
uses: actions/github-script@v7
with:
script: |
const { pollRun } = require('./.github/scripts/hil-status.js');
await pollRun({
github,
context,
runId: Number('${{ needs.hil-chips.outputs.run_id }}'),
commentId: Number('${{ needs.hil-chips.outputs.comment_id }}'),
kind: 'HIL (per-chip)',
});
hil-deny:
needs: auth
if:
github.event_name == 'issue_comment' && needs.auth.outputs.allowed != 'true' &&
(startsWith(github.event.comment.body, '/hil quick') ||
startsWith(github.event.comment.body, '/hil full') ||
startsWith(github.event.comment.body, '/hil ') ||
startsWith(github.event.comment.body, '/test-size'))
runs-on: ubuntu-latest
steps:
- name: Inform not allowed
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
body: |
@${{ github.event.comment.user.login }}, sorry — you're not allowed to execute HIL runs or binary size analysis for this PR.
Please ask an `esp-rs` member/owner to grant access with:
```
/trust @${{ github.event.comment.user.login }}
```
After that, you can use `/hil quick`, `/hil full`, `/hil <chips...>` or `/test-size`.
hil-help:
if: github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/hil') &&
!startsWith(github.event.comment.body, '/hil quick') &&
!startsWith(github.event.comment.body, '/hil full') &&
!contains(github.event.comment.body, 'esp32')
runs-on: ubuntu-latest
steps:
- name: Explain usage
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
body: |
Usage:
- `/hil quick` — run a quick HIL matrix (only `ESP32-S3` (Xtensa) and `ESP32-C6` (RISC-V) tests)
- `/hil full` — run the full HIL matrix for all supported chips
- `/hil <chip> [<chip> ...]` — run the full HIL tests **only** for the listed chips
- `/test-size` — run binary size analysis for this PR
- You can optionally append `--test <name>[,<name>...]` to any `/hil` command to only run selected tests.
If you aren't a repository **member/owner**, you must be **trusted for this PR**.
Maintainers can grant access with a `trusted-author` label or with:
```
/trust @<login>
```
and revoke with:
```
/revoke @<login>
```
binary-size:
needs: auth
if: github.event_name == 'issue_comment' &&
needs.auth.outputs.allowed == 'true' &&
startsWith(github.event.comment.body, '/test-size')
runs-on: ubuntu-latest
steps:
- name: Dispatch Binary Size Analysis
uses: benc-uk/workflow-dispatch@v1
with:
workflow: binary-size.yml
ref: ${{ github.event.repository.default_branch }}
inputs: |
{
"pr_number": "${{ github.event.issue.number }}"
}
- name: Confirm in PR
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.issue.number }}
body: >
Triggered binary size analysis for
#${{ github.event.issue.number }}. Results will be posted as a comment when ready.