Skip to content

Commit 6d34e8d

Browse files
lindseywildCopilot
andcommitted
Replace JSON string I/O with file-based approach in find, file, fix actions
Each sub-action (find, file, fix) now writes its output JSON to a temp file and exposes a *_file output alongside the existing string output. Each also accepts optional *_file inputs as alternatives to the string inputs. The composite action.yml now passes file paths between steps instead of interpolating large JSON strings, avoiding Linux's ARG_MAX limit that caused 'Argument list too long' errors when processing large datasets (~200KB+). Changes: - find: writes findings.json, sets findings_file output - file: accepts findings_file/cached_filings_file inputs, writes filings.json, sets filings_file output - fix: accepts issues_file input, writes fixings.json, sets fixings_file output - action.yml: normalize_cache reads directly from cache file, all inter-step data flows via file paths, results step reads from file outputs Backward compatible: string inputs/outputs still work for standalone usage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e1d8f99 commit 6d34e8d

File tree

7 files changed

+67
-29
lines changed

7 files changed

+67
-29
lines changed

.github/actions/file/action.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ description: "Files GitHub issues to track potential accessibility gaps."
44
inputs:
55
findings:
66
description: "List of potential accessibility gaps, as stringified JSON"
7-
required: true
7+
required: false
8+
findings_file:
9+
description: "Path to a JSON file containing findings (alternative to 'findings' for large datasets)"
10+
required: false
811
repository:
912
description: "Repository (with owner) to file issues in"
1013
required: true
@@ -14,6 +17,9 @@ inputs:
1417
cached_filings:
1518
description: "Cached filings from previous runs, as stringified JSON. Without this, duplicate issues may be filed."
1619
required: false
20+
cached_filings_file:
21+
description: "Path to a JSON file containing cached filings (alternative to 'cached_filings' for large datasets)"
22+
required: false
1723
screenshot_repository:
1824
description: "Repository (with owner) where screenshots are stored on the gh-cache branch. Defaults to the 'repository' input if not set. Required if issues are open in a different repo to construct proper screenshot URLs."
1925
required: false
@@ -25,6 +31,8 @@ inputs:
2531
outputs:
2632
filings:
2733
description: "List of issues filed (and their associated finding(s)), as stringified JSON"
34+
filings_file:
35+
description: "Path to a JSON file containing filings (use for large datasets to avoid output size limits)"
2836

2937
runs:
3038
using: "node24"

.github/actions/file/src/index.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import type {Finding, ResolvedFiling, RepeatedFiling, FindingGroupIssue, Filing, IssueResponse} from './types.d.js'
2+
import fs from 'node:fs'
3+
import path from 'node:path'
24
import process from 'node:process'
35
import * as core from '@actions/core'
46
import {Octokit} from '@octokit/core'
@@ -16,13 +18,17 @@ const OctokitWithThrottling = Octokit.plugin(throttling)
1618

1719
export default async function () {
1820
core.info("Started 'file' action")
19-
const findings: Finding[] = JSON.parse(core.getInput('findings', {required: true}))
21+
const findingsFile = core.getInput('findings_file', {required: false})
22+
const findings: Finding[] = findingsFile
23+
? JSON.parse(fs.readFileSync(findingsFile, 'utf8'))
24+
: JSON.parse(core.getInput('findings', {required: !findingsFile}))
2025
const repoWithOwner = core.getInput('repository', {required: true})
2126
const token = core.getInput('token', {required: true})
2227
const screenshotRepo = core.getInput('screenshot_repository', {required: false}) || repoWithOwner
23-
const cachedFilings: (ResolvedFiling | RepeatedFiling)[] = JSON.parse(
24-
core.getInput('cached_filings', {required: false}) || '[]',
25-
)
28+
const cachedFilingsFile = core.getInput('cached_filings_file', {required: false})
29+
const cachedFilings: (ResolvedFiling | RepeatedFiling)[] = cachedFilingsFile
30+
? JSON.parse(fs.readFileSync(cachedFilingsFile, 'utf8'))
31+
: JSON.parse(core.getInput('cached_filings', {required: false}) || '[]')
2632
const shouldOpenGroupedIssues = core.getBooleanInput('open_grouped_issues')
2733
core.debug(`Input: 'findings: ${JSON.stringify(findings)}'`)
2834
core.debug(`Input: 'repository: ${repoWithOwner}'`)
@@ -132,6 +138,11 @@ export default async function () {
132138
}
133139

134140
core.setOutput('filings', JSON.stringify(filings))
141+
142+
const filingsPath = path.join(process.env.RUNNER_TEMP || '/tmp', 'filings.json')
143+
fs.writeFileSync(filingsPath, JSON.stringify(filings))
144+
core.setOutput('filings_file', filingsPath)
145+
135146
core.debug(`Output: 'filings: ${JSON.stringify(filings)}'`)
136147
core.info("Finished 'file' action")
137148
}

.github/actions/find/action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ inputs:
2626
outputs:
2727
findings:
2828
description: 'List of potential accessibility gaps, as stringified JSON'
29+
findings_file:
30+
description: 'Path to a JSON file containing findings (use for large datasets to avoid output size limits)'
2931

3032
runs:
3133
using: 'node24'

.github/actions/find/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import type {AuthContextInput, ColorSchemePreference, ReducedMotionPreference} from './types.js'
2+
import fs from 'node:fs'
3+
import path from 'node:path'
24
import * as core from '@actions/core'
35
import {AuthContext} from './AuthContext.js'
46
import {findForUrl} from './findForUrl.js'
@@ -45,6 +47,11 @@ export default async function () {
4547
}
4648

4749
core.setOutput('findings', JSON.stringify(findings))
50+
51+
const findingsPath = path.join(process.env.RUNNER_TEMP || '/tmp', 'findings.json')
52+
fs.writeFileSync(findingsPath, JSON.stringify(findings))
53+
core.setOutput('findings_file', findingsPath)
54+
4855
core.debug(`Output: 'findings: ${JSON.stringify(findings)}'`)
4956
core.info(`Found ${findings.length} findings in total`)
5057
core.info("Finished 'find' action")

.github/actions/fix/action.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ description: "Attempts to fix issues with Copilot."
44
inputs:
55
issues:
66
description: "List of issues to attempt to fix, as stringified JSON"
7-
required: true
7+
required: false
8+
issues_file:
9+
description: "Path to a JSON file containing issues (alternative to 'issues' for large datasets)"
10+
required: false
811
repository:
912
description: "Repository (with owner) containing issues"
1013
required: true
@@ -15,6 +18,8 @@ inputs:
1518
outputs:
1619
fixings:
1720
description: "List of pull requests filed (and their associated issues), as stringified JSON"
21+
fixings_file:
22+
description: "Path to a JSON file containing fixings (use for large datasets to avoid output size limits)"
1823

1924
runs:
2025
using: "node24"

.github/actions/fix/src/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import type {Issue as IssueInput, Fixing} from './types.d.js'
2+
import fs from 'node:fs'
3+
import path from 'node:path'
24
import process from 'node:process'
35
import * as core from '@actions/core'
46
import {Octokit} from '@octokit/core'
@@ -11,7 +13,10 @@ const OctokitWithThrottling = Octokit.plugin(throttling)
1113

1214
export default async function () {
1315
core.info("Started 'fix' action")
14-
const issues: IssueInput[] = JSON.parse(core.getInput('issues', {required: true}) || '[]')
16+
const issuesFile = core.getInput('issues_file', {required: false})
17+
const issues: IssueInput[] = issuesFile
18+
? JSON.parse(fs.readFileSync(issuesFile, 'utf8'))
19+
: JSON.parse(core.getInput('issues', {required: !issuesFile}) || '[]')
1520
const repoWithOwner = core.getInput('repository', {required: true})
1621
const token = core.getInput('token', {required: true})
1722
core.debug(`Input: 'issues: ${JSON.stringify(issues)}'`)
@@ -57,6 +62,11 @@ export default async function () {
5762
}
5863

5964
core.setOutput('fixings', JSON.stringify(fixings))
65+
66+
const fixingsPath = path.join(process.env.RUNNER_TEMP || '/tmp', 'fixings.json')
67+
fs.writeFileSync(fixingsPath, JSON.stringify(fixings))
68+
core.setOutput('fixings_file', fixingsPath)
69+
6070
core.debug(`Output: 'fixings: ${JSON.stringify(fixings)}'`)
6171
core.info("Finished 'fix' action")
6272
}

action.yml

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ runs:
9090
# If cached data is a list of Finding objects, each with 'issueUrl' keys (i.e. v1),
9191
# convert to a list of (partial) Result objects, each with 'findings' and 'issue' keys (i.e. v2).
9292
# Otherwise, re-output as-is.
93-
printf '%s' "value=$(printf '%s' '${{ steps.restore.outputs.value }}' | jq -c 'if (type == "array" and length > 0 and (.[0] | has("issueUrl"))) then map({findings: [del(.issueUrl)], issue: {url: .issueUrl}}) else . end' )" >> $GITHUB_OUTPUT
93+
# Read directly from the cache file to avoid shell interpolation of large JSON.
94+
jq -c 'if (type == "array" and length > 0 and (.[0] | has("issueUrl"))) then map({findings: [del(.issueUrl)], issue: {url: .issueUrl}}) else . end' "${{ inputs.cache_key }}" > "$RUNNER_TEMP/cached_filings.json"
95+
echo "cached_filings_file=$RUNNER_TEMP/cached_filings.json" >> $GITHUB_OUTPUT
9496
- if: ${{ inputs.login_url && inputs.username && inputs.password && !inputs.auth_context }}
9597
name: Authenticate
9698
id: auth
@@ -113,49 +115,42 @@ runs:
113115
id: file
114116
uses: ./../../_actions/github/accessibility-scanner/current/.github/actions/file
115117
with:
116-
findings: ${{ steps.find.outputs.findings }}
118+
findings_file: ${{ steps.find.outputs.findings_file }}
117119
repository: ${{ inputs.repository }}
118120
token: ${{ inputs.token }}
119-
cached_filings: ${{ steps.normalize_cache.outputs.value }}
121+
cached_filings_file: ${{ steps.normalize_cache.outputs.cached_filings_file }}
120122
screenshot_repository: ${{ github.repository }}
121123
open_grouped_issues: ${{ inputs.open_grouped_issues }}
122-
- if: ${{ steps.file.outputs.filings }}
124+
- if: ${{ steps.file.outputs.filings_file }}
123125
name: Get issues from filings
124126
id: get_issues_from_filings
125127
shell: bash
126128
run: |
127-
# Extract open issues from Filing objects and output as a single-line JSON array
128-
issues=$(jq -c '[.[] | select(.issue.state == "open") | .issue]' <<< '${{ steps.file.outputs.filings }}')
129-
echo "issues=$issues" >> "$GITHUB_OUTPUT"
129+
# Extract open issues from Filing objects and write to a file
130+
jq -c '[.[] | select(.issue.state == "open") | .issue]' "${{ steps.file.outputs.filings_file }}" > "$RUNNER_TEMP/issues.json"
131+
echo "issues_file=$RUNNER_TEMP/issues.json" >> "$GITHUB_OUTPUT"
130132
- if: ${{ inputs.skip_copilot_assignment != 'true' }}
131133
name: Fix
132134
id: fix
133135
uses: ./../../_actions/github/accessibility-scanner/current/.github/actions/fix
134136
with:
135-
issues: ${{ steps.get_issues_from_filings.outputs.issues }}
137+
issues_file: ${{ steps.get_issues_from_filings.outputs.issues_file }}
136138
repository: ${{ inputs.repository }}
137139
token: ${{ inputs.token }}
138-
- name: Write filings and fixings to temp files
139-
shell: bash
140-
run: |
141-
cat > "$RUNNER_TEMP/filings.json" << 'FILINGS_HEREDOC_DELIMITER'
142-
${{ steps.file.outputs.filings || '[]' }}
143-
FILINGS_HEREDOC_DELIMITER
144-
145-
cat > "$RUNNER_TEMP/fixings.json" << 'FIXINGS_HEREDOC_DELIMITER'
146-
${{ steps.fix.outputs.fixings || '[]' }}
147-
FIXINGS_HEREDOC_DELIMITER
148-
149140
- name: Set results output
150141
id: results
151142
shell: bash
143+
env:
144+
FILINGS_FILE: ${{ steps.file.outputs.filings_file || '' }}
145+
FIXINGS_FILE: ${{ steps.fix.outputs.fixings_file || '' }}
152146
run: |
153147
node << 'NODE_SCRIPT'
154148
const fs = require('fs');
155149
const path = require('path');
156-
const runnerTemp = process.env.RUNNER_TEMP;
157-
const filings = JSON.parse(fs.readFileSync(path.join(runnerTemp, 'filings.json'), 'utf8')) || [];
158-
const fixings = JSON.parse(fs.readFileSync(path.join(runnerTemp, 'fixings.json'), 'utf8')) || [];
150+
const filingsFile = process.env.FILINGS_FILE;
151+
const fixingsFile = process.env.FIXINGS_FILE;
152+
const filings = filingsFile && fs.existsSync(filingsFile) ? JSON.parse(fs.readFileSync(filingsFile, 'utf8')) : [];
153+
const fixings = fixingsFile && fs.existsSync(fixingsFile) ? JSON.parse(fs.readFileSync(fixingsFile, 'utf8')) : [];
159154
const fixingsByIssueUrl = fixings.reduce((acc, fixing) => {
160155
if (fixing.issue && fixing.issue.url) acc[fixing.issue.url] = fixing;
161156
return acc;

0 commit comments

Comments
 (0)