mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 14:43:55 +08:00
Build, codesign, and notarize macOS packages in CI
This adds a new workflow and script to build macOS packages in GitHub CI. It also adds some documentation for the process.
This commit is contained in:
parent
e67ffc1a3b
commit
96c5139254
35
.github/workflows/mac_codesign.yml
vendored
Normal file
35
.github/workflows/mac_codesign.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
name: macOS build and codesign
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # Enables manual trigger from GitHub UI
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-code-sign:
|
||||||
|
runs-on: macos-latest
|
||||||
|
environment: macos-codesign
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@1.79
|
||||||
|
- name: build-and-codesign
|
||||||
|
run: |
|
||||||
|
cargo install apple-codesign
|
||||||
|
mkdir -p "$FISH_ARTEFACT_PATH"
|
||||||
|
echo "$MAC_CODESIGN_APP_P12_BASE64" | base64 --decode > /tmp/app.p12
|
||||||
|
echo "$MAC_CODESIGN_INSTALLER_P12_BASE64" | base64 --decode > /tmp/installer.p12
|
||||||
|
echo "$MACOS_NOTARIZE_JSON" > /tmp/notarize.json
|
||||||
|
./build_tools/make_pkg.sh -s -f /tmp/app.p12 -i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" -n -j /tmp/notarize.json
|
||||||
|
rm /tmp/installer.p12 /tmp/app.p12 /tmp/notarize.json
|
||||||
|
env:
|
||||||
|
MAC_CODESIGN_APP_P12_BASE64: ${{ secrets.MAC_CODESIGN_APP_P12_BASE64 }}
|
||||||
|
MAC_CODESIGN_INSTALLER_P12_BASE64: ${{ secrets.MAC_CODESIGN_INSTALLER_P12_BASE64 }}
|
||||||
|
MAC_CODESIGN_PASSWORD: ${{ secrets.MAC_CODESIGN_PASSWORD }}
|
||||||
|
MACOS_NOTARIZE_JSON: ${{ secrets.MACOS_NOTARIZE_JSON }}
|
||||||
|
# macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead
|
||||||
|
# of crates.io, so give this a try. It's also sometimes significantly faster on all platforms.
|
||||||
|
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||||
|
FISH_ARTEFACT_PATH: /tmp/fish-built
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: macOS Artefacts
|
||||||
|
path: /tmp/fish-built/*
|
||||||
|
if-no-files-found: error
|
|
@ -2,6 +2,48 @@
|
||||||
|
|
||||||
# Script to produce an OS X installer .pkg and .app(.zip)
|
# Script to produce an OS X installer .pkg and .app(.zip)
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Build macOS packages, optionally signing and notarizing them."
|
||||||
|
echo "Usage: $0 options"
|
||||||
|
echo "Options:"
|
||||||
|
echo " -s Enables code signing"
|
||||||
|
echo " -f <APP_KEY.p12> Path to .p12 file for application signing"
|
||||||
|
echo " -i <INSTALLER_KEY.p12> Path to .p12 file for installer signing"
|
||||||
|
echo " -p <PASSWORD> Password for the .p12 files (necessary to access the certificates)"
|
||||||
|
echo " -e <entitlements file> (Optional) Path to an entitlements XML file"
|
||||||
|
echo " -n Enables notarization. This will fail if code signing is not also enabled."
|
||||||
|
echo " -j <API_KEY.JSON> Path to JSON file generated with `rcodesign encode-app-store-connect-api-key` (required for notarization)"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
set -x
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SIGN=
|
||||||
|
NOTARIZE=
|
||||||
|
|
||||||
|
while getopts "sf:i:p:e:nj:" opt; do
|
||||||
|
case $opt in
|
||||||
|
s) SIGN=1;;
|
||||||
|
f) P12_APP_FILE=$(realpath "$OPTARG");;
|
||||||
|
i) P12_INSTALL_FILE=$(realpath "$OPTARG");;
|
||||||
|
p) P12_PASSWORD="$OPTARG";;
|
||||||
|
e) ENTITLEMENTS_FILE=$(realpath "$OPTARG");;
|
||||||
|
n) NOTARIZE=1;;
|
||||||
|
j) API_KEY_FILE=$(realpath "$OPTARG");;
|
||||||
|
\?) usage;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$SIGN" ] && ([ -z "$P12_APP_FILE" ] || [-z "$P12_INSTALL_FILE"] || [ -z "$P12_PASSWORD" ]); then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$NOTARIZE" ] && [ -z "$API_KEY_FILE" ]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
VERSION=$(git describe --always --dirty 2>/dev/null)
|
VERSION=$(git describe --always --dirty 2>/dev/null)
|
||||||
if test -z "$VERSION" ; then
|
if test -z "$VERSION" ; then
|
||||||
echo "Could not get version from git"
|
echo "Could not get version from git"
|
||||||
|
@ -12,16 +54,8 @@ fi
|
||||||
|
|
||||||
echo "Version is $VERSION"
|
echo "Version is $VERSION"
|
||||||
|
|
||||||
set -x
|
|
||||||
|
|
||||||
#Exit on error
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Respect MAC_CODESIGN_ID, or default for ad-hoc.
|
|
||||||
# Note the :- means "or default" and the following - is the value.
|
|
||||||
MAC_CODESIGN_ID=${MAC_CODESIGN_ID:--}
|
|
||||||
|
|
||||||
PKGDIR=$(mktemp -d)
|
PKGDIR=$(mktemp -d)
|
||||||
|
echo "$PKGDIR"
|
||||||
|
|
||||||
SRC_DIR=$PWD
|
SRC_DIR=$PWD
|
||||||
OUTPUT_PATH=${FISH_ARTEFACT_PATH:-~/fish_built}
|
OUTPUT_PATH=${FISH_ARTEFACT_PATH:-~/fish_built}
|
||||||
|
@ -30,14 +64,66 @@ mkdir -p "$PKGDIR/build" "$PKGDIR/root" "$PKGDIR/intermediates" "$PKGDIR/dst"
|
||||||
|
|
||||||
# Pass FISH_USE_SYSTEM_PCRE2=OFF because a system PCRE2 on macOS will not be signed by fish,
|
# Pass FISH_USE_SYSTEM_PCRE2=OFF because a system PCRE2 on macOS will not be signed by fish,
|
||||||
# and will probably not be built universal, so the package will fail to validate/run on other systems.
|
# and will probably not be built universal, so the package will fail to validate/run on other systems.
|
||||||
{ cd "$PKGDIR/build" && cmake -DMAC_INJECT_GET_TASK_ALLOW=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" -DWITH_GETTEXT=OFF -DFISH_USE_SYSTEM_PCRE2=OFF -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' -DMAC_CODESIGN_ID="${MAC_CODESIGN_ID}" "$SRC_DIR" && make VERBOSE=1 -j 12 && env DESTDIR="$PKGDIR/root/" make install; }
|
{ cd "$PKGDIR/build" && cmake -DMAC_INJECT_GET_TASK_ALLOW=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" -DWITH_GETTEXT=OFF -DFISH_USE_SYSTEM_PCRE2=OFF -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' "$SRC_DIR" && make VERBOSE=1 -j 12 && env DESTDIR="$PKGDIR/root/" make install; }
|
||||||
|
|
||||||
|
if test -n "$SIGN"; then
|
||||||
|
echo "Signing executables"
|
||||||
|
ARGS=(
|
||||||
|
--p12-file "$P12_APP_FILE"
|
||||||
|
--p12-password "$P12_PASSWORD"
|
||||||
|
--code-signature-flags runtime
|
||||||
|
--for-notarization
|
||||||
|
)
|
||||||
|
if [ -n "$ENTITLEMENTS_FILE" ]; then
|
||||||
|
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
|
||||||
|
fi
|
||||||
|
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
|
||||||
|
(set +x; rcodesign sign "${ARGS[@]}" "$FILE")
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
pkgbuild --scripts "$SRC_DIR/build_tools/osx_package_scripts" --root "$PKGDIR/root/" --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" "$PKGDIR/intermediates/fish.pkg"
|
pkgbuild --scripts "$SRC_DIR/build_tools/osx_package_scripts" --root "$PKGDIR/root/" --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" "$PKGDIR/intermediates/fish.pkg"
|
||||||
productbuild --package-path "$PKGDIR/intermediates" --distribution "$SRC_DIR/build_tools/osx_distribution.xml" --resources "$SRC_DIR/build_tools/osx_package_resources/" "$OUTPUT_PATH/fish-$VERSION.pkg"
|
productbuild --package-path "$PKGDIR/intermediates" --distribution "$SRC_DIR/build_tools/osx_distribution.xml" --resources "$SRC_DIR/build_tools/osx_package_resources/" "$OUTPUT_PATH/fish-$VERSION.pkg"
|
||||||
|
|
||||||
MAC_PRODUCTSIGN_ID=${MAC_PRODUCTSIGN_ID:--}
|
if test -n "$SIGN"; then
|
||||||
productsign --sign "${MAC_PRODUCTSIGN_ID}" "$OUTPUT_PATH/fish-$VERSION.pkg" "$OUTPUT_PATH/fish-$VERSION-signed.pkg" && mv "$OUTPUT_PATH/fish-$VERSION-signed.pkg" "$OUTPUT_PATH/fish-$VERSION.pkg"
|
echo "Signing installer"
|
||||||
|
ARGS=(
|
||||||
|
--p12-file "$P12_INSTALL_FILE"
|
||||||
|
--p12-password "$P12_PASSWORD"
|
||||||
|
--code-signature-flags runtime
|
||||||
|
--for-notarization
|
||||||
|
)
|
||||||
|
(set +x; rcodesign sign "${ARGS[@]}" "$OUTPUT_PATH/fish-$VERSION.pkg")
|
||||||
|
fi
|
||||||
|
|
||||||
# Make the app
|
# Make the app
|
||||||
{ cd "$PKGDIR/build" && make -j 12 signed_fish_macapp && zip -r "$OUTPUT_PATH/fish-$VERSION.app.zip" fish.app; }
|
cd "$PKGDIR/build"
|
||||||
|
make -j 12 fish_macapp
|
||||||
|
if test -n "$SIGN"; then
|
||||||
|
echo "Signing app"
|
||||||
|
ARGS=(
|
||||||
|
--p12-file "$P12_APP_FILE"
|
||||||
|
--p12-password "$P12_PASSWORD"
|
||||||
|
--code-signature-flags runtime
|
||||||
|
--for-notarization
|
||||||
|
)
|
||||||
|
if [ -n "$ENTITLEMENTS_FILE" ]; then
|
||||||
|
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
|
||||||
|
fi
|
||||||
|
(set +x; rcodesign sign "${ARGS[@]}" "fish.app")
|
||||||
|
|
||||||
|
fi
|
||||||
|
mv "fish.app" "$OUTPUT_PATH/fish-$VERSION.app"
|
||||||
|
cd "$OUTPUT_PATH"
|
||||||
|
|
||||||
|
# Maybe notarize.
|
||||||
|
if test -n "$NOTARIZE"; then
|
||||||
|
echo "Notarizing"
|
||||||
|
rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.pkg"
|
||||||
|
rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.app"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Zip it up.
|
||||||
|
zip -r "fish-$VERSION.app.zip" "fish-$VERSION.app" && rm -Rf "fish-$VERSION.app"
|
||||||
|
|
||||||
rm -rf "$PKGDIR"
|
rm -rf "$PKGDIR"
|
||||||
|
|
54
doc_internal/mac-artifacts.md
Normal file
54
doc_internal/mac-artifacts.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# Building macOS Artifacts
|
||||||
|
|
||||||
|
This describes how to build macOS artifacts as part of a release. These artifacts are uploaded to the GitHub release page, where they are discovered by the web site build script.
|
||||||
|
|
||||||
|
Artifacts may be built locally or in CI. Using CI is preferred.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> Only fish-shell administrations may create releases. Released macOS packages require code signing and notarization via private Apple developer keys, which are owned by @ridiculous_fish. These keys are stored in GitHub secrets.
|
||||||
|
|
||||||
|
## Building in CI (GitHub Actions)
|
||||||
|
|
||||||
|
macOS packages may be built in CI through a GitHub workflow. This requires a fish-shell administrator as it requires invoking secret code signing keys.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
|
||||||
|
1. Go to https://github.com/fish-shell/fish-shell/actions
|
||||||
|
2. On the left side, click on the "macOS build and codesign" Action.
|
||||||
|
3. On the right, click on the "Run workflow" button, select the branch or tag, and click Run Workflow.
|
||||||
|
4. **Reload the page**. This is necessary because the workflow will not appear until the page is reloaded.
|
||||||
|
5. Click on the new workflow. It should be in a Waiting state.
|
||||||
|
6. Click on Review Deployments, and approve and start the "deployment."
|
||||||
|
7. Once the workflow completes, expand the `actions/upload-artifact@v4` step in the logs. This should have an "Artifact download URL" - click it and download!
|
||||||
|
|
||||||
|
## Building locally (no code signing)
|
||||||
|
|
||||||
|
To build locally without notarizing and code signing, use the `build_tools/make_pkg.sh` script:
|
||||||
|
|
||||||
|
```
|
||||||
|
> ./build_tools/make_pkg.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Packages will be placed in `~/fish_built` by default.
|
||||||
|
|
||||||
|
Note these packages will result in loud warnings or errors when others try to install them, because of the lack of code signing.
|
||||||
|
|
||||||
|
## Building locally with code signing and notarization
|
||||||
|
|
||||||
|
You will need the following:
|
||||||
|
|
||||||
|
- The ".p12" certificate files for both "Developer ID Application" and "Developer ID Installer".
|
||||||
|
- (These can be generated via Export Certificate in Xcode)
|
||||||
|
- The password for these files (by convention, the same password is used for both).
|
||||||
|
- The JSON file generated via `rcodesign encode-app-store-connect-api-key`.
|
||||||
|
|
||||||
|
An example run:
|
||||||
|
|
||||||
|
```
|
||||||
|
> ./build_tools/make_pkg.sh -s \
|
||||||
|
-f fish-developer-id-application.p12 \
|
||||||
|
-i fish-developer-id-installer.p12 \
|
||||||
|
-p "$NOTARIZE_PASSWORD" \
|
||||||
|
-n \
|
||||||
|
-j notarize-data.json
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user