-
Notifications
You must be signed in to change notification settings - Fork 32
238 lines (213 loc) · 10.1 KB
/
Copy pathrelease.yml
File metadata and controls
238 lines (213 loc) · 10.1 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
name: Release Aetherphone
on:
push:
tags:
- 'v*.*.*'
# Manual fallback: when auto-tag pushes a tag via GITHUB_TOKEN, GitHub
# sometimes refuses to cascade-trigger this workflow. Dispatch on the tag
# ref to publish the release without having to delete and re-push the tag.
workflow_dispatch:
inputs:
tag:
description: 'Tag to release (e.g. v1.0.0.0). Defaults to the ref this is dispatched on.'
required: false
type: string
permissions:
contents: write
jobs:
release:
runs-on: windows-latest
# Job-level so the hub-ping step's `if` can see it; `secrets` can't be used
# directly in an `if:` condition, but `env` mapped from a secret can.
env:
HUB_REPO_PAT: ${{ secrets.HUB_REPO_PAT }}
steps:
- name: Resolve target tag
id: tag
shell: bash
run: |
ref_name="${{ github.ref_name }}"
input_tag="${{ inputs.tag }}"
if [ -n "$input_tag" ]; then
target="$input_tag"
else
target="$ref_name"
fi
if [[ ! "$target" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
echo "::error::Resolved target '$target' is not a v*.*.* tag; pass the tag input or dispatch on a tag ref."
exit 1
fi
echo "target=$target" >> "$GITHUB_OUTPUT"
echo "version=${target#v}" >> "$GITHUB_OUTPUT"
echo "Releasing $target"
- name: Checkout
uses: actions/checkout@v7
with:
ref: ${{ steps.tag.outputs.target }}
fetch-depth: 0
# PAT so the repo.json bump below can land on the protected default
# branch: master requires the Guards and Build (Windows) checks, which
# a freshly pushed commit cannot have yet, and github-actions[bot] gets
# no bypass. The PAT owner is an admin and enforce_admins is off.
token: ${{ secrets.HUB_REPO_PAT || secrets.GITHUB_TOKEN }}
- name: Set up .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'
- name: Download Dalamud
shell: pwsh
run: |
$dalamudUrl = "https://goatcorp.github.io/dalamud-distrib/latest.zip"
$dalamudDir = "$env:AppData\XIVLauncher\addon\Hooks\dev"
New-Item -ItemType Directory -Force -Path $dalamudDir | Out-Null
Invoke-WebRequest -Uri $dalamudUrl -OutFile dalamud.zip
Expand-Archive -Path dalamud.zip -DestinationPath $dalamudDir -Force
Remove-Item dalamud.zip
- name: Restore (locked)
run: dotnet restore Aetherphone.sln --locked-mode
- name: Build (Release)
run: dotnet build Aetherphone.sln --configuration Release --no-restore
- name: Stage latest.zip
shell: pwsh
run: |
$src = 'src/Aetherphone/bin/Release/Aetherphone/latest.zip'
if (-not (Test-Path $src)) { throw "SDK-built plugin zip not found at $src" }
Copy-Item $src 'latest.zip' -Force
- name: Create GitHub Release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
tag_name: ${{ steps.tag.outputs.target }}
name: ${{ steps.tag.outputs.target }}
files: latest.zip
generate_release_notes: true
fail_on_unmatched_files: true
- name: Fetch total download count
id: count
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
total=$(gh api "repos/${{ github.repository }}/releases" --paginate \
--jq '[.[].assets[].download_count] | add // 0')
echo "total=$total" >> "$GITHUB_OUTPUT"
echo "Total downloads across all releases: $total"
- name: Announce the release on Discord
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
WEBHOOK_URL: ${{ secrets.RELEASE_WEBHOOK_URL }}
PING_ROLE_ID: ${{ vars.RELEASE_PING_ROLE_ID }}
TAG: ${{ steps.tag.outputs.target }}
DOWNLOADS: ${{ steps.count.outputs.total }}
run: |
$ErrorActionPreference = 'Stop'
if ([string]::IsNullOrWhiteSpace($env:WEBHOOK_URL)) {
Write-Host 'RELEASE_WEBHOOK_URL not set; skipping the announcement.'
exit 0
}
$icon = 'https://raw.githubusercontent.com/XeldarAlz/FFXIV-Aetherphone/master/src/Aetherphone/Images/Icon.png'
$relList = "https://github.com/$($env:GH_REPO)/releases"
$rel = gh release view $env:TAG --json name,tagName,body,url,isPrerelease,publishedAt | ConvertFrom-Json
$title = if ([string]::IsNullOrEmpty($rel.name)) { $rel.tagName } else { $rel.name }
$desc = if ($null -eq $rel.body) { '' } else { [string]$rel.body }
$desc = $desc.Replace("`r", '').Replace([char]0x2014, '-').Replace([char]0x2013, '-')
if ($desc.Length -gt 3800) { $desc = $desc.Substring(0, 3800) + "`n`n...full notes on GitHub" }
$isPre = [bool]$rel.isPrerelease
$content = if ($isPre) { '🧪 **New preview build just dropped!**' } else { '🚀 **New version dropped!**' }
$pingRole = $env:PING_ROLE_ID
if (-not [string]::IsNullOrWhiteSpace($pingRole)) {
$content = "<@&$pingRole> $content"
}
$color = if ($isPre) { 10197915 } else { 9132790 }
$channel = if ($isPre) { 'Preview' } else { 'Stable' }
$fields = @(
[ordered]@{ name = 'Version'; value = '`' + $rel.tagName + '`'; inline = $true }
[ordered]@{ name = 'Channel'; value = $channel; inline = $true }
)
if (-not [string]::IsNullOrWhiteSpace($env:DOWNLOADS)) {
$fields += [ordered]@{ name = 'Total installs'; value = "$($env:DOWNLOADS)"; inline = $true }
}
$payload = [ordered]@{
username = 'Aetherphone'
avatar_url = $icon
content = $content
embeds = @(
[ordered]@{
author = [ordered]@{ name = 'Aetherphone'; url = $relList; icon_url = $icon }
title = $title
url = $rel.url
description = $desc
color = $color
fields = $fields
thumbnail = [ordered]@{ url = $icon }
footer = [ordered]@{ text = 'Aetherphone'; icon_url = $icon }
timestamp = $rel.publishedAt
}
)
}
if (-not [string]::IsNullOrWhiteSpace($pingRole)) {
$payload['allowed_mentions'] = [ordered]@{ roles = @($pingRole) }
}
$json = $payload | ConvertTo-Json -Depth 10
if ($json.Contains([char]0x2014) -or $json.Contains([char]0x2013)) { throw 'Em/en dash detected in payload' }
$bytes = [System.Text.Encoding]::UTF8.GetBytes($json)
$resp = Invoke-WebRequest -Uri $env:WEBHOOK_URL -Method Post -Body $bytes -ContentType 'application/json; charset=utf-8' -UseBasicParsing
Write-Host "Discord responded: $($resp.StatusCode) $($resp.StatusDescription) for $($env:TAG)"
- name: Update local repo.json
shell: pwsh
run: |
$v = '${{ steps.tag.outputs.version }}'
$path = 'repo.json'
$json = Get-Content -Raw -Path $path | ConvertFrom-Json
$json[0].AssemblyVersion = $v
$json[0].TestingAssemblyVersion = $v
$json[0].DownloadCount = [int]'${{ steps.count.outputs.total }}'
$json[0] | Add-Member -NotePropertyName 'LastUpdate' -NotePropertyValue ([string][int][double]::Parse((Get-Date -UFormat %s))) -Force
# -AsArray preserves the array wrapper; piping a single-element array through | unrolls it and loses the [ ... ] Dalamud requires.
ConvertTo-Json -InputObject $json -Depth 10 -AsArray | Set-Content -Path $path -Encoding utf8
- name: Commit local repo.json
shell: pwsh
run: |
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
git add repo.json
if (-not (git status --porcelain)) {
Write-Host 'No changes to commit.'
exit 0
}
git commit -m "Release ${{ steps.tag.outputs.target }}: bump repo.json"
# -X theirs auto-resolves any repo.json conflict in favour of our just-bumped values
# (rebase semantics: "theirs" = the commits being rebased, i.e. ours).
# Without it, a concurrent push that touched repo.json leaves conflict markers,
# push then reports "Everything up-to-date" with exit 0, and downstream steps
# silently consume the corrupted file.
for ($i = 1; $i -le 5; $i++) {
git fetch origin master
git rebase -X theirs origin/master
if ($LASTEXITCODE -ne 0) {
git rebase --abort 2>$null
Write-Host "Rebase failed (attempt $i); retrying..."
Start-Sleep -Seconds 2
continue
}
git push origin HEAD:master
if ($LASTEXITCODE -eq 0) { exit 0 }
Write-Host "Push rejected (attempt $i); retrying after rebase..."
Start-Sleep -Seconds 2
}
Write-Error 'Failed to push repo.json bump after 5 attempts.'
exit 1
# Ping the multi-plugin hub repo so it regenerates repo.json immediately
# instead of waiting for its hourly cron. The hub workflow re-reads each
# plugin's repo.json and refreshes DownloadCount from the GitHub API.
- name: Trigger hub repo regeneration
if: ${{ env.HUB_REPO_PAT != '' }}
shell: bash
run: |
curl -fsSL -X POST \
-H "Authorization: Bearer $HUB_REPO_PAT" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/XeldarAlz/DalamudPlugins/dispatches \
-d '{"event_type":"plugin-released","client_payload":{"plugin":"${{ github.event.repository.name }}","version":"${{ steps.tag.outputs.version }}"}}'