@plainconceptsplatform/workflows 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -11
- package/dist/catalog-installation.d.ts +11 -2
- package/dist/catalog-installation.js +53 -9
- package/dist/catalog-installation.test.js +198 -16
- package/dist/catalog-listing.d.ts +13 -0
- package/dist/catalog-listing.js +68 -0
- package/dist/catalog-listing.test.d.ts +1 -0
- package/dist/catalog-listing.test.js +137 -0
- package/dist/index.js +76 -12
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +112 -0
- package/dist/repository-inspection.test.d.ts +1 -0
- package/dist/repository-inspection.test.js +77 -0
- package/dist/tui.d.ts +25 -0
- package/dist/tui.js +254 -0
- package/dist/tui.test.d.ts +1 -0
- package/dist/tui.test.js +246 -0
- package/dist/workflow-catalog.d.ts +15 -8
- package/dist/workflow-catalog.js +25 -15
- package/dist/workflow-catalog.test.js +18 -3
- package/loops/actions/add-issue-labels/action.yml +30 -29
- package/loops/actions/agent-output.cjs +1 -0
- package/loops/actions/apply-agent-bundle/action.yml +24 -23
- package/loops/actions/apply-agent-bundle/apply-bundle.sh +1 -0
- package/loops/actions/apply-agent-comments/action.yml +42 -41
- package/loops/actions/apply-agent-labels/action.yml +55 -54
- package/loops/actions/apply-agent-output/action.yml +108 -107
- package/loops/actions/audit-close/action.yml +104 -103
- package/loops/actions/classify-route/action.yml +91 -90
- package/loops/actions/classify-route/classify-route.sh +1 -0
- package/loops/actions/cleanup-artifacts/action.yml +65 -64
- package/loops/actions/close-agent-issues/action.yml +43 -42
- package/loops/actions/create-agent-issues/action.yml +52 -51
- package/loops/actions/create-issue-comment/action.yml +29 -28
- package/loops/actions/download-agent-output/action.yml +53 -52
- package/loops/actions/identify-gate-subject/action.yml +97 -96
- package/loops/actions/link-pr-to-issue/action.yml +40 -39
- package/loops/actions/list-open-issues/action.yml +33 -32
- package/loops/actions/load-issue-context/action.yml +43 -42
- package/loops/actions/merge-agent-pr/action.yml +36 -35
- package/loops/actions/push-agent-branch/action.yml +45 -44
- package/loops/actions/remove-issue-labels/action.yml +35 -34
- package/loops/actions/stale-recovery/action.yml +288 -287
- package/loops/actions/update-agent-issues/action.yml +58 -57
- package/loops/actions/validate-refine-output/action.yml +44 -43
- package/loops/actions/validate-refine-output/validate-refine-output.sh +1 -0
- package/loops/actions/verify-composite-actions/action.yml +9 -8
- package/loops/actions/verify-composite-actions/verify-composite-actions.sh +1 -0
- package/loops/actions/verify-refine-output/action.yml +9 -8
- package/loops/actions/verify-refine-output/verify-refine-output.sh +1 -0
- package/loops/actions/verify-route-matrix/action.yml +9 -8
- package/loops/actions/verify-route-matrix/verify-route-matrix.sh +1 -0
- package/loops/scripts/compile-agent-workflows.mjs +29 -13
- package/loops/templates/agentics/agentics-checks.yml +86 -0
- package/loops/templates/agentics/agentics-maintenance.yml +121 -0
- package/loops/templates/ci/app-ci-dotnet-next.yml +167 -0
- package/loops/templates/ci/app-ci-node-monorepo.yml +178 -0
- package/loops/templates/opencode/opencode.ci.json +46 -0
- package/loops/templates/opencode/opencode.ci.json.md +41 -0
- package/loops/workflows/agent-apply-review.md +9 -10
- package/loops/workflows/agent-audit.md +6 -7
- package/loops/workflows/agent-direct.md +7 -8
- package/loops/workflows/agent-implement.md +7 -8
- package/loops/workflows/agent-merge-gate.md +9 -10
- package/loops/workflows/agent-propose.md +7 -8
- package/loops/workflows/agent-refine.md +5 -7
- package/loops/workflows/shared/opencode-ci.md +105 -1
- package/loops/workflows/shared/platform-defaults.md +1 -0
- package/loops/workflows/work-router.yml +1 -0
- package/package.json +2 -2
- package/loops/aw/repo-config.md +0 -12
|
@@ -1,103 +1,104 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
let
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
let
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
closed
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
.
|
|
103
|
-
.
|
|
1
|
+
# Managed by @plainconceptsplatform/workflows. Source: loops/actions/audit-close/action.yml. Update with workflows update --force; consumer edits may be overwritten.
|
|
2
|
+
name: Close audit reports
|
|
3
|
+
description: Close open audit reports once every issue they reference is closed.
|
|
4
|
+
inputs:
|
|
5
|
+
token:
|
|
6
|
+
description: GitHub token with issues write access.
|
|
7
|
+
required: true
|
|
8
|
+
runs:
|
|
9
|
+
using: composite
|
|
10
|
+
steps:
|
|
11
|
+
- name: Close every report whose referenced issues are all closed
|
|
12
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
13
|
+
with:
|
|
14
|
+
github-token: ${{ inputs.token }}
|
|
15
|
+
script: |
|
|
16
|
+
const reports = await github.paginate(github.rest.issues.listForRepo, {
|
|
17
|
+
...context.repo,
|
|
18
|
+
state: 'open',
|
|
19
|
+
labels: 'audit',
|
|
20
|
+
per_page: 100,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (reports.length === 0) {
|
|
24
|
+
core.info('No open audit reports.');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Skip `owner/repo#12` and `abc#12`: only a bare `#12` references this repository.
|
|
29
|
+
const referencedIssues = (body) => {
|
|
30
|
+
const matches = (body ?? '').matchAll(/(?:^|[^A-Za-z0-9_/])#(\d+)/g);
|
|
31
|
+
return [...new Set([...matches].map((match) => Number(match[1])))];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let closed = 0;
|
|
35
|
+
let keptOpen = 0;
|
|
36
|
+
|
|
37
|
+
for (const report of reports.sort((a, b) => a.number - b.number)) {
|
|
38
|
+
const refs = referencedIssues(report.body).filter((n) => n !== report.number);
|
|
39
|
+
|
|
40
|
+
const stillOpen = [];
|
|
41
|
+
const unknown = [];
|
|
42
|
+
let closedRefs = 0;
|
|
43
|
+
let resolved = 0;
|
|
44
|
+
|
|
45
|
+
for (const ref of refs) {
|
|
46
|
+
let state;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
({ data: { state } } = await github.rest.issues.get({
|
|
50
|
+
...context.repo,
|
|
51
|
+
issue_number: ref,
|
|
52
|
+
}));
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error.status === 404) {
|
|
55
|
+
core.info(`#${report.number}: ignoring #${ref}, not an issue in this repository`);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
unknown.push(ref);
|
|
59
|
+
resolved += 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
resolved += 1;
|
|
64
|
+
if (state === 'closed') closedRefs += 1;
|
|
65
|
+
else stillOpen.push(ref);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (stillOpen.length > 0) {
|
|
69
|
+
core.info(`#${report.number}: kept open, still-open references: ${stillOpen.join(', ')}`);
|
|
70
|
+
keptOpen += 1;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (unknown.length > 0) {
|
|
75
|
+
core.info(`#${report.number}: kept open, undetermined references: ${unknown.join(', ')}`);
|
|
76
|
+
keptOpen += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const reason = resolved === 0
|
|
81
|
+
? 'This report references no issues.'
|
|
82
|
+
: `All ${closedRefs} referenced issue(s) are closed.`;
|
|
83
|
+
|
|
84
|
+
await github.rest.issues.createComment({
|
|
85
|
+
...context.repo,
|
|
86
|
+
issue_number: report.number,
|
|
87
|
+
body: `Closed automatically by \`Work Router: audit-close\`. ${reason}`,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await github.rest.issues.update({
|
|
91
|
+
...context.repo,
|
|
92
|
+
issue_number: report.number,
|
|
93
|
+
state: 'closed',
|
|
94
|
+
state_reason: 'completed',
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
core.info(`#${report.number}: closed. ${reason}`);
|
|
98
|
+
closed += 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
await core.summary
|
|
102
|
+
.addHeading('Audit close', 2)
|
|
103
|
+
.addList([`Reports closed: ${closed}`, `Reports left open: ${keptOpen}`])
|
|
104
|
+
.write();
|
|
@@ -1,90 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
--
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
echo "
|
|
1
|
+
# Managed by @plainconceptsplatform/workflows. Source: loops/actions/classify-route/action.yml. Update with workflows update --force; consumer edits may be overwritten.
|
|
2
|
+
name: Classify route
|
|
3
|
+
description: Classify the triggering event into exactly one route, and resolve the issue a gated pull request closes.
|
|
4
|
+
inputs:
|
|
5
|
+
token:
|
|
6
|
+
description: GitHub token with pull-requests read access.
|
|
7
|
+
required: true
|
|
8
|
+
outputs:
|
|
9
|
+
route:
|
|
10
|
+
description: The single route this event selects, or `none`.
|
|
11
|
+
value: ${{ steps.classify.outputs.route }}
|
|
12
|
+
issue-number:
|
|
13
|
+
description: Issue number the route operates on.
|
|
14
|
+
value: ${{ steps.classify.outputs.issue-number }}
|
|
15
|
+
pr-number:
|
|
16
|
+
description: Pull request number the route operates on.
|
|
17
|
+
value: ${{ steps.classify.outputs.pr-number }}
|
|
18
|
+
linked-issue:
|
|
19
|
+
description: Issue the pull request closes. Empty for routes that do not target one.
|
|
20
|
+
value: ${{ steps.linked-issue.outputs.issue }}
|
|
21
|
+
ci-conclusion:
|
|
22
|
+
description: Conclusion reported by the CI run that triggered a merge-gate route.
|
|
23
|
+
value: ${{ steps.classify.outputs.ci-conclusion }}
|
|
24
|
+
ci-run-id:
|
|
25
|
+
description: Workflow run ID of that CI run.
|
|
26
|
+
value: ${{ steps.classify.outputs.ci-run-id }}
|
|
27
|
+
refine-mode:
|
|
28
|
+
description: first or rerefine.
|
|
29
|
+
value: ${{ steps.classify.outputs.refine-mode }}
|
|
30
|
+
direct-mode:
|
|
31
|
+
description: first or continue.
|
|
32
|
+
value: ${{ steps.classify.outputs.direct-mode }}
|
|
33
|
+
trigger-kind:
|
|
34
|
+
description: scheduled or manual.
|
|
35
|
+
value: ${{ steps.classify.outputs.trigger-kind }}
|
|
36
|
+
runs:
|
|
37
|
+
using: composite
|
|
38
|
+
steps:
|
|
39
|
+
- name: Classify the event
|
|
40
|
+
id: classify
|
|
41
|
+
shell: bash
|
|
42
|
+
env:
|
|
43
|
+
EVENT: ${{ github.event_name }}
|
|
44
|
+
ACTION: ${{ github.event.action }}
|
|
45
|
+
LABEL: ${{ github.event.label.name }}
|
|
46
|
+
ISSUE_LABELS: ${{ toJSON(github.event.issue.labels.*.name) }}
|
|
47
|
+
EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
|
|
48
|
+
EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
49
|
+
COMMENT_ON_PR: ${{ github.event.issue.pull_request != '' }}
|
|
50
|
+
COMMENT_SENDER_TYPE: ${{ github.event.comment.user.type }}
|
|
51
|
+
RUN_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
|
52
|
+
RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
|
53
|
+
RUN_ID: ${{ github.event.workflow_run.id }}
|
|
54
|
+
SCHEDULE: ${{ github.event.schedule }}
|
|
55
|
+
OPERATION: ${{ github.event.inputs.operation }}
|
|
56
|
+
INPUT_ISSUE_NUMBER: ${{ github.event.inputs.issue-number }}
|
|
57
|
+
INPUT_PR_NUMBER: ${{ github.event.inputs.pr-number }}
|
|
58
|
+
INPUT_MODE: ${{ github.event.inputs.mode }}
|
|
59
|
+
INPUT_CI_CONCLUSION: ${{ github.event.inputs.ci-conclusion }}
|
|
60
|
+
INPUT_CI_RUN_ID: ${{ github.event.inputs.ci-run-id }}
|
|
61
|
+
INPUT_TRIGGER_KIND: ${{ github.event.inputs.trigger-kind }}
|
|
62
|
+
run: |
|
|
63
|
+
set -euo pipefail
|
|
64
|
+
|
|
65
|
+
bash "${GITHUB_ACTION_PATH}/classify-route.sh" | tee "$RUNNER_TEMP/route.env"
|
|
66
|
+
cat "$RUNNER_TEMP/route.env" >> "$GITHUB_OUTPUT"
|
|
67
|
+
|
|
68
|
+
route="$(sed -n 's/^route=//p' "$RUNNER_TEMP/route.env")"
|
|
69
|
+
reason="$(sed -n 's/^error=//p' "$RUNNER_TEMP/route.env")"
|
|
70
|
+
|
|
71
|
+
if [ "$route" = "none" ] && [ -n "$reason" ]; then
|
|
72
|
+
echo "::notice::No route for this event: $reason"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
- name: Resolve the issue the pull request closes
|
|
76
|
+
id: linked-issue
|
|
77
|
+
if: steps.classify.outputs.route == 'merge-gate' || steps.classify.outputs.route == 'apply-review'
|
|
78
|
+
shell: bash
|
|
79
|
+
env:
|
|
80
|
+
GH_TOKEN: ${{ inputs.token }}
|
|
81
|
+
REPO: ${{ github.repository }}
|
|
82
|
+
PR_NUMBER: ${{ steps.classify.outputs.pr-number }}
|
|
83
|
+
run: |
|
|
84
|
+
set -euo pipefail
|
|
85
|
+
|
|
86
|
+
issue="$(gh pr view "$PR_NUMBER" --repo "$REPO" \
|
|
87
|
+
--json closingIssuesReferences \
|
|
88
|
+
--jq '.closingIssuesReferences[0].number // empty')"
|
|
89
|
+
|
|
90
|
+
echo "issue=${issue}" >> "$GITHUB_OUTPUT"
|
|
91
|
+
echo "Pull request #${PR_NUMBER} closes issue #${issue:-<none>}"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# Managed by @plainconceptsplatform/workflows. Source: loops/actions/classify-route/classify-route.sh. Update with `workflows update --force`; consumer edits may be overwritten.
|
|
2
3
|
# Classify one GitHub event into exactly one route. Pure: no network, no gh calls, so
|
|
3
4
|
# verify-route-matrix.sh can source this file and exercise the same code the router runs.
|
|
4
5
|
#
|
|
@@ -1,64 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.
|
|
55
|
-
|
|
56
|
-
`
|
|
57
|
-
`
|
|
58
|
-
`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
1
|
+
# Managed by @plainconceptsplatform/workflows. Source: loops/actions/cleanup-artifacts/action.yml. Update with workflows update --force; consumer edits may be overwritten.
|
|
2
|
+
name: Clean up artifacts
|
|
3
|
+
description: Delete workflow artifacts older than the configured retention period.
|
|
4
|
+
inputs:
|
|
5
|
+
token:
|
|
6
|
+
description: GitHub token with actions write access.
|
|
7
|
+
required: true
|
|
8
|
+
artifact-retention-days:
|
|
9
|
+
description: Retention period in days. Invalid or empty values use 3.
|
|
10
|
+
required: false
|
|
11
|
+
default: ''
|
|
12
|
+
runs:
|
|
13
|
+
using: composite
|
|
14
|
+
steps:
|
|
15
|
+
- name: Delete expired artifacts
|
|
16
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
17
|
+
env:
|
|
18
|
+
ARTIFACT_RETENTION_DAYS: ${{ inputs.artifact-retention-days }}
|
|
19
|
+
with:
|
|
20
|
+
github-token: ${{ inputs.token }}
|
|
21
|
+
script: |
|
|
22
|
+
const parsedDays = Number.parseInt(process.env.ARTIFACT_RETENTION_DAYS, 10);
|
|
23
|
+
const days = Number.isInteger(parsedDays) && parsedDays > 0 ? parsedDays : 3;
|
|
24
|
+
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
25
|
+
|
|
26
|
+
core.info(`Retention: ${days} days (cutoff ${cutoff.toISOString()})`);
|
|
27
|
+
|
|
28
|
+
const artifacts = await github.paginate(github.rest.actions.listArtifactsForRepo, {
|
|
29
|
+
...context.repo,
|
|
30
|
+
per_page: 100,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const expired = artifacts.filter((artifact) => new Date(artifact.created_at) < cutoff);
|
|
34
|
+
|
|
35
|
+
let deleted = 0;
|
|
36
|
+
const failed = [];
|
|
37
|
+
|
|
38
|
+
for (const artifact of expired) {
|
|
39
|
+
try {
|
|
40
|
+
await github.rest.actions.deleteArtifact({
|
|
41
|
+
...context.repo,
|
|
42
|
+
artifact_id: artifact.id,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
core.info(`Deleted ${artifact.name} (created ${artifact.created_at})`);
|
|
46
|
+
deleted += 1;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
core.warning(`Could not delete ${artifact.name} (${artifact.id}): ${error.message}`);
|
|
49
|
+
failed.push(artifact.name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await core.summary
|
|
54
|
+
.addHeading('Artifact cleanup', 2)
|
|
55
|
+
.addList([
|
|
56
|
+
`Retention: ${days} days (cutoff ${cutoff.toISOString()})`,
|
|
57
|
+
`Deleted: ${deleted}`,
|
|
58
|
+
`Failed to delete: ${failed.length}`,
|
|
59
|
+
`Within retention: ${artifacts.length - expired.length}`,
|
|
60
|
+
])
|
|
61
|
+
.write();
|
|
62
|
+
|
|
63
|
+
if (failed.length > 0) {
|
|
64
|
+
core.setFailed(`${failed.length} artifact(s) could not be deleted: ${failed.join(', ')}`);
|
|
65
|
+
}
|
|
@@ -1,42 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
# Managed by @plainconceptsplatform/workflows. Source: loops/actions/close-agent-issues/action.yml. Update with workflows update --force; consumer edits may be overwritten.
|
|
2
|
+
name: Close agent issues
|
|
3
|
+
description: Close every close_issue item from agent_output.json.
|
|
4
|
+
inputs:
|
|
5
|
+
output-file:
|
|
6
|
+
description: Path to agent_output.json.
|
|
7
|
+
required: true
|
|
8
|
+
token:
|
|
9
|
+
description: GitHub token with issues:write.
|
|
10
|
+
required: true
|
|
11
|
+
runs:
|
|
12
|
+
using: composite
|
|
13
|
+
steps:
|
|
14
|
+
- name: Close issues
|
|
15
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
16
|
+
env:
|
|
17
|
+
AGENT_OUTPUT_LIB: ${{ github.action_path }}/../agent-output.cjs
|
|
18
|
+
OUTPUT_FILE: ${{ inputs.output-file }}
|
|
19
|
+
with:
|
|
20
|
+
github-token: ${{ inputs.token }}
|
|
21
|
+
script: |
|
|
22
|
+
const { readAgentItems } = require(process.env.AGENT_OUTPUT_LIB);
|
|
23
|
+
const items = readAgentItems(process.env.OUTPUT_FILE, 'close_issue');
|
|
24
|
+
|
|
25
|
+
let closed = 0;
|
|
26
|
+
|
|
27
|
+
for (const item of items) {
|
|
28
|
+
if (!item.item_number) {
|
|
29
|
+
core.warning(`close_issue item has no item_number, skipping: ${JSON.stringify(item)}`);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
await github.rest.issues.update({
|
|
34
|
+
...context.repo,
|
|
35
|
+
issue_number: Number(item.item_number),
|
|
36
|
+
state: 'closed',
|
|
37
|
+
state_reason: item.state_reason === 'not_planned' ? 'not_planned' : 'completed',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
closed += 1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
core.info(`Closed ${closed} issue(s).`);
|