Skip to content

Commit 89b74e1

Browse files
Copilotneilime
authored andcommitted
feat(actions): add package action
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent cf95fa3 commit 89b74e1

File tree

5 files changed

+262
-0
lines changed

5 files changed

+262
-0
lines changed

.github/workflows/__shared-ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ jobs:
3535
permissions:
3636
contents: read
3737

38+
test-action-package:
39+
name: Test action "package"
40+
needs: linter
41+
uses: ./.github/workflows/__test-action-package.yml
42+
permissions:
43+
contents: read
44+
3845
test-action-setup-node:
3946
name: Test action "setup-node"
4047
needs: linter
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Internal - Tests for "package" action
2+
3+
on:
4+
workflow_call:
5+
6+
permissions: {}
7+
8+
jobs:
9+
test:
10+
name: Test "package" (${{ matrix.working-directory }})
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
14+
strategy:
15+
matrix:
16+
include:
17+
- working-directory: tests/npm
18+
artifact-suffix: npm
19+
- working-directory: tests/pnpm
20+
artifact-suffix: pnpm
21+
- working-directory: tests/pnpm-package-manager
22+
artifact-suffix: pnpm-package-manager
23+
- working-directory: tests/yarn
24+
artifact-suffix: yarn
25+
steps:
26+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
27+
28+
- id: package
29+
uses: ./actions/package
30+
with:
31+
working-directory: ${{ matrix.working-directory }}
32+
artifact-name: package-tarball-${{ matrix.artifact-suffix }}
33+
34+
- name: Check "package" outputs
35+
run: |
36+
if [ -z "${{ steps.package.outputs.package-tarball-path }}" ]; then
37+
echo "package-tarball-path output is empty"
38+
exit 1
39+
fi
40+
41+
if [ ! -f "${{ steps.package.outputs.package-tarball-path }}" ]; then
42+
echo "Generated package tarball does not exist"
43+
exit 1
44+
fi
45+
46+
if [ -z "${{ steps.package.outputs.package-tarball-artifact-id }}" ]; then
47+
echo "package-tarball-artifact-id output is empty"
48+
exit 1
49+
fi

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ _Actions for continuous integration steps: build, lint, and test._
2626

2727
#### - [Codecov](actions/codecov/README.md)
2828

29+
#### - [Package](actions/package/README.md)
30+
2931
#### - [Lint](actions/lint/README.md)
3032

3133
#### - [Test](actions/test/README.md)

actions/package/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!-- header:start -->
2+
3+
# GitHub Action: Package
4+
5+
---
6+
7+
<!-- header:end -->
8+
9+
## Overview
10+
11+
Action to create and upload an npm package tarball from a Node.js project.
12+
13+
## Usage
14+
15+
```yaml
16+
- uses: hoverkraft-tech/ci-github-nodejs/actions/package@c9d9d041ba4ef35695ee469c4782fa6a8bbebbcc # 0.21.2
17+
with:
18+
# Working directory where the package is packed.
19+
# Can be absolute or relative to the repository root.
20+
#
21+
# Default: `.`
22+
working-directory: .
23+
24+
# Optional build artifact ID to download before packaging.
25+
build-artifact-id: ""
26+
27+
# Optional version to apply with `npm version` before packaging.
28+
# The version is applied without creating a git tag.
29+
version: ""
30+
31+
# Name of the uploaded package tarball artifact
32+
# Default: `package-tarball`
33+
artifact-name: package-tarball
34+
```
35+
36+
## Inputs
37+
38+
| **Input** | **Description** | **Required** | **Default** |
39+
| ----------------------- | ---------------------------------------------------------------- | ------------ | ----------------- |
40+
| **`working-directory`** | Working directory where the package is packed. | **false** | `.` |
41+
| | Can be absolute or relative to the repository root. | | |
42+
| **`build-artifact-id`** | Optional build artifact ID to download before packaging. | **false** | - |
43+
| | When provided, the artifact will be downloaded to the workspace. | | |
44+
| **`version`** | Optional version to apply with `npm version` before packaging. | **false** | - |
45+
| | The version is applied without creating a Git tag. | | |
46+
| **`artifact-name`** | Name of the uploaded package tarball artifact | **false** | `package-tarball` |
47+
48+
## Outputs
49+
50+
| **Output** | **Description** |
51+
| --------------------------------- | ---------------------------------------------- |
52+
| **`package-tarball-path`** | Absolute path to the generated package tarball |
53+
| **`package-tarball-artifact-id`** | Artifact ID of the uploaded package tarball |
54+
55+
## Contributing
56+
57+
Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.

actions/package/action.yml

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
name: "Package"
2+
description: "Action to create and upload an npm package tarball from a Node.js project"
3+
author: hoverkraft
4+
branding:
5+
icon: package
6+
color: blue
7+
8+
inputs:
9+
working-directory:
10+
description: |
11+
Working directory where the package is packed.
12+
Can be absolute or relative to the repository root.
13+
required: false
14+
default: "."
15+
build-artifact-id:
16+
description: |
17+
Optional build artifact ID to download before packaging.
18+
When provided, the artifact will be downloaded to the workspace.
19+
required: false
20+
default: ""
21+
build-artifact-path:
22+
description: |
23+
Optional path to the build artifact contents relative to the workspace root.
24+
Used to locate the files to be included in the package when a build artifact is downloaded.
25+
required: false
26+
default: "${{ github.workspace }}"
27+
version:
28+
description: |
29+
Optional version to apply with `npm version` before packaging.
30+
The version is applied without creating a Git tag.
31+
required: false
32+
default: ""
33+
artifact-name:
34+
description: "Name of the uploaded package tarball artifact"
35+
required: false
36+
default: "package-tarball"
37+
38+
outputs:
39+
package-tarball-path:
40+
description: "Absolute path to the generated package tarball"
41+
value: ${{ steps.package.outputs.package-tarball-path }}
42+
package-tarball-artifact-id:
43+
description: "Artifact ID of the uploaded package tarball"
44+
value: ${{ steps.upload-package-tarball.outputs.artifact-id }}
45+
46+
runs:
47+
using: "composite"
48+
steps:
49+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
50+
with:
51+
persist-credentials: false
52+
53+
- shell: bash
54+
# FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684
55+
run: mkdir -p ./self-package-action/ && cp -r $GITHUB_ACTION_PATH/../* ./self-package-action/
56+
57+
- id: setup-node
58+
uses: ./self-package-action/setup-node
59+
with:
60+
working-directory: ${{ inputs.working-directory }}
61+
62+
- name: Download build artifacts
63+
if: inputs.build-artifact-id != ''
64+
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
65+
with:
66+
artifact-ids: ${{ inputs.build-artifact-id }}
67+
path: ${{ inputs.build-artifact-path }}
68+
69+
- id: package
70+
name: Create package tarball for verification
71+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
72+
env:
73+
WORKING_DIRECTORY: ${{ inputs.working-directory }}
74+
RELEASE_VERSION: ${{ inputs.version }}
75+
RUNNER_TEMP: ${{ runner.temp }}
76+
with:
77+
script: |
78+
const fs = require('node:fs');
79+
const path = require('node:path');
80+
const { execFileSync } = require('node:child_process');
81+
82+
let workingDirectory = process.env.WORKING_DIRECTORY || '.';
83+
if (!path.isAbsolute(workingDirectory)) {
84+
workingDirectory = path.join(process.env.GITHUB_WORKSPACE, workingDirectory);
85+
}
86+
87+
if (!fs.existsSync(workingDirectory)) {
88+
core.setFailed(`The specified working directory does not exist: ${workingDirectory}`);
89+
return;
90+
}
91+
92+
workingDirectory = path.resolve(workingDirectory);
93+
const releaseVersion = (process.env.RELEASE_VERSION || '').trim();
94+
const runnerTemp = process.env.RUNNER_TEMP;
95+
96+
if (releaseVersion) {
97+
core.info(`Updating package version to provided release version: ${releaseVersion}`);
98+
execFileSync(
99+
'npm',
100+
['version', releaseVersion, '--no-git-tag-version', '--no-workspaces-update'],
101+
{
102+
cwd: workingDirectory,
103+
stdio: 'inherit',
104+
},
105+
);
106+
}
107+
108+
const packOutput = execFileSync('npm', ['pack', '--json', '--pack-destination', runnerTemp], {
109+
cwd: workingDirectory,
110+
encoding: 'utf8',
111+
});
112+
113+
let packageInfo;
114+
try {
115+
packageInfo = JSON.parse(packOutput);
116+
} catch (error) {
117+
core.setFailed(`Failed to parse npm pack output: ${error.message}`);
118+
return;
119+
}
120+
121+
const tarballName = packageInfo?.[0]?.filename;
122+
if (!tarballName) {
123+
core.setFailed('No tarball filename returned by npm pack');
124+
return;
125+
}
126+
127+
const tarballPath = path.join(runnerTemp, tarballName);
128+
if (!fs.existsSync(tarballPath)) {
129+
core.setFailed(`Tarball was not created at expected path: ${tarballPath}`);
130+
return;
131+
}
132+
133+
core.info(`Generated package tarball: ${tarballPath}`);
134+
core.setOutput('package-tarball-path', tarballPath);
135+
136+
- name: Upload package tarball
137+
id: upload-package-tarball
138+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
139+
with:
140+
name: ${{ inputs.artifact-name }}
141+
path: ${{ steps.package.outputs.package-tarball-path }}
142+
if-no-files-found: error
143+
144+
# FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684
145+
- shell: bash
146+
if: always()
147+
run: rm -fr ./self-package-action

0 commit comments

Comments
 (0)