Skip to content

Commit 7644d8f

Browse files
committed
Initial commit of existing project files
0 parents  commit 7644d8f

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# aguilita1/github-script-post-comment
2+
3+
This action extends `actions/github-script` and makes it easy to quickly write
4+
a script in your workflow that uses the GitHub API and the workflow run context
5+
then posts comment to Pull Request and GitHub Summary.
6+
7+
### This action
8+
9+
To use this action, provide an input named `script` that contains the body of an asynchronous JavaScript function call.
10+
The following arguments will be provided:
11+
12+
- `github` A pre-authenticated
13+
[octokit/rest.js](https://octokit.github.io/rest.js) client with pagination plugins
14+
- `context` An object containing the [context of the workflow
15+
run](https://github.com/actions/toolkit/blob/main/packages/github/src/context.ts)
16+
- `core` A reference to the [@actions/core](https://github.com/actions/toolkit/tree/main/packages/core) package
17+
- `glob` A reference to the [@actions/glob](https://github.com/actions/toolkit/tree/main/packages/glob) package
18+
- `io` A reference to the [@actions/io](https://github.com/actions/toolkit/tree/main/packages/io) package
19+
- `exec` A reference to the [@actions/exec](https://github.com/actions/toolkit/tree/main/packages/exec) package
20+
- `require` A proxy wrapper around the normal Node.js `require` to enable
21+
requiring relative paths (relative to the current working directory) and
22+
requiring npm packages installed in the current working directory. If for
23+
some reason you need the non-wrapped `require`, there is an escape hatch
24+
available: `__original_require__` is the original value of `require` without
25+
our wrapping applied.
26+
27+
Since the `script` is just a function body, these values will already be
28+
defined, so you don't have to import them (see examples below). You script must
29+
return a `string` that will be included in comment on Pull Request and GitHub
30+
Summary.
31+
32+
See [actions/github-script](https://github.com/marketplace/actions/github-script) for
33+
documentation.
34+
35+
## Inputs
36+
37+
| Input | Required | Description |
38+
|--------|----------|-------------------------------------------------------|
39+
| script | Yes | JavaScript code to execute. |
40+
| label | No | Label to identify the type of comment (e.g. "lint"). |
41+
42+
*WARNING*: Actions expressions are evaluated before the `script` is passed to the action, so the result of any expressions *will be evaluated as JavaScript code*.
43+
44+
It's highly recommended to *not* evaluate expressions directly in the `script` to avoid
45+
[script injections](https://docs.github.com/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#understanding-the-risk-of-script-injections)
46+
and potential `SyntaxError`s when the expression is not valid JavaScript code (particularly when it comes to improperly escaped strings).
47+
48+
## Usage example
49+
50+
This examples will retrieve `coverage/coverage-summary.json` results from prior task and pretty print test coverage results to GitHub pull request (if exists) and GitHub Summary. The `label` is used to provide logging context.
51+
52+
```yaml
53+
- name: Add Test Coverage Comment on PR and GitHub Summary
54+
uses: aguilita1/github-script-post-comment
55+
env:
56+
JEST_THRESHOLD_LINES: 75
57+
with:
58+
label: "Test Coverage"
59+
script: |
60+
const fs = require('fs');
61+
const thresholdLines = parseInt(process.env.JEST_THRESHOLD_LINES, 10);
62+
if (isNaN(thresholdLines)) {
63+
throw new Error('JEST_THRESHOLD_LINES environment variable is not set or invalid');
64+
}
65+
66+
const coverage = JSON.parse(fs.readFileSync('coverage/coverage-summary.json'));
67+
const pct = Math.round(coverage.total.lines.pct);
68+
const status = pct >= thresholdLines ? '✅' : '❌';
69+
70+
let body = `## Test Coverage Report ${status}\n\n`
71+
+ `**Coverage Found:** ${pct}%\n`
72+
+ `**Expected:** ${thresholdLines}%\n\n`
73+
+ `- Lines: ${coverage.total.lines.pct}%\n`
74+
+ `- Functions: ${coverage.total.functions.pct}%\n`
75+
+ `- Branches: ${coverage.total.branches.pct}%\n`
76+
+ `- Statements: ${coverage.total.statements.pct}%`;
77+
78+
return body;
79+
```

action.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: 'GitHub Script with Post'
2+
description: 'Runs custom JavaScript and posts the result to GitHub Summary and Pull Request'
3+
author: 'Daniel I. Kelley'
4+
branding:
5+
icon: 'code'
6+
color: 'blue'
7+
8+
inputs:
9+
script:
10+
description: 'JavaScript code to run'
11+
required: true
12+
label:
13+
description: 'Identifies type of comment adding (e.g. lint)'
14+
required: false
15+
default: ''
16+
17+
runs:
18+
using: 'composite'
19+
steps:
20+
# REMINDER: the inputs.script from .github/actions/github-script-post-comment
21+
# is processed first then inputs.script from actions/github-script@v8
22+
#
23+
- name: Write script to file
24+
shell: bash
25+
run: |
26+
# WARNING: Must use single-quoted HEREDOC (<<'EOF') to write the script
27+
# exactly as provided. This preserves characters like $, ${},
28+
# backticks, and multiline formatting without shell or YAML
29+
# interpolation — ensuring the JavaScript is written to the file
30+
# verbatim.
31+
cat <<'EOF' > ext_script.js
32+
${{ inputs.script }}
33+
EOF
34+
35+
- name: Run custom JavaScript and post results
36+
uses: actions/github-script@v8
37+
with:
38+
script: |
39+
const fs = require('fs');
40+
41+
try {
42+
// Get the inputs passed to the GitHub Action
43+
console.info('Received Input Label:', "${{ inputs.label }}");
44+
console.info("Reading ext_script.js...");
45+
const scriptContent = fs.readFileSync('ext_script.js', 'utf8');
46+
47+
// Dynamically execute the input script provided in GitHub Action
48+
console.info('Executing script...');
49+
// passing github, and context to function
50+
const func = new Function('github', 'context', 'core', 'glob', 'io', 'exec', 'require', `
51+
return (async () => {
52+
${scriptContent}
53+
})();
54+
`);
55+
const body = await func(github, context, core, glob, io, exec, require);
56+
console.info('Executed script successfully');
57+
58+
// Output to GITHUB_STEP_SUMMARY
59+
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
60+
if (summaryPath) {
61+
fs.appendFileSync(summaryPath, '\n---\n');
62+
fs.appendFileSync(summaryPath, body);
63+
console.info(`📝 Appended ${{ inputs.label }} results to GITHUB_STEP_SUMMARY`);
64+
} else {
65+
console.warn('⚠️ GITHUB_STEP_SUMMARY is not defined.');
66+
}
67+
68+
// Create comment on the pull request (if applicable)
69+
if (context.eventName === 'pull_request') {
70+
await github.rest.issues.createComment({
71+
owner: context.repo.owner,
72+
repo: context.repo.repo,
73+
issue_number: context.issue.number,
74+
body: body,
75+
});
76+
console.info(`💬 Commented ${{ inputs.label }} results on PR`);
77+
}
78+
} catch (error) {
79+
console.error(`❌ Error processing ${{ inputs.label }} results:`, error);
80+
}

0 commit comments

Comments
 (0)