Skip to content

Commit

Permalink
Prepare codesigning script for use in CI
Browse files Browse the repository at this point in the history
- Set GitHub Actions "output" for path to dmg artifact.
- Emit information about the GitHub Actions build in CI.
- Add more docstring comments.
- Tweak CLI args to accept release name as a leading positional
  argument.
- Ensure at least one binary arugment is passed to the script.
- Ensure unexpected arguments result in the script exiting with an
  error.
- Ensure that trailing `--binary` or `--resource` flags are treated as
  errors.
- Make script more friendly for local development by building and
  outputing dmgs to a git ignored `dist` directory.
- Unnest dmg codesign step from an existing log group.
  • Loading branch information
lopopolo committed Sep 4, 2022
1 parent e0fb807 commit f00e6e4
Showing 1 changed file with 46 additions and 11 deletions.
57 changes: 46 additions & 11 deletions macos_sign_and_notarize.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,24 @@
from pathlib import Path


def set_output(*, name, value):
"""
Set an output for a GitHub Actions job.
https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs
"""

print(f"::set-output name={name}::{value}")


@contextmanager
def log_group(group):
"""
Create an expandable log group in GitHub Actions job logs.
https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines
"""

print(f"::group::{group}")
try:
yield
Expand Down Expand Up @@ -367,20 +383,21 @@ def create_notarization_bundle(*, release_name, binaries, resources):
Returns `Path` object to the newly created DMG archive.
"""

stage = Path("dist").joinpath(release_name)
dmg = Path("dist").joinpath(f"{release_name}.dmg")

with log_group("Create disk image for notarization"):
dmg = Path(f"{release_name}.dmg")
dmg.unlink(missing_ok=True)

try:
shutil.rmtree(release_name)
shutil.rmtree(stage)
except FileNotFoundError:
pass
os.makedirs(release_name, exist_ok=True)
os.makedirs(stage, exist_ok=True)

for binary in binaries:
shutil.copy(binary, release_name)
shutil.copy(binary, stage)
for resource in resources:
shutil.copy(resource, release_name)
shutil.copy(resource, stage)

# notarytool submit works only with UDIF disk images, signed "flat"
# installer packages, and zip files.
Expand All @@ -402,7 +419,7 @@ def create_notarization_bundle(*, release_name, binaries, resources):
"-volname",
"Artichoke Ruby nightly",
"-srcfolder",
release_name,
str(stage),
"-ov",
"-format",
"UDZO",
Expand All @@ -411,8 +428,8 @@ def create_notarization_bundle(*, release_name, binaries, resources):
],
check=True,
)
codesign_binary(binary_path=dmg)
return dmg
codesign_binary(binary_path=dmg)
return dmg


def notarize_bundle(*, bundle):
Expand Down Expand Up @@ -570,9 +587,10 @@ def validate(*, bundle, binary_names):

def main(args):
if not args:
print("Error: pass binaries to sign as positional arguments", file=sys.stderr)
print("Error: pass name of release as first argument", file=sys.stderr)
return 1

release_name, *args = args
binaries = []
resources = []
append_next = None
Expand All @@ -585,29 +603,46 @@ def main(args):
append_next = resources
continue
print(f"Unexpected argument: {arg}", file=sys.stderr)
return 1
append_next.append(Path(arg))
append_next = None

if append_next is not None:
if append_next is binaries:
print("Error: unterminated --binary flag", file=sys.stderr)
if append_next is resources:
print("Error: unterminated --resource flag", file=sys.stderr)
return 1

if not binaries:
print("Error: no binaries passed to be codesigned", file=sys.stderr)
return 1

for binary in binaries:
if not binary.is_file():
print("Error: {binary} does not exist", file=sys.stderr)
return 1

try:
emit_metadata()

keychain_password = secrets.token_urlsafe()
setup_codesigning_and_notarization_keychain(keychain_password=keychain_password)

for binary in binaries:
codesign_binary(binary_path=binary)

bundle = create_notarization_bundle(
release_name="2022-09-03-test-codesign-notarize-dmg-v1",
release_name=release_name,
binaries=binaries,
resources=resources,
)
notarize_bundle(bundle=bundle)
staple_bundle(bundle=bundle)

validate(bundle=bundle, binary_names=[binary.name for binary in binaries])
set_output(name="bundle", value=bundle)

return 0
except subprocess.CalledProcessError as e:
print(
Expand Down

0 comments on commit f00e6e4

Please sign in to comment.