@codfish/actions 1.1.0 → 2.0.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/.github/workflows/claude.yml +0 -1
- package/AGENT.md +21 -1
- package/README.md +13 -8
- package/npm-publish-pr/README.md +2 -2
- package/npm-publish-pr/action.yml +19 -12
- package/package.json +1 -1
- package/setup-node-and-install/README.md +16 -14
- package/setup-node-and-install/action.yml +97 -124
- package/tests/integration/comment/basic.bats +11 -11
- package/tests/integration/npm-pr-version/basic.bats +131 -46
- package/tests/integration/setup-node-and-install/basic.bats +471 -33
package/AGENT.md
CHANGED
|
@@ -62,7 +62,8 @@ This project uses **pnpm** as the package manager. All commands should use pnpm:
|
|
|
62
62
|
- `comment` - Creates or updates pull request comments with intelligent upsert functionality using unique tags
|
|
63
63
|
- **IMPORTANT**: Any job using the comment action must include `permissions: pull-requests: write`
|
|
64
64
|
- `setup-node-and-install` - Sets up Node.js environment and installs dependencies with automatic package manager
|
|
65
|
-
detection, intelligent caching, and
|
|
65
|
+
detection, intelligent caching, and dynamic Node version detection via input, `.node-version`, `.nvmrc`, or
|
|
66
|
+
`package.json` `volta.node`. Validation is relaxed; the action no longer fails when no version is detected.
|
|
66
67
|
|
|
67
68
|
## Testing
|
|
68
69
|
|
|
@@ -127,3 +128,22 @@ The project implements multiple security measures:
|
|
|
127
128
|
- **Vulnerability auditing**: Regular pnpm audit checks
|
|
128
129
|
- **Note**: Dependency review requires GitHub Advanced Security (available free on public repos, paid feature for
|
|
129
130
|
private repos)
|
|
131
|
+
|
|
132
|
+
## Code Quality and File Editing Rules
|
|
133
|
+
|
|
134
|
+
### Bats File Editing Rules
|
|
135
|
+
|
|
136
|
+
**CRITICAL**: After editing any `.bats` file, ALWAYS check for and remove trailing spaces:
|
|
137
|
+
|
|
138
|
+
1. Run: `grep -n " $" path/to/file.bats`
|
|
139
|
+
2. If any trailing spaces are found, remove them immediately
|
|
140
|
+
3. Bats files are NOT automatically formatted by eslint/prettier, so manual cleanup is required
|
|
141
|
+
4. Trailing spaces in bats files can cause test execution issues
|
|
142
|
+
|
|
143
|
+
### General File Editing Guidelines
|
|
144
|
+
|
|
145
|
+
- Do what has been asked; nothing more, nothing less
|
|
146
|
+
- NEVER create files unless they're absolutely necessary for achieving your goal
|
|
147
|
+
- ALWAYS prefer editing an existing file to creating a new one
|
|
148
|
+
- NEVER proactively create documentation files (\*.md) or README files. Only create documentation files if explicitly
|
|
149
|
+
requested by the User
|
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ automatically comments on PR
|
|
|
67
67
|
|
|
68
68
|
| Input | Description | Required | Default |
|
|
69
69
|
| -------------- | ----------------------------------------------------------------------------------- | -------- | ---------------- |
|
|
70
|
-
| `npm-token` | Registry authentication token with publish permissions (works with npm/yarn/pnpm) |
|
|
70
|
+
| `npm-token` | Registry authentication token with publish permissions (works with npm/yarn/pnpm) | Yes | - |
|
|
71
71
|
| `github-token` | GitHub token with pull request comment permissions (typically secrets.GITHUB_TOKEN) | Yes | - |
|
|
72
72
|
| `comment` | Whether to comment on the PR with the published version (true/false) | No | `true` |
|
|
73
73
|
| `comment-tag` | Tag to use for PR comments (for comment identification and updates) | No | `npm-publish-pr` |
|
|
@@ -101,16 +101,21 @@ steps:
|
|
|
101
101
|
### [setup-node-and-install](./setup-node-and-install/)
|
|
102
102
|
|
|
103
103
|
Sets up Node.js environment and installs dependencies with automatic package manager detection (npm/pnpm/yarn),
|
|
104
|
-
intelligent caching, and .
|
|
104
|
+
intelligent caching, and version detection via input, .node-version, .nvmrc, or package.json volta.node
|
|
105
105
|
|
|
106
106
|
**Inputs:**
|
|
107
107
|
|
|
108
|
-
| Input | Description
|
|
109
|
-
| ------------------- |
|
|
110
|
-
| `node-version` | Node.js version to install (e.g.
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
113
|
-
|
|
108
|
+
| Input | Description | Required | Default |
|
|
109
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------- |
|
|
110
|
+
| `node-version` | Node.js version to install (e.g. "24", "lts/\*"). Precedence: node-version input > .node-version > .nvmrc > package.json volta.node. | No | - |
|
|
111
|
+
| `install-options` | Extra command-line options to pass to npm/pnpm/yarn install. | No | - |
|
|
112
|
+
| `working-directory` | Directory containing package.json and lockfile. | No | `.` |
|
|
113
|
+
|
|
114
|
+
**Outputs:**
|
|
115
|
+
|
|
116
|
+
| Output | Description |
|
|
117
|
+
| ----------- | -------------------------------------------------- |
|
|
118
|
+
| `cache-hit` | Whether the dependency cache was hit (true/false). |
|
|
114
119
|
|
|
115
120
|
**Usage:**
|
|
116
121
|
|
package/npm-publish-pr/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# npm-pr
|
|
1
|
+
# npm-publish-pr
|
|
2
2
|
|
|
3
3
|
Publishes packages with PR-specific version numbers for testing in downstream applications before merging. Automatically
|
|
4
4
|
detects your package manager (npm, yarn, or pnpm) and uses the appropriate publish command. The action generates
|
|
@@ -102,7 +102,7 @@ The package is published under the `pr` tag, so it won't interfere with your reg
|
|
|
102
102
|
|
|
103
103
|
| Input | Description | Required | Default |
|
|
104
104
|
| -------------- | ----------------------------------------------------------------------------------- | -------- | ---------------- |
|
|
105
|
-
| `npm-token` | Registry authentication token with publish permissions (works with npm/yarn/pnpm) |
|
|
105
|
+
| `npm-token` | Registry authentication token with publish permissions (works with npm/yarn/pnpm) | Yes | - |
|
|
106
106
|
| `github-token` | GitHub token with pull request comment permissions (typically secrets.GITHUB_TOKEN) | Yes | - |
|
|
107
107
|
| `comment` | Whether to comment on the PR with the published version (true/false) | No | `true` |
|
|
108
108
|
| `comment-tag` | Tag to use for PR comments (for comment identification and updates) | No | `npm-publish-pr` |
|
|
@@ -6,7 +6,7 @@ description:
|
|
|
6
6
|
|
|
7
7
|
inputs:
|
|
8
8
|
npm-token:
|
|
9
|
-
required:
|
|
9
|
+
required: true
|
|
10
10
|
description: Registry authentication token with publish permissions (works with npm/yarn/pnpm)
|
|
11
11
|
github-token:
|
|
12
12
|
required: true
|
|
@@ -53,11 +53,18 @@ runs:
|
|
|
53
53
|
package_name=""
|
|
54
54
|
version=""
|
|
55
55
|
|
|
56
|
+
# Function to sanitize error messages for GitHub output
|
|
57
|
+
sanitize_error() {
|
|
58
|
+
local message="$1"
|
|
59
|
+
# Replace newlines with spaces, remove extra whitespace, truncate if too long
|
|
60
|
+
echo "$message" | tr '\n' ' ' | tr -s ' ' | cut -c1-500
|
|
61
|
+
}
|
|
62
|
+
|
|
56
63
|
# Validate package.json exists
|
|
57
64
|
if [ ! -f "package.json" ]; then
|
|
58
65
|
error_message="❌ ERROR: package.json not found in current directory. Make sure you're running this action in a directory with a package.json file"
|
|
59
66
|
echo "$error_message"
|
|
60
|
-
echo "error-message=$error_message" >> $GITHUB_OUTPUT
|
|
67
|
+
echo "error-message=$(sanitize_error "$error_message")" >> $GITHUB_OUTPUT
|
|
61
68
|
exit 1
|
|
62
69
|
fi
|
|
63
70
|
|
|
@@ -65,7 +72,7 @@ runs:
|
|
|
65
72
|
if ! jq empty package.json 2>/dev/null; then
|
|
66
73
|
error_message="❌ ERROR: package.json is not valid JSON"
|
|
67
74
|
echo "$error_message"
|
|
68
|
-
echo "error-message=$error_message" >> $GITHUB_OUTPUT
|
|
75
|
+
echo "error-message=$(sanitize_error "$error_message")" >> $GITHUB_OUTPUT
|
|
69
76
|
exit 1
|
|
70
77
|
fi
|
|
71
78
|
|
|
@@ -74,7 +81,7 @@ runs:
|
|
|
74
81
|
if [ -z "$package_name" ] || [ "$package_name" = "null" ]; then
|
|
75
82
|
error_message="❌ ERROR: package.json must have a 'name' field"
|
|
76
83
|
echo "$error_message"
|
|
77
|
-
echo "error-message=$error_message" >> $GITHUB_OUTPUT
|
|
84
|
+
echo "error-message=$(sanitize_error "$error_message")" >> $GITHUB_OUTPUT
|
|
78
85
|
exit 1
|
|
79
86
|
fi
|
|
80
87
|
|
|
@@ -104,29 +111,29 @@ runs:
|
|
|
104
111
|
if [ $version_exit_code -ne 0 ]; then
|
|
105
112
|
error_message="❌ ERROR: Failed to update package version. Check if the version format is valid. Error: $version_output"
|
|
106
113
|
echo "$error_message"
|
|
107
|
-
echo "error-message=$error_message" >> $GITHUB_OUTPUT
|
|
114
|
+
echo "error-message=$(sanitize_error "$error_message")" >> $GITHUB_OUTPUT
|
|
108
115
|
exit 1
|
|
109
116
|
fi
|
|
110
117
|
|
|
111
118
|
# Publish package based on detected package manager
|
|
112
119
|
case "$package_manager" in
|
|
113
120
|
"yarn")
|
|
114
|
-
publish_output=$(yarn publish --access public --tag pr --new-version $version --no-git-tag-version 2>&1)
|
|
121
|
+
publish_output=$(yarn publish --access public --tag pr --new-version $version --no-git-tag-version --skip-check-working-tree 2>&1)
|
|
115
122
|
publish_exit_code=$?
|
|
116
123
|
if [ $publish_exit_code -ne 0 ]; then
|
|
117
124
|
error_message="❌ ERROR: Failed to publish package with yarn. Error: $publish_output"
|
|
118
125
|
echo "$error_message"
|
|
119
|
-
echo "error-message=$error_message" >> $GITHUB_OUTPUT
|
|
126
|
+
echo "error-message=$(sanitize_error "$error_message")" >> $GITHUB_OUTPUT
|
|
120
127
|
exit 1
|
|
121
128
|
fi
|
|
122
129
|
;;
|
|
123
130
|
"pnpm")
|
|
124
|
-
publish_output=$(pnpm publish --access public --tag pr 2>&1)
|
|
131
|
+
publish_output=$(pnpm publish --no-git-checks --access public --tag pr 2>&1)
|
|
125
132
|
publish_exit_code=$?
|
|
126
133
|
if [ $publish_exit_code -ne 0 ]; then
|
|
127
134
|
error_message="❌ ERROR: Failed to publish package with pnpm. Error: $publish_output"
|
|
128
135
|
echo "$error_message"
|
|
129
|
-
echo "error-message=$error_message" >> $GITHUB_OUTPUT
|
|
136
|
+
echo "error-message=$(sanitize_error "$error_message")" >> $GITHUB_OUTPUT
|
|
130
137
|
exit 1
|
|
131
138
|
fi
|
|
132
139
|
;;
|
|
@@ -136,7 +143,7 @@ runs:
|
|
|
136
143
|
if [ $publish_exit_code -ne 0 ]; then
|
|
137
144
|
error_message="❌ ERROR: Failed to publish package with npm. Error: $publish_output"
|
|
138
145
|
echo "$error_message"
|
|
139
|
-
echo "error-message=$error_message" >> $GITHUB_OUTPUT
|
|
146
|
+
echo "error-message=$(sanitize_error "$error_message")" >> $GITHUB_OUTPUT
|
|
140
147
|
exit 1
|
|
141
148
|
fi
|
|
142
149
|
;;
|
|
@@ -156,7 +163,7 @@ runs:
|
|
|
156
163
|
|
|
157
164
|
Error: ${{ steps.publish.outputs.error-message }}
|
|
158
165
|
|
|
159
|
-
|
|
166
|
+
📋 [View workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details.
|
|
160
167
|
upsert: true
|
|
161
168
|
tag: ${{ inputs.comment-tag }}
|
|
162
169
|
|
|
@@ -166,6 +173,6 @@ runs:
|
|
|
166
173
|
message: |
|
|
167
174
|
✅ **PR package published successfully!**
|
|
168
175
|
|
|
169
|
-
Install with:
|
|
176
|
+
Install with: <code>npm install ${{ steps.publish.outputs.package-name }}@${{ steps.publish.outputs.version }}</code>
|
|
170
177
|
upsert: true
|
|
171
178
|
tag: ${{ inputs.comment-tag }}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# setup-node-and-install
|
|
2
2
|
|
|
3
3
|
Sets up Node.js environment and installs dependencies with automatic package manager detection, intelligent caching, and
|
|
4
|
-
|
|
4
|
+
dynamic Node version detection via the `node-version` input, `.node-version`, `.nvmrc`, or `package.json` `volta.node`.
|
|
5
5
|
|
|
6
6
|
This action provides the following functionality:
|
|
7
7
|
|
|
8
8
|
- Automatically detects package manager (npm, yarn, or pnpm) from lockfiles
|
|
9
9
|
- Uses GitHub's official `setup-node` action with optimized caching
|
|
10
10
|
- Installs dependencies with appropriate commands based on detected package manager
|
|
11
|
-
- Supports
|
|
11
|
+
- Supports `.node-version`, `.nvmrc`, and `package.json` `volta.node` for version specification
|
|
12
12
|
- Intelligent caching of node_modules when lockfiles are present
|
|
13
13
|
|
|
14
14
|
<!-- DOCTOC SKIP -->
|
|
@@ -30,8 +30,10 @@ steps:
|
|
|
30
30
|
- run: npm test
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
The `node-version` input is optional. If not supplied, this action will attempt to
|
|
34
|
-
|
|
33
|
+
The `node-version` input is optional. If not supplied, this action will attempt to resolve a version using, in order:
|
|
34
|
+
|
|
35
|
+
1. `.node-version`, 2) `.nvmrc`, 3) `package.json` `volta.node`. If none are present, `actions/setup-node` runs without
|
|
36
|
+
an explicit version and will use its default behavior.
|
|
35
37
|
|
|
36
38
|
The `cache-key-suffix` input is optional. If not supplied, no suffix will be applied to the cache key used to restore
|
|
37
39
|
cache in subsequent workflow runs.
|
|
@@ -69,25 +71,25 @@ steps:
|
|
|
69
71
|
- run: npm test
|
|
70
72
|
```
|
|
71
73
|
|
|
72
|
-
## Node Version
|
|
74
|
+
## Node Version Resolution Priority
|
|
73
75
|
|
|
74
76
|
When multiple version specification methods are present, the action uses this priority order:
|
|
75
77
|
|
|
76
78
|
1. **Input parameter** (`node-version`) - highest priority
|
|
77
|
-
2. **`.
|
|
78
|
-
3. **`.
|
|
79
|
-
4.
|
|
79
|
+
2. **`.node-version` file**
|
|
80
|
+
3. **`.nvmrc` file**
|
|
81
|
+
4. **`package.json` `volta.node` property**
|
|
82
|
+
5. **`actions/setup-node` default behavior** when no version is specified
|
|
80
83
|
|
|
81
84
|
## Inputs
|
|
82
85
|
|
|
83
86
|
<!-- start inputs -->
|
|
84
87
|
|
|
85
|
-
| Input | Description
|
|
86
|
-
| ------------------- |
|
|
87
|
-
| `node-version` | Node.js version to install (e.g.
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `working-directory` | Directory containing package.json and lockfile | No | `.` |
|
|
88
|
+
| Input | Description | Required | Default |
|
|
89
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------- |
|
|
90
|
+
| `node-version` | Node.js version to install (e.g. "24", "lts/\*"). Precedence: node-version input > .node-version > .nvmrc > package.json volta.node. | No | - |
|
|
91
|
+
| `install-options` | Extra command-line options to pass to npm/pnpm/yarn install. | No | - |
|
|
92
|
+
| `working-directory` | Directory containing package.json and lockfile. | No | `.` |
|
|
91
93
|
|
|
92
94
|
<!-- end inputs -->
|
|
93
95
|
|
|
@@ -2,39 +2,35 @@ name: setup-node-and-install
|
|
|
2
2
|
|
|
3
3
|
description:
|
|
4
4
|
Sets up Node.js environment and installs dependencies with automatic package manager detection (npm/pnpm/yarn),
|
|
5
|
-
intelligent caching, and .
|
|
5
|
+
intelligent caching, and version detection via input, .node-version, .nvmrc, or package.json volta.node
|
|
6
6
|
|
|
7
7
|
inputs:
|
|
8
8
|
node-version:
|
|
9
|
-
description:
|
|
9
|
+
description:
|
|
10
|
+
'Node.js version to install (e.g. "24", "lts/*"). Precedence: node-version input > .node-version > .nvmrc >
|
|
11
|
+
package.json volta.node.'
|
|
10
12
|
required: false
|
|
11
|
-
cache-key-suffix:
|
|
12
|
-
description: Additional suffix for cache key to enable multiple caches per workflow
|
|
13
|
-
default: ''
|
|
14
13
|
install-options:
|
|
15
|
-
description: Extra command-line options to pass to npm/pnpm/yarn install
|
|
14
|
+
description: Extra command-line options to pass to npm/pnpm/yarn install.
|
|
16
15
|
default: ''
|
|
17
16
|
working-directory:
|
|
18
|
-
description: Directory containing package.json and lockfile
|
|
17
|
+
description: Directory containing package.json and lockfile.
|
|
19
18
|
default: .
|
|
20
19
|
|
|
21
|
-
outputs:
|
|
20
|
+
outputs:
|
|
21
|
+
cache-hit:
|
|
22
|
+
description: Whether the dependency cache was hit (true/false).
|
|
23
|
+
value: "${{ steps.setup-node.outputs.cache-hit == 'true' && 'true' || 'false' }}"
|
|
22
24
|
|
|
23
25
|
runs:
|
|
24
26
|
using: composite
|
|
25
27
|
|
|
26
28
|
steps:
|
|
27
|
-
- name: Validate
|
|
28
|
-
id:
|
|
29
|
+
- name: Validate environment and detect package manager
|
|
30
|
+
id: detect-package-manager
|
|
29
31
|
working-directory: ${{ inputs.working-directory }}
|
|
30
32
|
shell: bash
|
|
31
33
|
run: |
|
|
32
|
-
# Validate working directory exists
|
|
33
|
-
if [ ! -d "." ]; then
|
|
34
|
-
echo "❌ ERROR: Working directory '${{ inputs.working-directory }}' does not exist"
|
|
35
|
-
exit 1
|
|
36
|
-
fi
|
|
37
|
-
|
|
38
34
|
# Validate package.json exists
|
|
39
35
|
if [ ! -f "./package.json" ]; then
|
|
40
36
|
echo "❌ ERROR: package.json not found in '${{ inputs.working-directory }}'"
|
|
@@ -42,48 +38,6 @@ runs:
|
|
|
42
38
|
exit 1
|
|
43
39
|
fi
|
|
44
40
|
|
|
45
|
-
# Validate package.json is valid JSON
|
|
46
|
-
if ! jq empty package.json 2>/dev/null; then
|
|
47
|
-
echo "❌ ERROR: package.json is not valid JSON"
|
|
48
|
-
exit 1
|
|
49
|
-
fi
|
|
50
|
-
|
|
51
|
-
# Check Node version requirements (.nvmrc, .node-version, or input)
|
|
52
|
-
if [[ ! -f "./.nvmrc" && ! -f "./.node-version" && -z "$INPUT_NODE_VERSION" ]]; then
|
|
53
|
-
echo "node-version-missing=true" >> $GITHUB_OUTPUT
|
|
54
|
-
exit
|
|
55
|
-
fi
|
|
56
|
-
|
|
57
|
-
# Validate .nvmrc format if it exists
|
|
58
|
-
if [ -f "./.nvmrc" ]; then
|
|
59
|
-
nvmrc_version=$(cat .nvmrc | tr -d '\n\r' | xargs)
|
|
60
|
-
if [ -z "$nvmrc_version" ]; then
|
|
61
|
-
echo "❌ ERROR: .nvmrc file is empty"
|
|
62
|
-
exit 1
|
|
63
|
-
fi
|
|
64
|
-
echo "📋 Found .nvmrc with Node version: $nvmrc_version"
|
|
65
|
-
fi
|
|
66
|
-
|
|
67
|
-
# Validate .node-version format if it exists (and no .nvmrc)
|
|
68
|
-
if [ -f "./.node-version" ] && [ ! -f "./.nvmrc" ]; then
|
|
69
|
-
node_version_file=$(cat .node-version | tr -d '\n\r' | xargs)
|
|
70
|
-
if [ -z "$node_version_file" ]; then
|
|
71
|
-
echo "❌ ERROR: .node-version file is empty"
|
|
72
|
-
exit 1
|
|
73
|
-
fi
|
|
74
|
-
echo "📋 Found .node-version with Node version: $node_version_file"
|
|
75
|
-
fi
|
|
76
|
-
|
|
77
|
-
# Show priority info if both files exist
|
|
78
|
-
if [ -f "./.nvmrc" ] && [ -f "./.node-version" ]; then
|
|
79
|
-
echo "📋 Both .nvmrc and .node-version found, .nvmrc takes priority"
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
# Validate node-version input format if provided
|
|
83
|
-
if [ -n "$INPUT_NODE_VERSION" ]; then
|
|
84
|
-
echo "📋 Using Node version from input: $INPUT_NODE_VERSION"
|
|
85
|
-
fi
|
|
86
|
-
|
|
87
41
|
# Detect package manager based on lockfiles (including yarn)
|
|
88
42
|
if [ -f "./pnpm-lock.yaml" ]; then
|
|
89
43
|
echo "package-manager=pnpm" >> $GITHUB_OUTPUT
|
|
@@ -106,115 +60,134 @@ runs:
|
|
|
106
60
|
echo "lockfile-path=" >> $GITHUB_OUTPUT
|
|
107
61
|
echo "📦 No lockfile found, defaulting to: npm"
|
|
108
62
|
fi
|
|
109
|
-
env:
|
|
110
|
-
INPUT_NODE_VERSION: ${{ inputs.node-version }}
|
|
111
|
-
|
|
112
|
-
- if: steps.setup.outputs.node-version-missing == 'true'
|
|
113
|
-
uses: actions/github-script@v7
|
|
114
|
-
with:
|
|
115
|
-
script: |
|
|
116
|
-
core.setFailed('You need to create an .nvmrc file, .node-version file, or pass a value in the `node-version` input.')
|
|
117
63
|
|
|
118
64
|
- name: Install pnpm
|
|
119
|
-
if: steps.
|
|
65
|
+
if: steps.detect-package-manager.outputs.package-manager == 'pnpm'
|
|
120
66
|
uses: pnpm/action-setup@v4
|
|
121
67
|
with:
|
|
122
68
|
run_install: false
|
|
123
69
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
id: setup-node
|
|
128
|
-
with:
|
|
129
|
-
# use detected package manager cache if a lockfile is present
|
|
130
|
-
cache: ${{ steps.setup.outputs.lockfile-exists == 'true' && steps.setup.outputs.package-manager || '' }}
|
|
131
|
-
# supplying a node-version input will override the .nvmrc file and give a warning, but that's to be expected.
|
|
132
|
-
cache-dependency-path: ${{ inputs.working-directory }}
|
|
133
|
-
node-version: ${{ inputs.node-version }}
|
|
134
|
-
node-version-file: '${{ inputs.working-directory }}/.nvmrc'
|
|
135
|
-
registry-url: 'https://registry.npmjs.org'
|
|
136
|
-
|
|
137
|
-
- name: Read .node-version file
|
|
138
|
-
if:
|
|
139
|
-
${{ inputs.node-version == '' && hashFiles(format('{0}/.nvmrc', inputs.working-directory)) == '' &&
|
|
140
|
-
hashFiles(format('{0}/.node-version', inputs.working-directory)) != '' }}
|
|
141
|
-
id: read-node-version
|
|
70
|
+
# Detect Node.js version to use (input > .node-version > .nvmrc > package.json volta.node)
|
|
71
|
+
- name: Detect node version
|
|
72
|
+
id: detect-node-version
|
|
142
73
|
working-directory: ${{ inputs.working-directory }}
|
|
143
74
|
shell: bash
|
|
144
75
|
run: |
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
76
|
+
resolved_version=""
|
|
77
|
+
|
|
78
|
+
if [ -n "${INPUT_NODE_VERSION}" ]; then
|
|
79
|
+
resolved_version="$INPUT_NODE_VERSION"
|
|
80
|
+
echo "📋 Using Node version from input: $resolved_version"
|
|
81
|
+
elif [ -f "./.node-version" ]; then
|
|
82
|
+
file_version=$(cat ./.node-version | tr -d '\n\r' | xargs)
|
|
83
|
+
if [ -n "$file_version" ]; then
|
|
84
|
+
resolved_version="$file_version"
|
|
85
|
+
echo "📋 Using Node version from .node-version: $resolved_version"
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
if [ -z "$resolved_version" ] && [ -f "./.nvmrc" ]; then
|
|
90
|
+
nvmrc_version=$(cat ./.nvmrc | tr -d '\n\r' | xargs)
|
|
91
|
+
if [ -n "$nvmrc_version" ]; then
|
|
92
|
+
resolved_version="$nvmrc_version"
|
|
93
|
+
echo "📋 Using Node version from .nvmrc: $resolved_version"
|
|
94
|
+
fi
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
if [ -z "$resolved_version" ]; then
|
|
98
|
+
volta_node=$(jq -r '.volta.node // empty' package.json 2>/dev/null || true)
|
|
99
|
+
if [ -n "$volta_node" ]; then
|
|
100
|
+
resolved_version="$volta_node"
|
|
101
|
+
echo "📋 Using Node version from package.json volta.node: $resolved_version"
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
echo "version=$resolved_version" >> $GITHUB_OUTPUT
|
|
106
|
+
env:
|
|
107
|
+
INPUT_NODE_VERSION: ${{ inputs.node-version }}
|
|
108
|
+
|
|
109
|
+
- name: Setup Node.js
|
|
153
110
|
uses: actions/setup-node@v5
|
|
154
|
-
id: setup-node
|
|
111
|
+
id: setup-node
|
|
155
112
|
with:
|
|
156
|
-
# use detected package manager cache
|
|
157
|
-
cache: ${{ steps.
|
|
113
|
+
# use detected package manager cache
|
|
114
|
+
cache: ${{ steps.detect-package-manager.outputs.package-manager }}
|
|
158
115
|
cache-dependency-path: ${{ inputs.working-directory }}
|
|
159
|
-
node-version: ${{ steps.
|
|
116
|
+
node-version: ${{ steps.detect-node-version.outputs.version }}
|
|
160
117
|
registry-url: 'https://registry.npmjs.org'
|
|
161
118
|
|
|
162
|
-
#
|
|
119
|
+
# apply `./node_modules` cache only if a lockfile is present
|
|
120
|
+
# Will remove the need to run install commands twice. Risk reduced by using a very specific cache key.
|
|
121
|
+
# Cache wont be used if the lockfile changes, package manager, node version, or OS changes.
|
|
122
|
+
- name: Setup node_modules dependency cache
|
|
123
|
+
if: steps.detect-package-manager.outputs.lockfile-exists == 'true'
|
|
124
|
+
uses: actions/cache@v4
|
|
125
|
+
id: cache
|
|
126
|
+
with:
|
|
127
|
+
path: ${{ inputs.working-directory }}/node_modules
|
|
128
|
+
key:
|
|
129
|
+
${{ runner.os }}-node_modules-${{ steps.detect-package-manager.outputs.package-manager }}-${{
|
|
130
|
+
steps.setup-node.outputs.node-version }}-${{ hashFiles(format('{0}/{1}', inputs.working-directory,
|
|
131
|
+
steps.detect-package-manager.outputs.lockfile-path)) }}
|
|
132
|
+
|
|
163
133
|
- name: Install dependencies with pnpm
|
|
164
|
-
if: steps.
|
|
134
|
+
if: steps.detect-package-manager.outputs.package-manager == 'pnpm' && steps.cache.outputs.cache-hit != 'true'
|
|
165
135
|
working-directory: ${{ inputs.working-directory }}
|
|
166
136
|
shell: bash
|
|
167
137
|
run: |
|
|
168
138
|
echo "🔧 Installing dependencies with pnpm..."
|
|
169
|
-
if
|
|
139
|
+
if [ "$LOCKFILE_EXISTS" = "true" ]; then
|
|
140
|
+
INPUT_INSTALL_OPTIONS="--frozen-lockfile $INPUT_INSTALL_OPTIONS"
|
|
141
|
+
else
|
|
142
|
+
echo "⚠️ Warning: No lockfile found, not using --frozen-lockfile"
|
|
143
|
+
fi
|
|
144
|
+
if ! pnpm i $INPUT_INSTALL_OPTIONS; then
|
|
170
145
|
echo "❌ ERROR: pnpm install failed"
|
|
171
146
|
exit 1
|
|
172
147
|
fi
|
|
173
148
|
echo "✅ pnpm install completed successfully"
|
|
174
149
|
env:
|
|
175
150
|
INPUT_INSTALL_OPTIONS: ${{ inputs.install-options }}
|
|
151
|
+
LOCKFILE_EXISTS: ${{ steps.detect-package-manager.outputs.lockfile-exists }}
|
|
176
152
|
|
|
177
|
-
# Install dependencies with yarn
|
|
178
153
|
- name: Install dependencies with yarn
|
|
179
|
-
if: steps.
|
|
154
|
+
if: steps.detect-package-manager.outputs.package-manager == 'yarn' && steps.cache.outputs.cache-hit != 'true'
|
|
180
155
|
working-directory: ${{ inputs.working-directory }}
|
|
181
156
|
shell: bash
|
|
182
157
|
run: |
|
|
183
158
|
echo "🔧 Installing dependencies with yarn..."
|
|
184
|
-
if
|
|
159
|
+
if [ "$LOCKFILE_EXISTS" = "true" ]; then
|
|
160
|
+
INPUT_INSTALL_OPTIONS="--frozen-lockfile $INPUT_INSTALL_OPTIONS"
|
|
161
|
+
else
|
|
162
|
+
echo "⚠️ Warning: No lockfile found, results may vary"
|
|
163
|
+
fi
|
|
164
|
+
if ! yarn install $INPUT_INSTALL_OPTIONS; then
|
|
185
165
|
echo "❌ ERROR: yarn install failed"
|
|
186
166
|
exit 1
|
|
187
167
|
fi
|
|
188
168
|
echo "✅ yarn install completed successfully"
|
|
189
169
|
env:
|
|
190
170
|
INPUT_INSTALL_OPTIONS: ${{ inputs.install-options }}
|
|
171
|
+
LOCKFILE_EXISTS: ${{ steps.detect-package-manager.outputs.lockfile-exists }}
|
|
191
172
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if: steps.setup.outputs.lockfile-exists == 'true' && steps.setup.outputs.package-manager == 'npm'
|
|
173
|
+
- name: Install dependencies with npm
|
|
174
|
+
if: steps.detect-package-manager.outputs.package-manager == 'npm' && steps.cache.outputs.cache-hit != 'true'
|
|
195
175
|
working-directory: ${{ inputs.working-directory }}
|
|
196
176
|
shell: bash
|
|
197
177
|
run: |
|
|
198
|
-
|
|
199
|
-
if
|
|
200
|
-
|
|
201
|
-
|
|
178
|
+
NPM_CMD=""
|
|
179
|
+
if [ "$LOCKFILE_EXISTS" = "true" ]; then
|
|
180
|
+
NPM_CMD="ci"
|
|
181
|
+
else
|
|
182
|
+
echo "⚠️ Warning: No lockfile found, versions may vary"
|
|
183
|
+
NPM_CMD="install"
|
|
202
184
|
fi
|
|
203
|
-
echo "
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
- name: Install dependencies with npm (without lockfile)
|
|
208
|
-
if: steps.setup.outputs.lockfile-exists == 'false' && steps.setup.outputs.package-manager == 'npm'
|
|
209
|
-
working-directory: ${{ inputs.working-directory }}
|
|
210
|
-
shell: bash
|
|
211
|
-
run: |
|
|
212
|
-
echo "🔧 Installing dependencies with npm install..."
|
|
213
|
-
echo "⚠️ Warning: No lockfile found, versions may vary"
|
|
214
|
-
if ! npm install --no-save --prefer-offline --no-audit $INPUT_INSTALL_OPTIONS; then
|
|
215
|
-
echo "❌ ERROR: npm install failed"
|
|
185
|
+
echo "🔧 Installing dependencies with npm $NPM_CMD..."
|
|
186
|
+
if ! npm $NPM_CMD --no-save --prefer-offline --no-audit $INPUT_INSTALL_OPTIONS; then
|
|
187
|
+
echo "❌ ERROR: npm $NPM_CMD failed"
|
|
216
188
|
exit 1
|
|
217
189
|
fi
|
|
218
|
-
echo "✅ npm
|
|
190
|
+
echo "✅ npm $NPM_CMD completed successfully"
|
|
219
191
|
env:
|
|
220
192
|
INPUT_INSTALL_OPTIONS: ${{ inputs.install-options }}
|
|
193
|
+
LOCKFILE_EXISTS: ${{ steps.detect-package-manager.outputs.lockfile-exists }}
|