-
Notifications
You must be signed in to change notification settings - Fork 31
251 lines (215 loc) · 11.5 KB
/
Copy pathrelease.yml
File metadata and controls
251 lines (215 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
name: Release
on:
pull_request:
branches: [main]
types: [closed]
permissions:
contents: write
id-token: write
actions: read
jobs:
release:
if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'dev'
runs-on: windows-latest
steps:
- uses: actions/checkout@v5
- name: Get version
id: version
shell: pwsh
run: |
$version = ([xml](Get-Content src/Directory.Build.props)).Project.PropertyGroup.Version | Where-Object { $_ }
echo "VERSION=$version" >> $env:GITHUB_OUTPUT
- name: Check if release already exists
id: check
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if gh release view "v${{ steps.version.outputs.VERSION }}" > /dev/null 2>&1; then
echo "EXISTS=true" >> $GITHUB_OUTPUT
else
echo "EXISTS=false" >> $GITHUB_OUTPUT
fi
- name: Create release
if: steps.check.outputs.EXISTS == 'false'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "v${{ steps.version.outputs.VERSION }}" --title "v${{ steps.version.outputs.VERSION }}" --generate-notes --target main
- name: Setup .NET 10.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
- name: Build and test
run: |
dotnet restore
dotnet build -c Release
dotnet test tests/PlanViewer.Core.Tests/PlanViewer.Core.Tests.csproj -c Release --no-build --verbosity normal
- name: Publish App (all platforms)
run: |
dotnet publish src/PlanViewer.App/PlanViewer.App.csproj -c Release -r win-x64 --self-contained -o publish/win-x64
dotnet publish src/PlanViewer.App/PlanViewer.App.csproj -c Release -r linux-x64 --self-contained -o publish/linux-x64
dotnet publish src/PlanViewer.App/PlanViewer.App.csproj -c Release -r osx-x64 --self-contained -o publish/osx-x64
dotnet publish src/PlanViewer.App/PlanViewer.App.csproj -c Release -r osx-arm64 --self-contained -o publish/osx-arm64
# ── SSMS extension VSIX (issue 343 — get it into automated builds) ──
# PlanViewer.Ssms is a legacy non-SDK project and is not in PlanViewer.sln,
# so the `dotnet build` above never touches it. It needs full MSBuild plus
# the VSSDK build targets from the Microsoft.VSSDK.BuildTools package.
# The build step never fails the job (it only sets an output on success),
# so a VSIX build failure can never block the cross-platform app release.
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v2
continue-on-error: true
- name: Build SSMS extension
id: ssms
continue-on-error: true
shell: pwsh
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
$manifest = 'src/PlanViewer.Ssms/source.extension.vsixmanifest'
$manifestVersion = ([xml](Get-Content $manifest)).PackageManifest.Metadata.Identity.Version
if ($manifestVersion -ne $env:VERSION) {
Write-Host "::warning::VSIX manifest version ($manifestVersion) does not match release version ($env:VERSION) - bump source.extension.vsixmanifest and Properties/AssemblyInfo.cs"
}
# Use -restore (not the -t:Restore,Build target list) so the
# package-generated props land in a fresh evaluation before Build.
# Those props redirect VSToolsPath into the Microsoft.VSSDK.BuildTools
# package, which is how the VSSDK targets resolve on a runner that
# lacks the Visual Studio extension-development workload.
msbuild src/PlanViewer.Ssms/PlanViewer.Ssms.csproj -restore -t:Build -p:Configuration=Release -p:DeployExtension=false
dotnet build src/PlanViewer.Ssms.Installer/PlanViewer.Ssms.Installer.csproj -c Release
$vsix = 'src/PlanViewer.Ssms/bin/Release/PlanViewer.Ssms.vsix'
$exe = 'src/PlanViewer.Ssms.Installer/bin/Release/net472/InstallSsmsExtension.exe'
if ((Test-Path $vsix) -and (Test-Path $exe)) {
New-Item -ItemType Directory -Force -Path releases | Out-Null
Copy-Item $vsix 'releases/PlanViewer.Ssms.vsix'
Copy-Item $exe 'releases/InstallSsmsExtension.exe'
"BUILT=true" >> $env:GITHUB_OUTPUT
Write-Host "SSMS extension built: $vsix"
} else {
Write-Host "::warning::SSMS extension did not produce the expected artifacts - release published without the VSIX (issue 343)"
}
- name: Upload SSMS extension to release
if: steps.ssms.outputs.BUILT == 'true'
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.VERSION }}
run: gh release upload "v$env:VERSION" releases/PlanViewer.Ssms.vsix releases/InstallSsmsExtension.exe --clobber
# Publish to the SSMS Gallery (https://ssmsgallery.azurewebsites.net, issue 343).
# The gallery extracts version/description from the vsixmanifest, so the
# upload filename is irrelevant. continue-on-error: a gallery outage must
# never fail the release. bash so `curl` is curl.exe, not the pwsh alias.
- name: Publish SSMS extension to SSMS Gallery
if: steps.ssms.outputs.BUILT == 'true'
continue-on-error: true
shell: bash
run: |
echo "Uploading PlanViewer.Ssms.vsix to the SSMS Gallery..."
curl -sS -f "https://ssmsgallery.azurewebsites.net/api/upload" \
-F "file=@releases/PlanViewer.Ssms.vsix"
# ── SignPath code signing (Windows only, skipped if secret not configured) ──
- name: Check if signing is configured
id: signing
shell: bash
run: |
if [ -n "${{ secrets.SIGNPATH_API_TOKEN }}" ]; then
echo "ENABLED=true" >> $GITHUB_OUTPUT
else
echo "ENABLED=false" >> $GITHUB_OUTPUT
echo "::warning::SIGNPATH_API_TOKEN not configured — releasing unsigned binaries"
fi
- name: Upload Windows build for signing
if: steps.signing.outputs.ENABLED == 'true'
id: upload-unsigned
uses: actions/upload-artifact@v6
with:
name: App-unsigned
path: publish/win-x64/
- name: Sign Windows build
if: steps.signing.outputs.ENABLED == 'true'
uses: signpath/github-action-submit-signing-request@v2
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '7969f8b6-d946-4a74-9bac-a55856d8b8e0'
project-slug: 'PerformanceStudio'
signing-policy-slug: 'release-signing'
artifact-configuration-slug: 'App'
github-artifact-id: '${{ steps.upload-unsigned.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: 'signed/win-x64'
- name: Replace unsigned Windows build with signed
if: steps.signing.outputs.ENABLED == 'true'
shell: pwsh
run: |
Remove-Item -Recurse -Force publish/win-x64
Copy-Item -Recurse signed/win-x64 publish/win-x64
# ── Velopack (uses signed Windows binaries) ───────────────────────
- name: Create Velopack release (Windows)
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
dotnet tool install -g vpk
New-Item -ItemType Directory -Force -Path releases/velopack
# Download previous release for delta generation
vpk download github --repoUrl https://github.com/${{ github.repository }} --channel win -o releases/velopack --token $env:GH_TOKEN
# Pack Windows release (now signed)
vpk pack -u PerformanceStudio -v $env:VERSION -p publish/win-x64 -e PlanViewer.App.exe -o releases/velopack --channel win
# ── Package and upload ────────────────────────────────────────────
- name: Package and upload
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
New-Item -ItemType Directory -Force -Path releases
# Package Windows (signed) and Linux as flat zips
foreach ($rid in @('win-x64', 'linux-x64')) {
if (Test-Path 'README.md') { Copy-Item 'README.md' "publish/$rid/" }
if (Test-Path 'LICENSE') { Copy-Item 'LICENSE' "publish/$rid/" }
Compress-Archive -Path "publish/$rid/*" -DestinationPath "releases/PerformanceStudio-$rid.zip" -Force
}
# Package macOS as proper .app bundles
foreach ($rid in @('osx-x64', 'osx-arm64')) {
$appName = "PerformanceStudio.app"
$bundleDir = "publish/$rid-bundle/$appName"
# Create .app bundle structure
New-Item -ItemType Directory -Force -Path "$bundleDir/Contents/MacOS"
New-Item -ItemType Directory -Force -Path "$bundleDir/Contents/Resources"
# Copy all published files into Contents/MacOS
Copy-Item -Path "publish/$rid/*" -Destination "$bundleDir/Contents/MacOS/" -Recurse
# Move Info.plist to Contents/ (it was copied to MacOS/ with the publish output)
if (Test-Path "$bundleDir/Contents/MacOS/Info.plist") {
Move-Item -Path "$bundleDir/Contents/MacOS/Info.plist" -Destination "$bundleDir/Contents/Info.plist" -Force
}
# Update version in Info.plist to match csproj
$plist = Get-Content "$bundleDir/Contents/Info.plist" -Raw
$plist = $plist -replace '(<key>CFBundleVersion</key>\s*<string>)[^<]*(</string>)', "`${1}$env:VERSION`${2}"
$plist = $plist -replace '(<key>CFBundleShortVersionString</key>\s*<string>)[^<]*(</string>)', "`${1}$env:VERSION`${2}"
Set-Content -Path "$bundleDir/Contents/Info.plist" -Value $plist -NoNewline
# Move icon to Contents/Resources
if (Test-Path "$bundleDir/Contents/MacOS/EDD.icns") {
Move-Item -Path "$bundleDir/Contents/MacOS/EDD.icns" -Destination "$bundleDir/Contents/Resources/EDD.icns" -Force
}
# Add README and LICENSE alongside the .app bundle
$wrapperDir = "publish/$rid-bundle"
if (Test-Path 'README.md') { Copy-Item 'README.md' "$wrapperDir/" }
if (Test-Path 'LICENSE') { Copy-Item 'LICENSE' "$wrapperDir/" }
Compress-Archive -Path "$wrapperDir/*" -DestinationPath "releases/PerformanceStudio-$rid.zip" -Force
}
# Checksums (zips only, Velopack has its own checksums)
$checksums = Get-ChildItem releases/*.zip | ForEach-Object {
$hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower()
"$hash $($_.Name)"
}
$checksums | Out-File -FilePath releases/SHA256SUMS.txt -Encoding utf8
Write-Host "Checksums:"
$checksums | ForEach-Object { Write-Host $_ }
# Upload zips + checksums
gh release upload "v$env:VERSION" releases/*.zip releases/SHA256SUMS.txt --clobber
# Upload Velopack artifacts
vpk upload github --repoUrl https://github.com/${{ github.repository }} --channel win -o releases/velopack --releaseName "v$env:VERSION" --tag "v$env:VERSION" --merge --token $env:GH_TOKEN