Skip to content

Commit c3b47e1

Browse files
committed
refactor: enhance publish workflow with improved change detection and version handling
1 parent e6aa084 commit c3b47e1

1 file changed

Lines changed: 198 additions & 79 deletions

File tree

.github/workflows/publish.yml

Lines changed: 198 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,231 @@
11
name: 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

34
on:
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

1115
jobs:
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

Comments
 (0)