11name : Publish Extension to Visual Studio Marketplace
2+ run-name : ${{ inputs.dry_run && '🧪 Test publish workflow' || format('Validate, 🚀 Publish and Post-Process triggered from `{0}` branch', github.ref_name) }}
23
34on :
45 push :
5- branches :
6- - main
7- paths-ignore :
8- - ' .github/workflows/**' # Ignore changes to workflow files
9- workflow_dispatch : # Allow manual trigger
6+ branches : [pipeline, main]
7+ paths-ignore : ['.github/workflows/**']
8+ workflow_dispatch :
9+ inputs :
10+ dry_run :
11+ description : ' Run in test mode (no actual publish)'
12+ type : boolean
13+ default : false
1014
1115jobs :
12- verify-changes :
16+ validate :
1317 runs-on : ubuntu-latest
1418 outputs :
15- should_publish : ${{ steps.check-changes.outputs.should_publish }}
16-
19+ should_publish : ${{ steps.changes.outputs.should_publish }}
20+ version : ${{ steps.version.outputs.current }}
21+ skip_reason : ${{ steps.changes.outputs.skip_reason }}
22+ has_code_changes : ${{ steps.changes.outputs.has_code_changes }}
1723 steps :
1824 - name : Checkout code
1925 uses : actions/checkout@v4
2026 with :
21- fetch-depth : 0 # Fetch all history for all tags and branches
22-
23- - name : Get changed files
24- id : changed-files
27+ fetch-depth : 2 # For version diff check
28+
29+ - name : Get version info
30+ id : version
2531 run : |
26- echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | tr '\n' ' ')" >> $GITHUB_OUTPUT
27-
28- - name : Check version change and file types
29- id : check-changes
32+ CURRENT=$(node -p "require('./package.json').version")
33+ echo "current=$CURRENT" >> $GITHUB_OUTPUT
34+ echo "✨ Current version: $CURRENT"
35+
36+ - name : Analyze changes
37+ id : changes
3038 run : |
31- # Check if package.json version changed
32- VERSION_CHANGED =$(git diff ${{ github.event.before }} ${{ github.event.after }} package.json | grep '+\s* "version"' )
39+ # Get the version change status
40+ VERSION_UPDATED =$(git diff HEAD^ HEAD -- package.json | grep -q ' "version":' && echo "true" || echo "false" )
3341
34- # Get list of changed files
35- CHANGED_FILES="${{ steps.changed-files.outputs.files }}"
42+ # Get code changes (excluding docs and configuration)
43+ CODE_CHANGES=$(git diff --name-only HEAD^ HEAD | \
44+ grep -vE '\.(md|txt)$|^docs/|^\.github/|^\.vscode/|package\.json$' || echo "")
3645
37- # Check if only documentation files were changed
38- DOCS_ONLY=true
39- for file in $CHANGED_FILES; do
40- if [[ ! $file =~ \.(md|txt|doc|docx)$ ]] && [[ ! $file =~ ^docs/ ]]; then
41- DOCS_ONLY=false
42- break
43- fi
44- done
46+ # Get documentation changes
47+ DOC_CHANGES=$(git diff --name-only HEAD^ HEAD | \
48+ grep -E '\.(md|txt)$|^docs/' || echo "")
4549
46- # Initialize should_publish as false
47- echo "should_publish=false" >> $GITHUB_OUTPUT
50+ # Output change detection results
51+ echo "has_code_changes=${CODE_CHANGES:+true}" >> $GITHUB_OUTPUT
52+ echo "has_doc_changes=${DOC_CHANGES:+true}" >> $GITHUB_OUTPUT
4853
49- if [[ "$DOCS_ONLY" == "true" ]]; then
50- echo "ℹ️ Only documentation files were changed"
51- echo "should_publish=false" >> $GITHUB_OUTPUT
52- elif [[ -z "$VERSION_CHANGED" ]]; then
53- echo "❌ Version in package.json was not updated"
54- echo "should_publish=false" >> $GITHUB_OUTPUT
54+ # Determine workflow action based on changes
55+ if [[ "$VERSION_UPDATED" == "true" ]]; then
56+ if [[ -n "$CODE_CHANGES" ]]; then
57+ # Version bump with code changes - proceed with publish
58+ echo "should_publish=true" >> $GITHUB_OUTPUT
59+ echo "skip_reason=" >> $GITHUB_OUTPUT
60+ echo "✅ Publishing needed: Version update detected with code changes"
61+ else
62+ # Version bump without code changes - skip but warn
63+ echo "should_publish=false" >> $GITHUB_OUTPUT
64+ echo "skip_reason=Version update without code changes" >> $GITHUB_OUTPUT
65+ echo "⚠️ Version update detected but no code changes found"
66+ fi
5567 else
56- echo "✅ Version changed and non-documentation files modified"
57- echo "should_publish=true" >> $GITHUB_OUTPUT
68+ if [[ -n "$CODE_CHANGES" ]]; then
69+ # Code changes without version bump - fail
70+ echo "should_publish=false" >> $GITHUB_OUTPUT
71+ echo "skip_reason=Code changes without version update" >> $GITHUB_OUTPUT
72+ echo "❌ Code changes detected without version update"
73+ exit 1
74+ else
75+ # No relevant changes - skip
76+ echo "should_publish=false" >> $GITHUB_OUTPUT
77+ if [[ -n "$DOC_CHANGES" ]]; then
78+ echo "skip_reason=Documentation only changes" >> $GITHUB_OUTPUT
79+ echo "ℹ️ Documentation only changes detected"
80+ else
81+ echo "skip_reason=No significant changes" >> $GITHUB_OUTPUT
82+ echo "ℹ️ No significant changes detected"
83+ fi
84+ fi
5885 fi
5986
60- publish :
61- needs : verify-changes
62- if : needs.verify-changes .outputs.should_publish == 'true'
87+ build-and-package :
88+ needs : validate
89+ if : needs.validate .outputs.should_publish == 'true'
6390 runs-on : ubuntu-latest
64- environment : VSC EXT
65-
91+ outputs :
92+ vsix_path : ${{ steps.package.outputs.path }}
6693 steps :
67- - name : Checkout code
68- uses : actions/checkout@v4
69-
70- - name : Setup Node.js
71- uses : actions/setup-node@v4
94+ - uses : actions/checkout@v4
95+ - uses : actions/setup-node@v4
7296 with :
7397 node-version : ' 18'
74-
75- - name : Install dependencies
76- run : npm ci
77-
78- - name : Compile
79- run : npm run compile
80-
81- - name : Install vsce
82- run : npm install -g @vscode/vsce
83-
84- - name : Clean existing VSIX files
85- run : rm -f *.vsix
86-
87- - name : Package Extension
88- run : vsce package
89-
90- - name : Get Package Info
98+
99+ - name : Install and build
100+ run : |
101+ npm ci
102+ npm run compile
103+ npm install -g @vscode/vsce
104+
105+ - name : Package extension
91106 id : package
92107 run : |
93- VERSION=$(node -p "require('./package.json').version")
94- VSIX_PATH="simple-coding-time-tracker-${VERSION}.vsix"
95- if [ ! -f "$VSIX_PATH" ]; then
96- echo "Error: Expected VSIX file $VSIX_PATH not found"
108+ VERSION="${{ needs.validate.outputs.version }}"
109+ VSIX_NAME="simple-coding-time-tracker-${VERSION}.vsix"
110+
111+ rm -f *.vsix
112+ vsce package
113+
114+ if [ ! -f "$VSIX_NAME" ]; then
115+ echo "::error::Failed to create VSIX package"
97116 exit 1
98117 fi
99- echo "Package created: $VSIX_PATH"
100- echo "vsix_path=$VSIX_PATH" >> $GITHUB_OUTPUT
101- echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
102- echo "version=$VERSION" >> $GITHUB_OUTPUT
103118
104- - name : Upload VSIX as artifact
119+ echo "path=$VSIX_NAME" >> $GITHUB_OUTPUT
120+ echo "✅ Package created: $VSIX_NAME"
121+
122+ - name : Upload artifact
105123 uses : actions/upload-artifact@v4
106124 with :
107- name : extension-release-v${{ steps.package.outputs.version }}-${{ steps.package.outputs.date }}
108- path : " *.vsix"
109- retention-days : 99 # Maximum retention period allowed by GitHub
125+ name : extension-v${{ needs.validate.outputs.version }}
126+ path : ${{ steps.package.outputs.path }}
127+ retention-days : 90
128+
129+ publish :
130+ needs : [validate, build-and-package]
131+ runs-on : ubuntu-latest
132+ environment : VSC EXT
133+ outputs :
134+ status : ${{ steps.publish.outputs.status }}
135+ error_detail : ${{ steps.publish.outputs.error_detail }}
136+ steps :
137+ - name : Download package
138+ uses : actions/download-artifact@v4
139+ with :
140+ name : extension-v${{ needs.validate.outputs.version }}
141+
142+ - name : Install vsce
143+ run : npm install -g @vscode/vsce
144+
145+ - name : Publish to marketplace
146+ id : publish
147+ continue-on-error : true
148+ env :
149+ VSC_PAT : ${{ secrets.VSC_PAT }}
150+ run : |
151+ VERSION="${{ needs.validate.outputs.version }}"
152+
153+ if [[ "${{ inputs.dry_run }}" == "true" ]]; then
154+ echo "✨ Dry run mode - simulating publish of v${VERSION}"
155+ echo "status=success" >> $GITHUB_OUTPUT
156+ echo "This is a dry run - skipping actual publish" >> $GITHUB_STEP_SUMMARY
157+ exit 0
158+ fi
110159
111- - name : Publish to Visual Studio Marketplace
112- run : vsce publish -p "${{ secrets.VSC_PAT }}"
160+ # Attempt to publish and capture output
161+ OUTPUT=$(vsce publish -p "$VSC_PAT" 2>&1)
162+ EXIT_CODE=$?
163+
164+ if [ $EXIT_CODE -eq 0 ]; then
165+ echo "status=success" >> $GITHUB_OUTPUT
166+ else
167+ # Check specific error cases
168+ if [[ "$OUTPUT" == *"already exists"* ]]; then
169+ echo "status=exists" >> $GITHUB_OUTPUT
170+ else
171+ echo "status=failed" >> $GITHUB_OUTPUT
172+ ERROR_DETAIL=$(echo "$OUTPUT" | grep -v "error" | tail -n 1)
173+ echo "error_detail=$ERROR_DETAIL" >> $GITHUB_OUTPUT
174+ fi
175+ fi
176+
177+ - name : Create and push Git tag
178+ if : steps.publish.outputs.status == 'success'
179+ run : |
180+ VERSION="${{ needs.validate.outputs.version }}"
181+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
182+ git config --global user.name "GitHub Actions"
183+ git tag -a "v${VERSION}" -m "Release v${VERSION}"
184+ git push origin "v${VERSION}"
185+
186+ # Wrote this to update the run-name dynamically based on the publish status, but it is not supported in GitHub Actions now.
187+ # We can post the new extension publish in linked or comment on the PR.
188+ # https://github.com/orgs/community/discussions/69476
189+ post-process :
190+ needs : [validate, publish]
191+ if : always()
192+ runs-on : ubuntu-latest
193+ name : ${{ needs.validate.outputs.should_publish == 'false'
194+ && format('{0} {1}',
195+ needs.validate.outputs.has_code_changes == 'true' && '⚠️' || 'ℹ️',
196+ needs.validate.outputs.skip_reason) || needs.publish.result == 'success'
197+ && needs.publish.outputs.status == 'success'
198+ && format('✅ Published v{0} successfully', needs.validate.outputs.version) || needs.publish.outputs.status == 'exists'
199+ && format('ℹ️ v{0} already exists', needs.validate.outputs.version) || format('❌ Failed to publish v{0}', needs.validate.outputs.version) }}
200+ steps :
201+ - name : Set status summary
202+ run : |
203+ VERSION="${{ needs.validate.outputs.version }}"
204+
205+ # Set step summary only
206+ if [[ "${{ needs.validate.outputs.should_publish }}" == "false" ]]; then
207+ if [[ "${{ needs.validate.outputs.has_code_changes }}" == "true" ]]; then
208+ echo "### ⚠️ Version update needed for code changes" >> $GITHUB_STEP_SUMMARY
209+ else
210+ echo "### ℹ️ Documentation update only" >> $GITHUB_STEP_SUMMARY
211+ fi
212+ echo "${{ needs.validate.outputs.skip_reason }}" >> $GITHUB_STEP_SUMMARY
213+ elif [[ "${{ needs.publish.result }}" == "success" ]]; then
214+ case "${{ needs.publish.outputs.status }}" in
215+ "success")
216+ echo "### ✅ Published v${VERSION} successfully" >> $GITHUB_STEP_SUMMARY
217+ echo "Extension successfully published to VS Code Marketplace" >> $GITHUB_STEP_SUMMARY
218+ ;;
219+ "exists")
220+ echo "### ℹ️ v${VERSION} already exists" >> $GITHUB_STEP_SUMMARY
221+ echo "Version already exists in VS Code Marketplace" >> $GITHUB_STEP_SUMMARY
222+ ;;
223+ *)
224+ echo "### ❌ Failed to publish v${VERSION}" >> $GITHUB_STEP_SUMMARY
225+ echo "${{ needs.publish.outputs.error_detail }}" >> $GITHUB_STEP_SUMMARY
226+ ;;
227+ esac
228+ else
229+ echo "### ❌ Failed to publish v${VERSION}" >> $GITHUB_STEP_SUMMARY
230+ echo "Workflow failed during publish stage" >> $GITHUB_STEP_SUMMARY
231+ fi
0 commit comments