Skip to content

Commit 4d9217d

Browse files
authored
qs-push-plugin.swift (#3081)
* CI and tooling rework for plugins Summary of changes: qs-push-plugin: - convert from ruby to Swift - the initial version in this commit was generated by chatgpt 5 pro on 20251022 using the historical ruby implementation of qs-push-plugin as input and the simple prompt `Convert the below Ruby script to a Swift script that only uses the stdlib.` - minor changes from the LLM output (e.g. dispatchGroup instead of semaphore) .github/workflows/ci.yml, Quicksilver/Tools/qsrelease, Quicksilver/Tools/qssign, Quicksilver/Tools/qstest: - some much needed maintenance as these have accumulated a little cruft in the last few years - `QS_BUILD_ONLY` removed as functionality was duplicated with QS_DONT_SIGN - `QS_DONT_SIGN` removed as we weren't automatically signing using `qsrelease` - signing happens via XCode if running interactively - previously CI was using `QS_DONT_SIGN` and manually calling `qssign` when appropriate - this change just makes the above more explicit by removing `qssign` from `qsrelease`, so `QS_DONT_SIGN` is no longer useful - added `QS_DONT_TEST` which allows us to skip testing in `qsrelease` - this can be helpful for example when building plugins, as the Quicksilver build is done from a tagged release (for which we can be confident tests have already been run) - alternatively could consider mirroring the `qssign` changes and just make `qstest` a manual thing - moved much of the signing logic from yaml to qssign - much easier to write and maintain with appropriate linters, formatters, highighting, etc. - removed calls to set up the self-signed cert, as this process is not useful or needed in CI Quicksilver/Quicksilver.xcodeproj/project.pbxproj: - set signing identity to ad-hoc (`-`) for the testing scheme - our current tests do not require special permissions, therefore do not require the special cert Quicksilver/Tools/utils.sh - new file to hold shell functions that are useful to share between our other scripts - should reduce duplicated code and help with readability and maintainability Quicksilver/Tools/build-qs-plugin: - new script to build a plugin - given that the QS frameworks are required to build a plugin, we already clone the QS source as part of building a plugin - therefore adding a script to the QS source lets us keep the bulk of the logic in one place - works in conjunction with the new <https://github.com/quicksilver/qs-plugin-action> - this lets us remove a *ton* of build logic from the CI scripts in each individual plugin repo; they can essentially be reduced to just passing in the required secrets and `use`ing the new action * Rename build-qs-plugin qs-build-plugin For consistency with other tooling
1 parent 9b376b2 commit 4d9217d

File tree

8 files changed

+759
-347
lines changed

8 files changed

+759
-347
lines changed

.github/workflows/ci.yml

Lines changed: 13 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,13 @@ on:
1414
jobs:
1515
build:
1616
runs-on: macos-latest
17-
env:
18-
QS_DONT_SIGN: 1
1917
steps:
2018
- uses: actions/checkout@v4
2119
with:
2220
submodules: recursive
2321
- name: Build debug version
2422
working-directory: Quicksilver
2523
run: |
26-
./Tools/codesign/setup_cert.sh
2724
./Tools/qsrelease Debug
2825
mv /tmp/QS/build/Debug/Quicksilver{,-debug}.zip
2926
- name: Upload debug version
@@ -37,12 +34,7 @@ jobs:
3734
./Tools/qsrelease
3835
- name: Prepare DMG_INGREDIENTS artifact
3936
working-directory: /tmp/QS/build/Release/
40-
run: |
41-
cp \
42-
/tmp/qs_build_settings \
43-
/tmp/Quicksilver.entitlements \
44-
./dmg/
45-
tar -czvf ./dmg_ingredients.tar.gz ./dmg
37+
run: tar -czvf ./dmg_ingredients.tar.gz ./dmg
4638
- name: Upload components for sign action
4739
uses: actions/upload-artifact@v4
4840
with:
@@ -53,16 +45,6 @@ jobs:
5345
needs: build
5446
runs-on: macos-latest
5547
if: startsWith(github.ref, 'refs/tags/v')
56-
env:
57-
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
58-
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
59-
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
60-
61-
SIGNING_IDENTITY: ${{ secrets.SIGNING_IDENTITY }}
62-
NOTARIZING_ID: ${{ secrets.NOTARIZING_ID }}
63-
NOTARIZING_PASS: ${{ secrets.NOTARIZING_PASS }}
64-
65-
KEYCHAIN_PROFILE: "Quicksilver Notarization"
6648
steps:
6749
- name: Download dmg folder artifact
6850
uses: actions/download-artifact@v4
@@ -77,37 +59,23 @@ jobs:
7759
./dmg/qs_build_settings \
7860
./dmg/Quicksilver.entitlements \
7961
/tmp/
80-
QS_INFO_VERSION=$(awk '/QS_INFO_VERSION/ { print $NF }' \
81-
/tmp/qs_build_settings)
62+
QS_INFO_VERSION=$(
63+
awk '/QS_INFO_VERSION/ { print $NF }' /tmp/qs_build_settings
64+
)
8265
echo "QS_INFO_VERSION=${QS_INFO_VERSION}" >> "${GITHUB_ENV}"
8366
- uses: actions/checkout@v4
8467
with:
8568
submodules: recursive
86-
- name: Run Tools/qssign
69+
- name: qssign
8770
working-directory: Quicksilver
71+
env:
72+
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
73+
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
74+
SIGNING_IDENTITY: ${{ secrets.SIGNING_IDENTITY }}
75+
NOTARIZING_ID: ${{ secrets.NOTARIZING_ID }}
76+
NOTARIZING_PASS: ${{ secrets.NOTARIZING_PASS }}
8877
run: |
89-
# https://docs.github.com/en/actions/deployment/deploying-xcode-applications/installing-an-apple-certificate-on-macos-runners-for-xcode-development
90-
KEYCHAIN_PATH=${RUNNER_TEMP}/app-signing.keychain-db
91-
CERTIFICATE_PATH=${RUNNER_TEMP}/build_certificate.p12
92-
base64 --decode --output "${CERTIFICATE_PATH}" <<<"${MACOS_CERTIFICATE}"
93-
trap "rm -rf -- '${RUNNER_TEMP}'" EXIT
94-
95-
security create-keychain -p "${KEYCHAIN_PASSWORD}" "${KEYCHAIN_PATH}"
96-
security default-keychain -s "${KEYCHAIN_PATH}"
97-
security set-keychain-settings -lut 21600 "${KEYCHAIN_PATH}"
98-
99-
security unlock-keychain -p "${KEYCHAIN_PASSWORD}" "${KEYCHAIN_PATH}"
100-
101-
security import "${CERTIFICATE_PATH}" \
102-
-P "${MACOS_CERTIFICATE_PASSWORD}" \
103-
-A -t cert -f pkcs12 -k "${KEYCHAIN_PATH}"
104-
rm -- "${CERTIFICATE_PATH}"
105-
xcrun notarytool store-credentials "${KEYCHAIN_PROFILE}" \
106-
--apple-id "${NOTARIZING_ID}" \
107-
--team-id "${SIGNING_IDENTITY}" \
108-
--password "${NOTARIZING_PASS}"
109-
110-
./Tools/qssign
78+
./Tools/qssign ./Quicksilver.app
11179
- name: Download debug artifact
11280
uses: actions/download-artifact@v4
11381
with:
@@ -135,4 +103,4 @@ jobs:
135103
files: |
136104
/tmp/QS/build/Release/Quicksilver*.dmg
137105
/tmp/QS/build/Release/checksum.txt
138-
/tmp/Quicksilver-debug.zip
106+
/tmp/Quicksilver-debug.zip

Quicksilver/Quicksilver.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6383,7 +6383,7 @@
63836383
ARCHS = "$(ARCHS_STANDARD)";
63846384
CLANG_ENABLE_OBJC_ARC = YES;
63856385
CODE_SIGN_ENTITLEMENTS = Quicksilver.entitlements;
6386-
CODE_SIGN_IDENTITY = "Local Self-Signed";
6386+
CODE_SIGN_IDENTITY = "-";
63876387
DEVELOPMENT_TEAM = "";
63886388
FRAMEWORK_SEARCH_PATHS = (
63896389
"$(inherited)",

Quicksilver/Tools/qs-build-plugin

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env bash
2+
3+
set -Eeuf -o pipefail
4+
5+
TOOLSDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
6+
readonly TOOLSDIR
7+
. "${TOOLSDIR}/utils.sh"
8+
9+
usage() {
10+
printf 'USAGE:
11+
CONFIGURATION=Release Tools/build-plugin /path/to/plugin
12+
'
13+
}
14+
15+
main() {
16+
local plugin_dir=${1:-}
17+
# Fail early if plugin directory doesn't exit
18+
if [[ ! -d "${plugin_dir}" ]]; then
19+
usage
20+
err "Plugin directory '${plugin_dir}' doesn't seem to exist"
21+
fi
22+
23+
export CONFIGURATION=${CONFIGURATION:-Debug}
24+
25+
# build quicksilver to provide necessary frameworks
26+
pushd "$(dirname "${BASH_SOURCE[0]}")"
27+
./qsrelease
28+
popd
29+
30+
pushd "${plugin_dir}"
31+
local project=$(find . -maxdepth 1 -name '*.xcodeproj' -not -iname "*test.xcodeproj" -print -quit)
32+
local scheme_list
33+
if [[ -z "${project}" ]]; then
34+
scheme_list=$(xcodebuild -list -json || true)
35+
else
36+
scheme_list=$(xcodebuild -list -json -project "${project}")
37+
fi
38+
39+
if [[ -z "${scheme_list}" ]]; then
40+
err "unable to determine scheme list"
41+
fi
42+
43+
local scheme=$(json '["project"]["targets"][0]' <<< "${scheme_list}")
44+
log "Using default scheme: ${scheme}"
45+
46+
# Absence of a project can still build, but will error if `-project` is specified
47+
local opts=(
48+
-configuration "${CONFIGURATION}"
49+
-scheme "${scheme}"
50+
-destination 'generic/platform=macos'
51+
)
52+
if [[ -n "${project}" ]]; then
53+
opts+=(-project "${project}")
54+
fi
55+
xcodebuild build -quiet "${opts[@]}"
56+
57+
local settings=$(xcodebuild -configuration "${CONFIGURATION}" -showBuildSettings -json)
58+
local plugin_name=$(json '[0]["buildSettings"]["FULL_PRODUCT_NAME"]' <<< "${settings}")
59+
local build_dir=$(json '[0]["buildSettings"]["BUILT_PRODUCTS_DIR"]' <<< "${settings}")
60+
local expected="${build_dir}/${plugin_name}"
61+
62+
if [[ -d "${expected}" ]]; then
63+
log "Plugin successfully built to ${expected}"
64+
else
65+
err "Did not find built plugin at ${expected}"
66+
fi
67+
}
68+
main "$@"

0 commit comments

Comments
 (0)