1 name: winget Release
2
3 # Dispatched by release-github.yml once the release and its checksums exist.
4 #
5 # winget manifests live in microsoft/winget-pkgs, and `wingetcreate update`
6 # only works on a package that is already there. So this workflow branches:
7 #
8 # - package already in winget-pkgs -> `wingetcreate update`, which rewrites
9 # the URLs and re-hashes the installers for us.
10 # - package not there yet -> render the manifests in packaging/winget/ and
11 # `wingetcreate submit` them as a new package.
12 #
13 # The second path only runs once, but keeping it here means a first release
14 # does not need someone to sit at a Windows box running `wingetcreate new`
15 # interactively.
16 on:
17 workflow_dispatch:
18 inputs:
19 tag:
20 description: "Release tag (e.g. v1.5.2)"
21 required: true
22
23 permissions:
24 contents: read
25
26 env:
27 REPO: getsigit/sigit
28 PACKAGE_IDENTIFIER: getSigit.siGitCode
29
30 jobs:
31 submit-winget-manifest:
32 name: Submit winget manifest
33 # wingetcreate is a Windows-only tool.
34 runs-on: windows-latest
35
36 steps:
37 - name: Check out repository
38 uses: actions/checkout@v6
39
40 - name: Resolve tag, version and release date
41 id: release
42 shell: bash
43 env:
44 GH_TOKEN: ${{ github.token }}
45 run: |
46 TAG="${{ github.event.inputs.tag }}"
47 VERSION="${TAG#v}"
48 # wingetcreate wants ReleaseDate as YYYY-MM-DD.
49 DATE=$(gh release view "$TAG" --repo "$REPO" --json publishedAt --jq '.publishedAt[0:10]')
50
51 echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
52 echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
53 echo "date=${DATE}" >> "$GITHUB_OUTPUT"
54
55 - name: Check whether the package is already in winget-pkgs
56 id: exists
57 shell: bash
58 env:
59 GH_TOKEN: ${{ github.token }}
60 run: |
61 # manifests are filed under the lowercased first letter of the
62 # publisher, e.g. manifests/g/getSigit/siGitCode.
63 PUBLISHER="${PACKAGE_IDENTIFIER%%.*}"
64 NAME="${PACKAGE_IDENTIFIER#*.}"
65 FIRST=$(echo "${PUBLISHER:0:1}" | tr '[:upper:]' '[:lower:]')
66 PATH_IN_REPO="manifests/${FIRST}/${PUBLISHER}/${NAME}"
67
68 if gh api "repos/microsoft/winget-pkgs/contents/${PATH_IN_REPO}" >/dev/null 2>&1; then
69 echo "Found ${PACKAGE_IDENTIFIER} at ${PATH_IN_REPO}; submitting an update."
70 echo "found=true" >> "$GITHUB_OUTPUT"
71 else
72 echo "No ${PACKAGE_IDENTIFIER} at ${PATH_IN_REPO}; submitting it as a new package."
73 echo "found=false" >> "$GITHUB_OUTPUT"
74 fi
75
76 - name: Render manifests for a first submission
77 if: steps.exists.outputs.found == 'false'
78 shell: bash
79 env:
80 GH_TOKEN: ${{ github.token }}
81 run: |
82 TAG="${{ steps.release.outputs.tag }}"
83 VERSION="${{ steps.release.outputs.version }}"
84
85 mkdir -p artifacts manifests
86
87 gh release download "$TAG" \
88 --repo "$REPO" \
89 --pattern "sigit-win-*.exe.sha256" \
90 --dir artifacts/
91
92 # The schema wants 64 hex characters; the community validation
93 # pipeline writes them uppercase, so match that.
94 SHA_AMD64=$(tr -d '[:space:]' < artifacts/sigit-win-amd64.exe.sha256 | tr '[:lower:]' '[:upper:]')
95 SHA_ARM64=$(tr -d '[:space:]' < artifacts/sigit-win-arm64.exe.sha256 | tr '[:lower:]' '[:upper:]')
96
97 RELEASE_DATE="${{ steps.release.outputs.date }}"
98
99 for template in packaging/winget/*.yaml.in; do
100 out="manifests/$(basename "$template" .in)"
101 sed \
102 -e "s|@VERSION@|${VERSION}|g" \
103 -e "s|@TAG@|${TAG}|g" \
104 -e "s|@REPO@|${REPO}|g" \
105 -e "s|@SHA_AMD64@|${SHA_AMD64}|g" \
106 -e "s|@SHA_ARM64@|${SHA_ARM64}|g" \
107 -e "s|@RELEASE_DATE@|${RELEASE_DATE}|g" \
108 "$template" > "$out"
109
110 echo "--- ${out} ---"
111 cat "$out"
112 done
113
114 - name: Download wingetcreate
115 shell: pwsh
116 run: Invoke-WebRequest -Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe
117
118 - name: Submit new package
119 if: steps.exists.outputs.found == 'false'
120 shell: pwsh
121 env:
122 # wingetcreate reads the token from this variable. Passing it as
123 # --token instead makes the tool warn that the token can end up in
124 # logs, which on a shared runner is not a warning worth ignoring.
125 WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_TOKEN }}
126 run: |
127 if (-not $env:WINGET_CREATE_GITHUB_TOKEN) {
128 Write-Error "WINGET_TOKEN is not set. It needs a PAT with public_repo scope so wingetcreate can fork microsoft/winget-pkgs and open the manifest PR."
129 }
130
131 $version = "${{ steps.release.outputs.version }}"
132
133 # --no-open because the runner has no browser to open the PR in.
134 .\wingetcreate.exe submit manifests `
135 --prtitle "New package: $env:PACKAGE_IDENTIFIER version $version" `
136 --no-open
137
138 if ($LASTEXITCODE -ne 0) {
139 Write-Error "wingetcreate submit failed with exit code $LASTEXITCODE"
140 }
141
142 - name: Submit manifest update
143 if: steps.exists.outputs.found == 'true'
144 shell: pwsh
145 env:
146 WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_TOKEN }}
147 run: |
148 if (-not $env:WINGET_CREATE_GITHUB_TOKEN) {
149 Write-Error "WINGET_TOKEN is not set. It needs a PAT with public_repo scope so wingetcreate can fork microsoft/winget-pkgs and open the manifest PR."
150 }
151
152 $tag = "${{ steps.release.outputs.tag }}"
153 $version = "${{ steps.release.outputs.version }}"
154 $base = "https://github.com/${env:REPO}/releases/download/$tag"
155
156 # The trailing |x64 and |arm64 tell wingetcreate which installer
157 # entry each URL replaces. Without them it guesses from the file
158 # name, and "sigit-win-amd64.exe" is not a spelling it recognises.
159 .\wingetcreate.exe update $env:PACKAGE_IDENTIFIER `
160 --version $version `
161 --urls "$base/sigit-win-amd64.exe|x64" "$base/sigit-win-arm64.exe|arm64" `
162 --release-notes-url "https://github.com/${env:REPO}/releases/tag/$tag" `
163 --release-date "${{ steps.release.outputs.date }}" `
164 --prtitle "Update $env:PACKAGE_IDENTIFIER to version $version" `
165 --submit `
166 --no-open
167
168 if ($LASTEXITCODE -ne 0) {
169 Write-Error "wingetcreate failed with exit code $LASTEXITCODE"
170 }