-
Notifications
You must be signed in to change notification settings - Fork 0
307 lines (269 loc) · 12.7 KB
/
Copy pathrelease.yml
File metadata and controls
307 lines (269 loc) · 12.7 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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
name: release gdextension
# workflow_dispatch のみ。
# 既定 (upload_release=false) はビルドのみ (release/X.Y ブランチ上の QA 用)。
# Release の作成は v* タグ ref 上で upload_release=true を付けた明示的な
# dispatch のみ。
on:
workflow_dispatch:
inputs:
godot_version:
required: true
type: choice
options:
- "4.7"
default: "4.7"
description: "Target Godot API version"
upload_release:
# 既定でビルドのみ行い、true を指定した場合だけ Release を作成する
# (v* タグの ref 上で実行したときのみ有効)。
description: 'Upload to GitHub Release (only effective on a v* tag ref)'
required: false
default: false
type: boolean
env:
GODOT_VERSION: ${{ inputs.godot_version || '4.7' }}
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
PYTHONIOENCODING: utf8
KEYCHAIN_PATH: app-signing.keychain-db
SCONS_CACHE: ~/.scons_cache
# Least-privilege default token; the package job below elevates to
# contents: write only to publish the GitHub Release.
permissions:
contents: read
concurrency:
group: ci-scons-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
cancel-in-progress: true
jobs:
gdextension:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: 🐧 Linux (GCC)
os: ubuntu-latest
platform: linux
- name: 🏁 Windows (x86_64, MSVC)
os: windows-latest
platform: windows
- name: 🍎 macOS (universal)
os: macos-latest
platform: macos
- name: 🤖 Android (arm64)
os: ubuntu-latest
platform: android
- name: 🍏 iOS (arm64)
os: macos-latest
platform: ios
- name: 🌐 Web (wasm32)
os: ubuntu-latest
platform: web
defaults:
run:
shell: zsh {0}
steps:
- name: Checkout
uses: actions/checkout@v7
with:
submodules: recursive
- name: clone Godot Cpp repository
uses: GuillaumeFalourd/clone-github-repo-action@19817562c346ff60f9935158dede6c5ece8fd0ac # v2.3
with:
depth: 1
branch: master
owner: 'godotengine'
repository: 'godot-cpp'
# Fetch the prebuilt SDK runtime (headers + static libs) that the
# GDExtension build links against. Requires the SpriteStudio-SDK release
# assets to be downloadable from GitHub Releases.
- name: Download Prebuilt SDK (ssruntime)
if: matrix.platform != 'windows'
run: ./scripts/download-sdk.sh
- name: Download Prebuilt SDK (ssruntime, Windows)
if: matrix.platform == 'windows'
shell: pwsh
run: ./scripts/download-sdk.ps1
- name: setup for gdextension
uses: ./.github/actions/setup-extension
with:
platform: ${{ matrix.platform }}
os: ${{ matrix.os }}
- name: Setup SCons Cache
uses: actions/cache@v3
with:
path: ~/.scons_cache
key: ${{ runner.os }}-${{ matrix.platform }}-scons-${{ github.sha }}
restore-keys: |
${{ runner.os }}-${{ matrix.platform }}-scons-
# Import the Developer ID Application certificate into an ephemeral keychain
# so codesign (run inside the release scripts) can resolve the signing
# identity. No-ops when the certificate secret is absent, leaving the
# artifacts unsigned.
- name: Set up signing keychain
if: matrix.platform == 'macos' || matrix.platform == 'ios'
env:
APPLE_DEV_ID_APP_CERT: ${{ secrets.APPLE_DEV_ID_APP_CERT }}
APPLE_DEV_ID_APP_CERT_PASS: ${{ secrets.APPLE_DEV_ID_APP_CERT_PASS }}
run: |
if [ -z "$APPLE_DEV_ID_APP_CERT" ]; then
echo "APPLE_DEV_ID_APP_CERT not set — skipping keychain setup (artifacts will be unsigned)."
exit 0
fi
CERTIFICATE_PATH="$RUNNER_TEMP/build_certificate.p12"
# Random per-run password for the throwaway keychain; never persisted.
# (The org also holds a TMP_KC_PASS secret, deliberately unused here —
# generating the password per run is strictly better than sharing one.)
KEYCHAIN_PASSWORD="$(openssl rand -base64 24)"
echo -n "$APPLE_DEV_ID_APP_CERT" | base64 --decode > "$CERTIFICATE_PATH"
# Create, harden and unlock a temporary keychain.
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
# Import the cert and authorize codesign to use its private key.
security import "$CERTIFICATE_PATH" -P "$APPLE_DEV_ID_APP_CERT_PASS" -f pkcs12 -k "$KEYCHAIN_PATH" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
# Put the keychain on the search list so codesign resolves the identity
# (keep login.keychain-db so other tooling still works).
security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain-db
rm -f "$CERTIFICATE_PATH"
# Decode the App Store Connect API key (.p8) used to notarize the macOS
# frameworks and expose its path to the macOS build step. No-ops when the
# secret is absent. macOS only (iOS is not notarized).
- name: Prepare Apple API key
if: matrix.platform == 'macos'
env:
ASC_API_KEY_PASS: ${{ secrets.ASC_API_KEY_PASS }}
run: |
if [ -z "$ASC_API_KEY_PASS" ]; then
echo "ASC_API_KEY_PASS not set — skipping API key setup (frameworks will not be notarized)."
exit 0
fi
echo "$ASC_API_KEY_PASS" | base64 --decode > "$RUNNER_TEMP/apple_api_key.p8"
echo "APPLE_API_KEY_PATH=$RUNNER_TEMP/apple_api_key.p8" >> "$GITHUB_ENV"
- name: build Linux
if: matrix.platform == 'linux'
run: |
./scripts/release-gdextension-linux.sh api_version=${{ env.GODOT_VERSION }}
# release-gdextension-macos.sh signs the frameworks (hardened runtime +
# timestamp) when APPLE_SIGNING_IDENTITY is present, and notarizes them
# when the APPLE_API_* App Store Connect credentials are also present.
# APPLE_API_KEY_PATH is set by the "Prepare Apple API key" step above.
- name: build macOS
if: matrix.platform == 'macos'
env:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_DEV_ID_APP_NAME }}
APPLE_API_ISSUER: ${{ secrets.ASC_API_ISSUER_ID }}
APPLE_API_KEY: ${{ secrets.ASC_API_KEY_ID }}
run: |
./scripts/release-gdextension-macos.sh api_version=${{ env.GODOT_VERSION }}
# release-gdextension-ios.sh signs the XCFrameworks inside-out (no hardened
# runtime; iOS is not notarized) when APPLE_SIGNING_IDENTITY is present.
- name: build iOS
if: matrix.platform == 'ios'
env:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_DEV_ID_APP_NAME }}
run: |
./scripts/release-gdextension-ios.sh api_version=${{ env.GODOT_VERSION }}
- name: build Android
if: matrix.platform == 'android'
run: |
./scripts/release-gdextension-android.sh api_version=${{ env.GODOT_VERSION }}
- name: build Windows
if: matrix.platform == 'windows'
shell: pwsh
# The script drops the .exp / .lib link residue itself, so a local run
# leaves bin/windows looking exactly like a release.
run: ./scripts/release-gdextension-windows.ps1 api_version=${{ env.GODOT_VERSION }}
- name: build Web
if: matrix.platform == 'web'
run: |
./scripts/release-gdextension-web.sh api_version=${{ env.GODOT_VERSION }}
# Stage the runtime third-party license files (produced by the SDK
# download step) into the uploaded artifact so the packaging job can
# bundle them into the release zip, as required by the licenses of the
# statically-linked Rust crates. shell: bash so the Windows runner works.
- name: Stage third-party license files
shell: bash
run: |
mkdir -p bin/licenses
cp ss_player/runtime/THIRD-PARTY-LICENSES.ssruntime.md bin/licenses/
cp ss_player/runtime/THIRD-PARTY-LICENSES.ssconverter.md bin/licenses/
cp ss_player/runtime/LICENSE.md bin/licenses/runtime-LICENSE.md
# No commit hash in the name: these are consumed by the package job in the
# same run, where the platform already makes them unique, and a name the
# packaging step has to be told the hash of is a name it cannot resolve on
# its own. scripts/build-release.sh reads them by platform.
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: extension-${{ env.GODOT_VERSION }}-${{ matrix.platform }}
path: bin/
if-no-files-found: error
# A week, not the 90-day default: this is the matrix's handoff to the
# package job, not something to keep. See the same setting there.
retention-days: 7
package:
needs: gdextension
runs-on: ubuntu-latest
# Needs write access to publish the GitHub Release (softprops/action-gh-release).
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- name: Download all artifacts
uses: actions/download-artifact@v8
with:
path: artifacts
# scripts/build-release.sh IS the release package: the addons/spritestudio
# folder a user drops into a project — the descriptor, the icons it points
# at, every licence the shipped binaries carry, and bin/<platform>/ for all
# six — then the zip and SHA256SUMS. Every option is spelled out so a
# release cannot change because a default did, and so this is the command a
# human runs locally, after `gh run download <this run> -D artifacts`, to
# reproduce this exact archive without rebuilding six platforms.
#
# Its check is the one nothing else does: spritestudio.gdextension names a
# file per platform and build target, Godot resolves them at load time, and
# a name that does not match what shipped fails silently on that platform.
# Every path in it is looked up inside the finished zip.
- name: Build the release
run: ./scripts/build-release.sh in=artifacts out=release-dist api_version=${{ env.GODOT_VERSION }} verify=yes clean=yes
- name: Upload final release package
uses: actions/upload-artifact@v7
with:
name: ssplayer-godot-release-dist-${{ env.GODOT_VERSION }}
path: release-dist
if-no-files-found: error
# A week, not the 90-day default. What is meant to last is attached to
# the GitHub Release, which never expires; this is a copy for a run
# that uploaded nothing. Artifact storage is an org-wide quota, and a
# full one does not degrade — `upload-artifact` fails, so the release
# build fails, in a step that has nothing to do with the release.
retention-days: 7
# A release is a tag that was pushed first and dispatched from second, so
# asking to upload from anything else is an operator error, not a mode.
# Failing beats the silent skip this used to do: a dispatch meant to cut a
# release should not report success and quietly produce no Release. Leave
# upload_release=false to build the extension off a branch.
- name: Refuse to release from a non-tag ref
if: inputs.upload_release && !startsWith(github.ref, 'refs/tags/v')
run: |
echo "::error::upload_release=true needs a v* tag. Push the tag first, then dispatch this workflow from it (Use workflow from → the tag)."
exit 1
- name: Create GitHub Release
if: inputs.upload_release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
with:
files: |
release-dist/*.zip
release-dist/SHA256SUMS
tag_name: ${{ github.ref_name }}
generate_release_notes: true
# 常に draft として作成する。アセットと自動生成リリースノートが揃った
# 状態を人間が確認し、GitHub UI から公開する。「Set as a pre-release」
# 「Set as the latest release」も公開時に UI で選ぶ。
# ここで prerelease / make_latest を指定しないのは意図的:
# GitHub は draft を latest にできない仕様のため、指定しても効かない。
draft: true