1- name : Publish to NPM
1+ name : Auto Publish to NPM
22
33on :
44 push :
5- tags :
6- - ' v*'
5+ branches : [main, develop]
6+ paths :
7+ - ' packages/*/package.json'
8+ - ' packages/*/src/**'
9+ - ' packages/*/build/**'
710 workflow_dispatch :
811 inputs :
9- version :
10- description : ' Version to publish (patch, minor, major, or specific version like 1.2.3)'
11- required : true
12- default : ' patch'
13- type : choice
14- options :
15- - patch
16- - minor
17- - major
12+ force_publish :
13+ description : ' Force publish packages even if versions match'
14+ required : false
15+ default : false
16+ type : boolean
1817 packages :
19- description : ' Packages to publish (comma-separated: mcp,types or leave empty for all)'
18+ description : ' Specific packages to check (comma-separated: mcp,core,ai,cli or leave empty for all)'
2019 required : false
2120 type : string
2221
2322jobs :
24- publish :
23+ check-and- publish :
2524 runs-on : ubuntu-latest
2625 permissions :
27- contents : write
26+ contents : read
2827 id-token : write
2928
3029 steps :
3130 - name : Checkout code
3231 uses : actions/checkout@v4
3332 with :
3433 fetch-depth : 0
35- token : ${{ secrets.GITHUB_TOKEN }}
3634
3735 - name : Setup Node.js
3836 uses : actions/setup-node@v4
3937 with :
40- node-version : ' 18 '
38+ node-version : ' 20 '
4139 registry-url : ' https://registry.npmjs.org'
4240
4341 - name : Setup pnpm
4442 uses : pnpm/action-setup@v4
4543 with :
46- version : 10.12 .1
44+ version : 10.13 .1
4745 run_install : false
4846
4947 - name : Get pnpm store directory
@@ -66,116 +64,156 @@ jobs:
6664 run : pnpm build
6765
6866 - name : Run tests
69- run : pnpm test
70-
71- - name : Configure git
72- run : |
73- git config --local user.email "[email protected] " 74- git config --local user.name "GitHub Action"
67+ run : pnpm test && pnpm test:packages
7568
76- - name : Determine version bump
77- id : version
69+ - name : Check versions and determine what to publish
70+ id : check_versions
71+ env :
72+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
7873 run : |
79- if [ "${{ github.event_name }}" == "push" ] && [[ "${{ github.ref }}" == refs/tags/* ]]; then
80- VERSION="${{ github.ref_name }}"
81- VERSION="${VERSION#v}" # Remove 'v' prefix
82- echo "version=$VERSION" >> $GITHUB_OUTPUT
83- echo "bump=false" >> $GITHUB_OUTPUT
84- else
85- VERSION="${{ github.event.inputs.version }}"
86- echo "version=$VERSION" >> $GITHUB_OUTPUT
87- echo "bump=true" >> $GITHUB_OUTPUT
74+ PACKAGES_TO_PUBLISH=""
75+ FORCE_PUBLISH="${{ github.event.inputs.force_publish }}"
76+ SPECIFIED_PACKAGES="${{ github.event.inputs.packages }}"
77+
78+ # Define all publishable packages
79+ declare -A PACKAGE_MAP=(
80+ ["mcp"]="packages/mcp"
81+ ["core"]="packages/core"
82+ ["ai"]="packages/ai"
83+ ["cli"]="packages/cli"
84+ )
85+
86+ # If specific packages specified, filter to those
87+ if [ -n "$SPECIFIED_PACKAGES" ]; then
88+ IFS=',' read -ra SPECIFIED_ARRAY <<< "$SPECIFIED_PACKAGES"
89+ declare -A FILTERED_MAP
90+ for pkg in "${SPECIFIED_ARRAY[@]}"; do
91+ pkg=$(echo "$pkg" | xargs) # trim whitespace
92+ if [[ -n "${PACKAGE_MAP[$pkg]}" ]]; then
93+ FILTERED_MAP[$pkg]="${PACKAGE_MAP[$pkg]}"
94+ fi
95+ done
96+ PACKAGE_MAP=()
97+ for key in "${!FILTERED_MAP[@]}"; do
98+ PACKAGE_MAP[$key]="${FILTERED_MAP[$key]}"
99+ done
88100 fi
89-
90- - name : Determine packages to publish
91- id : packages
92- run : |
93- if [ -n "${{ github.event.inputs.packages }}" ]; then
94- PACKAGES="${{ github.event.inputs.packages }}"
95- else
96- PACKAGES="mcp,types"
97- fi
98- echo "packages=$PACKAGES" >> $GITHUB_OUTPUT
99-
100- - name : Version bump packages
101- if : steps.version.outputs.bump == 'true'
102- run : |
103- IFS=',' read -ra PACKAGE_ARRAY <<< "${{ steps.packages.outputs.packages }}"
104- for pkg in "${PACKAGE_ARRAY[@]}"; do
105- pkg=$(echo "$pkg" | xargs) # trim whitespace
106- if [ "$pkg" == "mcp" ]; then
107- cd packages/mcp
108- npm version ${{ steps.version.outputs.version }} --no-git-tag-version
109- cd ../..
110- elif [ "$pkg" == "types" ]; then
111- cd packages/types
112- npm version ${{ steps.version.outputs.version }} --no-git-tag-version
113- cd ../..
114- fi
115- done
116-
117- - name : Set specific version for packages
118- if : steps.version.outputs.bump == 'false'
119- run : |
120- IFS=',' read -ra PACKAGE_ARRAY <<< "${{ steps.packages.outputs.packages }}"
121- for pkg in "${PACKAGE_ARRAY[@]}"; do
122- pkg=$(echo "$pkg" | xargs) # trim whitespace
123- if [ "$pkg" == "mcp" ]; then
124- cd packages/mcp
125- npm version ${{ steps.version.outputs.version }} --no-git-tag-version --allow-same-version
126- cd ../..
127- elif [ "$pkg" == "types" ]; then
128- cd packages/types
129- npm version ${{ steps.version.outputs.version }} --no-git-tag-version --allow-same-version
130- cd ../..
101+
102+ for pkg_key in "${!PACKAGE_MAP[@]}"; do
103+ pkg_dir="${PACKAGE_MAP[$pkg_key]}"
104+
105+ if [ -f "$pkg_dir/package.json" ]; then
106+ PKG_NAME=$(jq -r '.name' "$pkg_dir/package.json")
107+ LOCAL_VERSION=$(jq -r '.version' "$pkg_dir/package.json")
108+
109+ echo "Checking $PKG_NAME@$LOCAL_VERSION..."
110+
111+ # Check if package exists on npm and get published version
112+ NPM_VERSION=$(npm view "$PKG_NAME" version 2>/dev/null || echo "0.0.0")
113+
114+ echo "Local: $LOCAL_VERSION, NPM: $NPM_VERSION"
115+
116+ # Compare versions using node semver logic
117+ SHOULD_PUBLISH=$(node -e "
118+ const semver = require('semver');
119+ const local = '$LOCAL_VERSION';
120+ const npm = '$NPM_VERSION';
121+ const force = '$FORCE_PUBLISH' === 'true';
122+
123+ if (force) {
124+ console.log('true');
125+ } else if (npm === '0.0.0') {
126+ // Package doesn't exist on npm
127+ console.log('true');
128+ } else {
129+ // Check if local version is greater than npm version
130+ console.log(semver.gt(local, npm) ? 'true' : 'false');
131+ }
132+ ")
133+
134+ if [ "$SHOULD_PUBLISH" = "true" ]; then
135+ echo "✅ Will publish $PKG_NAME@$LOCAL_VERSION (npm has $NPM_VERSION)"
136+ PACKAGES_TO_PUBLISH="$PACKAGES_TO_PUBLISH$pkg_key,"
137+ else
138+ echo "⏭️ Skipping $PKG_NAME@$LOCAL_VERSION (same as or older than npm version $NPM_VERSION)"
139+ fi
131140 fi
132141 done
133-
134- - name : Rebuild after version update
135- run : pnpm build
142+
143+ # Remove trailing comma
144+ PACKAGES_TO_PUBLISH=${PACKAGES_TO_PUBLISH%,}
145+
146+ echo "packages_to_publish=$PACKAGES_TO_PUBLISH" >> $GITHUB_OUTPUT
147+
148+ if [ -z "$PACKAGES_TO_PUBLISH" ]; then
149+ echo "has_packages_to_publish=false" >> $GITHUB_OUTPUT
150+ echo "No packages need to be published."
151+ else
152+ echo "has_packages_to_publish=true" >> $GITHUB_OUTPUT
153+ echo "Packages to publish: $PACKAGES_TO_PUBLISH"
154+ fi
136155
137156 - name : Publish packages
157+ id : publish
158+ if : steps.check_versions.outputs.has_packages_to_publish == 'true'
138159 env :
139- NODE_AUTH_TOKEN : ${{ secrets.NPM_PUBLISH_TOKEN }}
160+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
140161 run : |
141- IFS=',' read -ra PACKAGE_ARRAY <<< "${{ steps.packages.outputs.packages }}"
162+ PACKAGES="${{ steps.check_versions.outputs.packages_to_publish }}"
163+ IFS=',' read -ra PACKAGE_ARRAY <<< "$PACKAGES"
164+
165+ PUBLISHED_PACKAGES=""
166+
142167 for pkg in "${PACKAGE_ARRAY[@]}"; do
143- pkg=$(echo "$pkg" | xargs) # trim whitespace
144- if [ "$pkg" == "mcp" ]; then
145- echo "Publishing @codervisor/devlog-mcp..."
146- cd packages/mcp
147- npm publish --access public
148- cd ../..
149- elif [ "$pkg" == "types" ]; then
150- echo "Publishing @codervisor/devlog-types..."
151- cd packages/types
152- npm publish --access public
153- cd ../..
154- fi
168+ case $pkg in
169+ "mcp")
170+ echo "Publishing @codervisor/devlog-mcp..."
171+ cd packages/mcp
172+ npm publish --access public
173+ PUBLISHED_PACKAGES="$PUBLISHED_PACKAGES@codervisor/devlog-mcp@$(jq -r '.version' package.json) "
174+ cd ../..
175+ ;;
176+ "core")
177+ echo "Publishing @codervisor/devlog-core..."
178+ cd packages/core
179+ npm publish --access public
180+ PUBLISHED_PACKAGES="$PUBLISHED_PACKAGES@codervisor/devlog-core@$(jq -r '.version' package.json) "
181+ cd ../..
182+ ;;
183+ "ai")
184+ echo "Publishing @codervisor/devlog-ai..."
185+ cd packages/ai
186+ npm publish --access public
187+ PUBLISHED_PACKAGES="$PUBLISHED_PACKAGES@codervisor/devlog-ai@$(jq -r '.version' package.json) "
188+ cd ../..
189+ ;;
190+ "cli")
191+ echo "Publishing @codervisor/devlog-cli..."
192+ cd packages/cli
193+ npm publish --access public
194+ PUBLISHED_PACKAGES="$PUBLISHED_PACKAGES@codervisor/devlog-cli@$(jq -r '.version' package.json) "
195+ cd ../..
196+ ;;
197+ esac
155198 done
199+
200+ echo "published_packages=$PUBLISHED_PACKAGES" >> $GITHUB_OUTPUT
201+ echo "Successfully published: $PUBLISHED_PACKAGES"
156202
157- - name : Commit version changes
158- if : steps.version.outputs.bump == 'true'
203+ - name : Create summary
204+ if : always()
159205 run : |
160- git add .
161- git commit -m "chore: bump version to ${{ steps.version.outputs.version }}" || echo "No changes to commit"
162- git push origin main
163-
164- - name : Create GitHub release
165- if : steps.version.outputs.bump == 'true'
166- uses : actions/create-release@v1
167- env :
168- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
169- with :
170- tag_name : v${{ steps.version.outputs.version }}
171- release_name : Release v${{ steps.version.outputs.version }}
172- body : |
173- ## Changes
174-
175- Published packages: ${{ steps.packages.outputs.packages }}
176-
177- ### Packages
178- - @codervisor/devlog-mcp@${{ steps.version.outputs.version }}
179- - @codervisor/devlog-types@${{ steps.version.outputs.version }}
180- draft : false
181- prerelease : false
206+ echo "## 📦 NPM Publish Results" >> $GITHUB_STEP_SUMMARY
207+
208+ if [ "${{ steps.check_versions.outputs.has_packages_to_publish }}" == "true" ]; then
209+ echo "### ✅ Successfully Published" >> $GITHUB_STEP_SUMMARY
210+ echo "${{ steps.publish.outputs.published_packages }}" >> $GITHUB_STEP_SUMMARY
211+ else
212+ echo "### ℹ️ No Packages to Publish" >> $GITHUB_STEP_SUMMARY
213+ echo "All package versions are up to date with npmjs.org" >> $GITHUB_STEP_SUMMARY
214+ fi
215+
216+ echo "" >> $GITHUB_STEP_SUMMARY
217+ echo "**Trigger:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
218+ echo "**Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
219+ echo "**Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
0 commit comments