Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .github/actions/report-failure/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: "Report workflow failure"
description: "Open or comment on an issue when a workflow fails, and close it on the next green run."

inputs:
result:
description: "'failure' opens or comments on the issue, 'success' closes it"
required: true
title:
description: "Issue title; it identifies the issue across runs"
required: true
subject:
description: "What failed, in lower case, for the issue text (e.g. 'security audit')"
required: true
labels:
description: "JSON array of {name, color, description} for a new issue; missing labels are created"
required: false
default: "[]"

runs:
using: "composite"
steps:
- name: Open or close the issue
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
RESULT: ${{ inputs.result }}
TITLE: ${{ inputs.title }}
SUBJECT: ${{ inputs.subject }}
LABELS: ${{ inputs.labels }}
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const { RESULT: result, TITLE: title, SUBJECT: subject } = process.env;
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
if (result === 'failure') {
const labels = JSON.parse(process.env.LABELS);
for (const label of labels) {
try {
await github.rest.issues.getLabel({ owner, repo, name: label.name });
} catch (error) {
if (error.status !== 404) throw error;
await github.rest.issues.createLabel({ owner, repo, ...label });
}
}
const date = new Date().toISOString().split('T')[0];
const body = `The ${subject} failed on ${date}. See the [workflow run](${runUrl}).`;
const { data: open } = await github.rest.issues.listForRepo({
owner, repo, state: 'open', labels: labels.map(label => label.name).join(','), per_page: 100,
});
const existing = open.find(i => i.title === title);
if (existing) {
await github.rest.issues.createComment({
owner, repo,
issue_number: existing.number, body,
});
} else {
await github.rest.issues.create({
owner, repo,
title, body, labels: labels.map(label => label.name),
});
}
} else if (result === 'success') {
const passed = subject.charAt(0).toUpperCase() + subject.slice(1);
const { data: open } = await github.rest.issues.listForRepo({
owner, repo, state: 'open', per_page: 100,
});
for (const issue of open.filter(i => i.title === title)) {
await github.rest.issues.createComment({
owner, repo,
issue_number: issue.number,
body: `${passed} passed. Closing. See the [workflow run](${runUrl}).`,
});
await github.rest.issues.update({
owner, repo,
issue_number: issue.number, state: 'closed',
});
}
} else {
throw new Error(`result must be 'failure' or 'success', got '${result}'`);
}
6 changes: 3 additions & 3 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ runs:
restore-keys: |
${{ runner.os }}-native-${{ inputs.rust-toolchain }}-

- name: Cache integration fixtures (model + audio)
- name: Cache integration fixtures (models)
if: ${{ inputs.cache-fixtures == 'true' }}
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
test/fixtures/ggml-tiny.en.bin
test/fixtures/ggml-tiny.bin
test/fixtures/jfk.wav
key: ${{ runner.os }}-fixtures-v1
test/fixtures/ggml-silero-v5.1.2.bin
key: ${{ runner.os }}-fixtures-${{ hashFiles('test/support/fixtures.ex') }}

- name: Install Hex/Rebar + fetch deps
shell: bash
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
timeout-minutes: 25
permissions:
contents: read # checkout the repository
issues: write # open an issue when the integration run fails
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-integration
cancel-in-progress: true
Expand All @@ -48,3 +49,22 @@ jobs:

- name: Run integration tests
run: task test:integration

- name: Report integration failure
if: failure()
uses: $/.github/actions/report-failure
with:
result: failure
title: Integration Tests Failed
subject: integration run
labels: >-
[{"name": "integration", "color": "fbca04", "description": "Integration test run"},
{"name": "automated", "color": "ededed", "description": "Created by automation"}]

- name: Resolve integration issue on success
if: success()
uses: $/.github/actions/report-failure
with:
result: success
title: Integration Tests Failed
subject: integration run
66 changes: 11 additions & 55 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,63 +66,19 @@ jobs:

- name: Report audit failure
if: failure()
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: $/.github/actions/report-failure
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const title = 'Security Audit Failed';
const labels = [
{ name: 'security', color: 'd73a4a', description: 'Security-relevant' },
{ name: 'automated', color: 'ededed', description: 'Created by automation' },
];
for (const label of labels) {
try {
await github.rest.issues.getLabel({ owner, repo, name: label.name });
} catch (error) {
if (error.status !== 404) throw error;
await github.rest.issues.createLabel({ owner, repo, ...label });
}
}
const date = new Date().toISOString().split('T')[0];
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const body = `The security audit failed on ${date}. See the [workflow run](${runUrl}).`;
const { data: open } = await github.rest.issues.listForRepo({
owner, repo, state: 'open', labels: labels.map(label => label.name).join(','), per_page: 100,
});
const existing = open.find(i => i.title === title);
if (existing) {
await github.rest.issues.createComment({
owner, repo,
issue_number: existing.number, body,
});
} else {
await github.rest.issues.create({
owner, repo,
title, body, labels: labels.map(label => label.name),
});
}
result: failure
title: Security Audit Failed
subject: security audit
labels: >-
[{"name": "security", "color": "d73a4a", "description": "Security-relevant"},
{"name": "automated", "color": "ededed", "description": "Created by automation"}]

- name: Resolve audit issue on success
if: success()
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
uses: $/.github/actions/report-failure
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const title = 'Security Audit Failed';
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const { data: open } = await github.rest.issues.listForRepo({
owner, repo, state: 'open', per_page: 100,
});
for (const issue of open.filter(i => i.title === title)) {
await github.rest.issues.createComment({
owner, repo,
issue_number: issue.number,
body: `Security audit passed. Closing. See the [workflow run](${runUrl}).`,
});
await github.rest.issues.update({
owner, repo,
issue_number: issue.number, state: 'closed',
});
}
result: success
title: Security Audit Failed
subject: security audit
Loading