Skip to content

Commit ef0509d

Browse files
Copilotneilime
andcommitted
Refactor actions to use github-script and improve coverage/lint reporting
- Replace bash scripts with actions/github-script for better error handling - Change coverage type from "lcov" to "github" with ReportGenerator support - Use eslint-annotate-action for ESLint report processing - Use checkstyle-github-action for Checkstyle report processing - Add always() condition for post-processing steps - Update documentation to reflect new inputs and supported formats - Add jscpd:ignore markers to handle expected README duplication Co-authored-by: neilime <[email protected]>
1 parent 893bff4 commit ef0509d

File tree

6 files changed

+212
-143
lines changed

6 files changed

+212
-143
lines changed

actions/build/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ Action to build Node.js projects with support for custom commands, environment v
8787
| | Format: {"name": "artifact-name", "paths": "path1\npath2"} | | |
8888
| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` |
8989

90+
<!-- jscpd:ignore-start -->
9091
<!-- inputs:end -->
9192
<!-- secrets:start -->
9293
<!-- secrets:end -->
@@ -130,3 +131,4 @@ For more details, see the [license](http://choosealicense.com/licenses/mit/).
130131
This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
131132

132133
<!-- generated:end -->
134+
<!-- jscpd:ignore-end -->

actions/build/action.yml

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -72,56 +72,75 @@ runs:
7272
with:
7373
working-directory: ${{ inputs.working-directory }}
7474

75-
- shell: bash
75+
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
7676
env:
7777
BUILD_ENV: ${{ inputs.build-env }}
7878
BUILD_SECRETS: ${{ inputs.build-secrets }}
79-
run: |
80-
set -e
79+
with:
80+
script: |
81+
const envInput = process.env.BUILD_ENV || '{}';
8182
82-
# Export build environment variables
83-
BUILD_ENV_JSON="${BUILD_ENV:-"{}"}"
83+
let buildEnv = {};
8484
85-
# Parse and export build env variables
86-
if [ "$BUILD_ENV_JSON" != "{}" ]; then
87-
echo "$BUILD_ENV_JSON" | jq -r 'to_entries[] | "\(.key)=\(.value)"' | while IFS= read -r line; do
88-
if [ -n "$line" ]; then
89-
echo "$line" >> $GITHUB_ENV
90-
fi
91-
done
92-
fi
85+
try {
86+
buildEnv = JSON.parse(envInput);
87+
} catch (e) {
88+
core.setFailed(`Invalid build env JSON: ${e.message}`);
89+
}
9390
94-
# Export build secrets
95-
if [ -n "$BUILD_SECRETS" ]; then
96-
echo "$BUILD_SECRETS" | while IFS= read -r line; do
97-
line=$(echo "$line" | xargs)
98-
if [ -n "$line" ]; then
99-
echo "$line" >> $GITHUB_ENV
100-
fi
101-
done
102-
fi
91+
for (const [key, value] of Object.entries(buildEnv)) {
92+
core.exportVariable(key, value);
93+
}
10394
104-
- shell: bash
105-
working-directory: ${{ inputs.working-directory }}
95+
const secretsInput = process.env.BUILD_SECRETS || '';
96+
for (const line of secretsInput.split('\n').map(line => line.trim()).filter(Boolean)) {
97+
const [key, ...rest] = line.split('=');
98+
if (!key || !rest.length) {
99+
return core.setFailed(`Invalid build secrets format: ${line}`);
100+
}
101+
const value = rest.join('=');
102+
core.exportVariable(key.trim(), value.trim());
103+
}
104+
105+
# jscpd:ignore-start
106+
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
106107
env:
107108
BUILD_COMMANDS: ${{ inputs.build-commands }}
108109
RUN_SCRIPT_COMMAND: ${{ inputs.container == 'true' && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }}
109-
run: |
110-
set -e
111-
112-
echo "$BUILD_COMMANDS" | while IFS= read -r COMMAND ; do
113-
# Trim whitespace
114-
COMMAND=$(echo "$COMMAND" | xargs)
110+
WORKING_DIRECTORY: ${{ inputs.working-directory }}
111+
with:
112+
script: |
113+
const { exec } = require('child_process');
114+
const { promisify } = require('util');
115+
const execAsync = promisify(exec);
116+
const path = require('path');
115117
116-
# Skip empty lines
117-
if [ -z "$COMMAND" ]; then
118-
continue
119-
fi
118+
const buildCommands = process.env.BUILD_COMMANDS || '';
119+
const runScriptCommand = process.env.RUN_SCRIPT_COMMAND;
120+
const workingDirectory = process.env.WORKING_DIRECTORY || '.';
120121
121-
echo -e "\n🏗️ Running build command: $COMMAND"
122-
$RUN_SCRIPT_COMMAND "$COMMAND"
123-
done
122+
const commands = buildCommands.split('\n')
123+
.map(cmd => cmd.trim())
124+
.filter(Boolean);
124125
126+
for (const command of commands) {
127+
core.info(`\n🏗️ Running build command: ${command}`);
128+
129+
try {
130+
const { stdout, stderr } = await execAsync(`${runScriptCommand} ${command}`, {
131+
cwd: path.resolve(process.env.GITHUB_WORKSPACE, workingDirectory)
132+
});
133+
134+
if (stdout) core.info(stdout);
135+
if (stderr) core.warning(stderr);
136+
} catch (error) {
137+
if (error.stdout) core.info(error.stdout);
138+
if (error.stderr) core.error(error.stderr);
139+
core.setFailed(`Build command "${command}" failed with exit code ${error.code || 1}`);
140+
throw error;
141+
}
142+
}
143+
# jscpd:ignore-end
125144
- id: build-artifact-id
126145
if: inputs.build-artifact != ''
127146
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0

actions/lint/README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,16 @@ Action to lint Node.js projects with support for pull request reporting and anno
4343
container: "false"
4444

4545
# Path to lint report file to process as GitHub annotations.
46-
# Supports common formats like checkstyle XML, eslint JSON, etc.
46+
# Supports ESLint JSON and Checkstyle XML formats.
4747
# If not specified, no report processing is done.
4848
report-file: ""
4949

50+
# Format of the lint report file. Supported values:
51+
# - "eslint": ESLint JSON format
52+
# - "checkstyle": Checkstyle XML format
53+
# - "": Auto-detect from file extension
54+
report-format: ""
55+
5056
# Whether to fail the action if linting errors are found
5157
# Default: `true`
5258
fail-on-error: "true"
@@ -63,10 +69,15 @@ Action to lint Node.js projects with support for pull request reporting and anno
6369
| | Can be absolute or relative to the repository root. | | |
6470
| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` |
6571
| **`report-file`** | Path to lint report file to process as GitHub annotations. | **false** | - |
66-
| | Supports common formats like checkstyle XML, ESLint JSON, etc. | | |
72+
| | Supports ESLint JSON and Checkstyle XML formats. | | |
6773
| | If not specified, no report processing is done. | | |
74+
| **`report-format`** | Format of the lint report file. Supported values: | **false** | - |
75+
| | - "ESLint": ESLint JSON format | | |
76+
| | - "checkstyle": Checkstyle XML format | | |
77+
| | - "": Auto-detect from file extension | | |
6878
| **`fail-on-error`** | Whether to fail the action if linting errors are found | **false** | `true` |
6979

80+
<!-- jscpd:ignore-start -->
7081
<!-- inputs:end -->
7182
<!-- secrets:start -->
7283
<!-- secrets:end -->
@@ -103,3 +114,4 @@ For more details, see the [license](http://choosealicense.com/licenses/mit/).
103114
This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
104115

105116
<!-- generated:end -->
117+
<!-- jscpd:ignore-end -->

actions/lint/action.yml

Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,18 @@ inputs:
1919
report-file:
2020
description: |
2121
Path to lint report file to process as GitHub annotations.
22-
Supports common formats like checkstyle XML, eslint JSON, etc.
22+
Supports ESLint JSON and Checkstyle XML formats.
2323
If not specified, no report processing is done.
2424
required: false
2525
default: ""
26+
report-format:
27+
description: |
28+
Format of the lint report file. Supported values:
29+
- "eslint": ESLint JSON format
30+
- "checkstyle": Checkstyle XML format
31+
- "": Auto-detect from file extension
32+
required: false
33+
default: ""
2634
fail-on-error:
2735
description: "Whether to fail the action if linting errors are found"
2836
required: false
@@ -50,68 +58,66 @@ runs:
5058
with:
5159
working-directory: ${{ inputs.working-directory }}
5260

53-
- shell: bash
54-
id: run-lint
55-
working-directory: ${{ inputs.working-directory }}
61+
# jscpd:ignore-start
62+
- id: run-lint
63+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
5664
env:
5765
RUN_SCRIPT_COMMAND: ${{ inputs.container == 'true' && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }}
66+
WORKING_DIRECTORY: ${{ inputs.working-directory }}
5867
FAIL_ON_ERROR: ${{ inputs.fail-on-error }}
59-
run: |
60-
set +e # Don't exit on error, we want to process the report
61-
62-
echo "👕 Running lint..."
63-
$RUN_SCRIPT_COMMAND lint
64-
LINT_EXIT_CODE=$?
65-
66-
echo "lint-exit-code=$LINT_EXIT_CODE" >> $GITHUB_OUTPUT
67-
68-
if [ "$FAIL_ON_ERROR" = "true" ] && [ $LINT_EXIT_CODE -ne 0 ]; then
69-
echo "::error::Linting failed with exit code $LINT_EXIT_CODE"
70-
fi
68+
with:
69+
script: |
70+
const { exec } = require('child_process');
71+
const { promisify } = require('util');
72+
const execAsync = promisify(exec);
73+
const path = require('path');
7174
72-
# Always exit successfully here; we'll handle the failure later if needed
73-
exit 0
75+
const workingDirectory = process.env.WORKING_DIRECTORY || '.';
76+
const runScriptCommand = process.env.RUN_SCRIPT_COMMAND;
77+
const failOnError = process.env.FAIL_ON_ERROR === 'true';
7478
75-
- shell: bash
76-
if: inputs.report-file != ''
77-
working-directory: ${{ inputs.working-directory }}
78-
env:
79-
REPORT_FILE: ${{ inputs.report-file }}
80-
run: |
81-
set -e
79+
core.info('👕 Running lint...');
8280
83-
if [ ! -f "$REPORT_FILE" ]; then
84-
echo "::warning::Lint report file not found: $REPORT_FILE"
85-
exit 0
86-
fi
87-
88-
echo "📊 Processing lint report: $REPORT_FILE"
81+
try {
82+
const { stdout, stderr } = await execAsync(`${runScriptCommand} lint`, {
83+
cwd: path.resolve(process.env.GITHUB_WORKSPACE, workingDirectory)
84+
});
85+
86+
if (stdout) core.info(stdout);
87+
if (stderr) core.warning(stderr);
88+
89+
core.setOutput('lint-exit-code', 0);
90+
} catch (error) {
91+
core.setOutput('lint-exit-code', error.code || 1);
92+
93+
if (error.stdout) core.info(error.stdout);
94+
if (error.stderr) core.error(error.stderr);
95+
96+
if (failOnError) {
97+
core.setFailed(`Linting failed with exit code ${error.code || 1}`);
98+
} else {
99+
core.warning(`Linting failed with exit code ${error.code || 1}`);
100+
}
101+
}
102+
# jscpd:ignore-end
103+
# Process ESLint report
104+
- name: 📊 Annotate ESLint results
105+
if: always() && inputs.report-file != '' && (inputs.report-format == 'eslint' || inputs.report-format == '')
106+
uses: ataylorme/eslint-annotate-action@d57a1193d4c59cbfbf2f1529e82e2f8e0da1498d # v3.0.0
107+
with:
108+
report-json: ${{ inputs.working-directory }}/${{ inputs.report-file }}
109+
fail-on-error: false
110+
fail-on-warning: false
89111

90-
# Detect report format and process accordingly
91-
if echo "$REPORT_FILE" | grep -q "\.json$"; then
92-
echo "Detected JSON format"
93-
# Process ESLint JSON format
94-
if jq -e 'type == "array"' "$REPORT_FILE" > /dev/null 2>&1; then
95-
jq -r '.[] | select(.errorCount > 0 or .warningCount > 0) | .messages[] |
96-
"::warning file=\(.filePath // "unknown"),line=\(.line // 1),col=\(.column // 1)::\(.message)"' \
97-
"$REPORT_FILE" || true
98-
fi
99-
elif echo "$REPORT_FILE" | grep -q "\.xml$"; then
100-
echo "Detected XML format (checkstyle)"
101-
# Process checkstyle XML format
102-
# This is a simplified processor; for production, consider using a dedicated tool
103-
if command -v xmllint > /dev/null 2>&1; then
104-
xmllint --xpath '//error' "$REPORT_FILE" 2>/dev/null | \
105-
sed -E 's/<error line="([0-9]+)" column="([0-9]+)" severity="([^"]+)" message="([^"]+)" source="([^"]+)"[^>]*>/::warning line=\1,col=\2::\4/g' || true
106-
else
107-
echo "::warning::xmllint not available, skipping XML report processing"
108-
fi
109-
else
110-
echo "::warning::Unknown report format for $REPORT_FILE"
111-
fi
112+
# Process Checkstyle report
113+
- name: 📊 Annotate Checkstyle results
114+
if: always() && inputs.report-file != '' && inputs.report-format == 'checkstyle'
115+
uses: lcollins/checkstyle-github-action@8e0abb97e71a72c2cf9d6f0619e38002cb6e36c9 # v2.0.0
116+
with:
117+
path: ${{ inputs.working-directory }}/${{ inputs.report-file }}
112118

113119
- shell: bash
114-
if: steps.run-lint.outputs.lint-exit-code != '0' && inputs.fail-on-error == 'true'
120+
if: always() && steps.run-lint.outputs.lint-exit-code != '0' && inputs.fail-on-error == 'true'
115121
run: |
116122
echo "::error::Linting failed. Please fix the errors above."
117123
exit 1

actions/test/README.md

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -72,23 +72,25 @@ Action to test Node.js projects with support for coverage reporting and pull req
7272
7373
## Inputs
7474
75-
| **Input** | **Description** | **Required** | **Default** |
76-
| ----------------------- | ----------------------------------------------------------------- | ------------ | -------------------- |
77-
| **`working-directory`** | Working directory where test commands are executed. | **false** | `.` |
78-
| | Can be absolute or relative to the repository root. | | |
79-
| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` |
80-
| **`coverage`** | Code coverage reporter to use. Supported values: | **false** | - |
81-
| | - "Codecov": Upload coverage to Codecov | | |
82-
| | - "lcov": Use lcov-reporter-action for PR comments | | |
83-
| | - "": No coverage reporting | | |
84-
| **`lcov-file`** | Path to LCOV file for coverage reporting. | **false** | `coverage/lcov.info` |
85-
| | Only used when coverage is set to "lcov". | | |
86-
| **`codecov-token`** | Codecov token for private repositories. | **false** | - |
87-
| | Not required for public repositories when using OIDC. | | |
88-
| **`github-token`** | GitHub token for LCOV reporter PR comments. | **false** | - |
89-
| | Required when coverage is set to "lcov". | | |
90-
| **`fail-on-error`** | Whether to fail the action if tests fail | **false** | `true` |
91-
75+
| **Input** | **Description** | **Required** | **Default** |
76+
| ----------------------- | --------------------------------------------------------------------- | ------------ | --------------------------------- |
77+
| **`working-directory`** | Working directory where test commands are executed. | **false** | `.` |
78+
| | Can be absolute or relative to the repository root. | | |
79+
| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` |
80+
| **`coverage`** | Code coverage reporter to use. Supported values: | **false** | - |
81+
| | - "Codecov": Upload coverage to Codecov | | |
82+
| | - "GitHub": Use ReportGenerator for PR comments with coverage reports | | |
83+
| | - "": No coverage reporting | | |
84+
| **`coverage-files`** | Path to coverage files for reporting. | **false** | `coverage/cobertura-coverage.xml` |
85+
| | Supports multiple formats (Cobertura, OpenCover, lcov, etc.). | | |
86+
| | Can be a single file or multiple files separated by semicolons. | | |
87+
| **`codecov-token`** | Codecov token for private repositories. | **false** | - |
88+
| | Not required for public repositories when using OIDC. | | |
89+
| **`github-token`** | GitHub token for coverage PR comments. | **false** | - |
90+
| | Required when coverage is set to "GitHub". | | |
91+
| **`fail-on-error`** | Whether to fail the action if tests fail | **false** | `true` |
92+
93+
<!-- jscpd:ignore-start -->
9294
<!-- inputs:end -->
9395
<!-- secrets:start -->
9496
<!-- secrets:end -->
@@ -132,3 +134,4 @@ For more details, see the [license](http://choosealicense.com/licenses/mit/).
132134
This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
133135

134136
<!-- generated:end -->
137+
<!-- jscpd:ignore-end -->

0 commit comments

Comments
 (0)