Skip to content

Commit 753902a

Browse files
committed
Adds automated NPM publishing for monorepo packages
Introduces a workflow to discover package directories and publish new versions to NPM on main branch pushes, skipping packages whose versions already exist. Enables streamlined, version-aware release management for all monorepo packages.
1 parent 380cab2 commit 753902a

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

.github/workflows/publish.yml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: "Monorepo Packages Release to NPM"
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
id-token: write
11+
contents: read
12+
13+
jobs:
14+
discover-packages:
15+
name: "Discover Packages"
16+
runs-on: ubuntu-latest
17+
outputs:
18+
packages: ${{ steps.packages.outputs.matrix }}
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- id: packages
23+
name: "Find packages in ./packages"
24+
run: |
25+
echo "Discovering packages in ./packages..."
26+
# Get folder names under packages/ and convert to JSON array
27+
PACKAGES=$(find packages -maxdepth 1 -mindepth 1 -type d -printf '%f\n' \
28+
| jq -R -s -c 'split("\n")[:-1]')
29+
echo "Found packages: $PACKAGES"
30+
echo "matrix=$PACKAGES" >> "$GITHUB_OUTPUT"
31+
32+
release:
33+
name: "Release ${{ matrix.package }} to NPM"
34+
needs: discover-packages
35+
runs-on: ubuntu-latest
36+
strategy:
37+
fail-fast: false
38+
matrix:
39+
package: ${{ fromJson(needs.discover-packages.outputs.packages) }}
40+
env:
41+
# Directory for the current package in the matrix
42+
PACKAGE_DIR: packages/${{ matrix.package }}
43+
44+
steps:
45+
- uses: actions/checkout@v4
46+
47+
- name: Read version from package.json
48+
id: read_version
49+
run: |
50+
VERSION=$(jq -r '.version' "$PACKAGE_DIR/package.json")
51+
echo "Package dir: $PACKAGE_DIR"
52+
echo "Package version: $VERSION"
53+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
54+
55+
- name: Check if version exists on npm
56+
id: check
57+
run: |
58+
PACKAGE_NAME=$(jq -r '.name' "$PACKAGE_DIR/package.json")
59+
VERSION="${{ steps.read_version.outputs.version }}"
60+
61+
echo "Checking npm for $PACKAGE_NAME@$VERSION"
62+
63+
EXISTS=$(npm view "$PACKAGE_NAME" versions --json 2>/dev/null \
64+
| jq -e '.[] | select(.=="'"$VERSION"'")' || echo "no")
65+
66+
if [ "$EXISTS" = "no" ]; then
67+
echo "Version $PACKAGE_NAME@$VERSION does not exist on npm. Will publish."
68+
echo "should_publish=true" >> "$GITHUB_OUTPUT"
69+
else
70+
echo "Version $PACKAGE_NAME@$VERSION already exists on npm. Skipping publish."
71+
echo "should_publish=false" >> "$GITHUB_OUTPUT"
72+
fi
73+
74+
- uses: actions/setup-node@v4
75+
if: steps.check.outputs.should_publish == 'true'
76+
with:
77+
node-version: '25'
78+
registry-url: 'https://registry.npmjs.org'
79+
scope: \@${{ github.repository_owner }}
80+
81+
- name: Update npm
82+
if: steps.check.outputs.should_publish == 'true'
83+
run: npm install -g npm@latest
84+
85+
- name: Install dependencies (root)
86+
if: steps.check.outputs.should_publish == 'true'
87+
run: npm ci
88+
89+
- name: Build package
90+
if: steps.check.outputs.should_publish == 'true'
91+
working-directory: ${{ env.PACKAGE_DIR }}
92+
run: npm run build
93+
94+
- name: Publish package
95+
if: steps.check.outputs.should_publish == 'true'
96+
working-directory: ${{ env.PACKAGE_DIR }}
97+
run: npm publish --access public
98+
99+
- name: Skip publish (version already exists)
100+
if: steps.check.outputs.should_publish == 'false'
101+
run: |
102+
PACKAGE_NAME=$(jq -r '.name' "$PACKAGE_DIR/package.json")
103+
echo "Version ${{ steps.read_version.outputs.version }} for $PACKAGE_NAME already exists on npm. Skipping publish."

0 commit comments

Comments
 (0)