-
Notifications
You must be signed in to change notification settings - Fork 286
Description
Release Workflow
The automated release workflow shouldn't be kicked off when a release has been published (on: release: types: [published]
), because the release will have then already been made available to the public.
If anything fails or is suboptimal (like poorly worded generated release notes) in the workflow, we'd need to either delete, modify, or supersede the botched release, all of which are suboptimal.
It's best to split the release process into 3 stages:
Stage 1: Generate Draft
- When a tag matching a version string regex (
v\d+(?:\.\d+)*(?:-(?:alpha|beta|rc)\.\d+)?
) is pushed to themain
branch of themas-cli/mas
repo, run a workflow that will:- Stop progressing if any step fails.
- Revert prior steps if any step fails.
- Checkout the tag
- Validate the tag:
- Ensure that the the tag is annotated & signed (& possibly ensure its message follows conventions).
- Otherwise (e.g., the tag is lightweight, unsigned, improperly signed, or its message is improperly formatted), delete the tag & stop processing.
- Build
- Package the
*.pkg
(s) - Create a GitHub Release draft.
- Autogenerate release notes.
- Label the draft as a prerelease if the version tag contains a
-
.
- Upload the
*.pkg
(s) to the draft - Create a
mas-cli/tap/mas
formula bump PR, which will generate (but not yet publish) bottles for all applicable macOS versions & platforms
- Stop progressing if any step fails.
- In an emergency, a release can be made manually via the GitHub web or cli interface
Stage 2: Manual Draft Inspection / Modification
After inspecting everything created in stage 1, the releaser may then either:
- Publish the draft as a release as is
- Modify the draft, then publish the draft as a release
- Delete the draft
Stage 3: Publish Release / Delete Draft
No GitHub workflow events fire when a GitHub Release draft is deleted. Thus, if the releaser decides to delete the GitHub Release draft in stage 2, we can either have a script/delete_draft
script that will take care of deleting / reverting / closing / etc. everything, or just have them manually clean everything up.
If the releaser publishes the draft, then an on: release: types: [published]
workflow will:
- If the release is not a prerelease, bump the
homebrew-core
mas
formula. - Apply the
pr-pull
label to themas-cli/tap/mas
formula bump PR, which will approve the PR & publish bottles to a new GitHub Release for the new mas version inmas-cli/homebrew-tap
for:- Intel for macOS 10.13 & newer.
- Apple Silicon for macOS 11 & newer.
The custom tap bottle generation & publishing process has been implemented as follows, but not tested due to issues getting the testing environment setup (see mas-cli/homebrew-tap#66 for the custom tap issue):
- When the custom tap formula PR is pushed to
mas-cli/tap
, thetests.yml
workflow will:- Build one bottle for
arm64
onmacos-15
& one bottle forx86_64
onmacOS-13
- Rename each bottle from the macOS version on which it was built to the macOS version name for the oldest supported macOS version for each respective platform:
- Rename to
*arm64_big_sur*
forarm64
- Rename to
*high_sierra*
forx86_64
- Rename to
- Download the mas 1.8.6
el_capitan
bottle forx86_64
from the 1.8.6 release - Upload all 3 bottles as artifacts to the GitHub PR
- Build one bottle for
- When the PR is labelled with
pr-pull
, thepublish.yml
workflow will:- Publish the 3 bottles to a new GitHub Release for the new mas version in the custom tap repo.
Legacy Version Patch Branches
If we ever release patches for legacy mas versions, they should be done in a legacy version patch branch.
Given that we aren't patching legacy versions right now, the first revamp of the new release system doesn't need to support it, but we might want to think through the workflow to support it in the future.
See #655 for details about legacy version patch branches & other git-related proposals.
Current Work
- If possible, replace existing lightweight version tags with backdated signed annotated tags.
- GitHub Release artifacts:
- Include version (& platform? & macOS version?) in
mas.pkg
filename for existing versions - Platform-specific (instead of universal) installers
- Include version (& platform? & macOS version?) in
- Document release process #357
Possible Future Tasks
- Cleanup
actions/checkout@v4
output:git config --global advice.detachedHead false
- Ensure bottles built with the newest installed Xcode version?
- Rename
build-test.yml
asbuild-test-lint.yml
. - Custom tap version tags & releases for existing versions?
- Artifact attestations for builds
Dangerfile.swift
appears to be used only for PRs made directly onmas-cli/mas
, not for those via forks:- Setup for fork PRs.
- Or delete it.
- Move
.github/*.yml
into.github/workflows
? - Depend on
swift
command instead of on Xcode? github_prerelease_allowlist.json
?- GitHub/git protections #655
- Use YAML & JSON schemas for validation #657
Completed
- 3 stages outlined above implemented, except for:
- the custom tap bottle build workflows
script/delete_draft
- Remove extraneous files from
mas-cli/mas
repo:Makefile
.github/event.json
- Many shell scripts
- Homebrew formulae: store each only in its respective tap repo, e.g.,
homebrew/homebrew-core
ormas-cli/tap
- Bump
homebrew-core
&mas-cli/tap/mas
formulae in taps instead of locally generating / modifying them.- Do not create a manual pull request for the custom tap.
- Bump
- Generate files only when absolutely necessary, but git ignore them, e.g.,
Sources/mas/Package.swift
- Do not commit or branch in
mas-cli/mas
on release. - Store values in as few places as possible, e.g.:
- Store version in
mas-cli/mas
repo only in version tag, not in any files or in any branch names.
- Store version in
- Reuse existing functionality (like
brew bump-formula-pr
) instead of reinventing the wheel. - Standardize:
- Ensure the same tools are used everywhere, e.g.:
- ensure
/bin/bash
is used everywhere instead of some places usingbash
from the$PATH
.
- ensure
- Remove dependencies whose functionality can be performed by other things, e.g.:
sd
: script that used it was deleted, but if script had been kept, should use shell scripting insteadmise
: usebrew bundle
instead
- Ensure the same tools are used everywhere, e.g.:
- Scope code, e.g.,:
- Formulae should be bumped only during a release, so do not perform bumps in scripts called by release workflow; instead, embed bumps in the workflow itself, otherwise people might incorrectly run bump scripts outside of the workflow.
- If, under extraordinary circumstances, someone must bump the formulae outside of the release process, they should know enough about the release process to know that they should just copy the bump commands from the workflow.
- Formulae should be bumped only during a release, so do not perform bumps in scripts called by release workflow; instead, embed bumps in the workflow itself, otherwise people might incorrectly run bump scripts outside of the workflow.
- Limit pathways, prevent bad values, & make config more explicit, e.g.:
- shell scripts should accept only arguments, not environment variables.
- Release workflows & shell scripts should:
- Require that the release tag is a properly formatted version tag.
- Checkout the release version tag, then use that version tag as the source for the version & for the git revision.
- Not accept arguments, environment variables, or anything else to specify version, tag, branch, revision, etc.
- Replace
script/version --write
&script/version_bump
withscript/generate_version_info_for_swift
- When working locally, versions used (e.g. in
Sources/mas/Package.swift
) for revisions that aren't directly tagged with a version tag are now specified by the fullgit describe --tags
output, which includes the current revision & the number of commits since the tag. - Merge all
release.yml
jobs into one. - shell script cleanup:
- Migrate from bash to zsh.
- Standardize settings at beginning of scripts using .
- Prevent some external settings from affecting scripts.
cd
into project root at beginning of every script.
- Use
-Ndfgku
in all shebangs (add-e
to all shebangs except forlint
's). - Lowercase all non-environment variables.
- Quote as appropriate.
- Include braces in all variable uses.
- Use
printf
instead ofecho
. - Write to stderr where appropriate.
- Inline single-use variables.
- Improve script outputs.
- Simplify & standardize scripts.
- Use more zsh builtins instead of external commands.
- Fix informational URLs throughout repo:
- Replace redirecting links.
- Remove defunct links.
- http -> http.
- Ensure all files have one & only one trailing newline, and no leading newlines.
- Minor Swift cleanups.
- Improve documentation & samples.
- Improve & simplify
.editorconfig
. - Upgrade danger-swift from 3.18.0 to 3.20.2.
- Suppress
script/test
boilerplate output. - Fix
mas-cli/tap/mas
tap URLs. - Remove
.actrc
& act brew dependency - Cleanup
actions/checkout@v4
output:git config --global init.defaultBranch main
- Include mas version in
mas.pkg
filename. - Platform-specific bottles.
- Custom tap version tags & releases.
- Bottles in
mas-cli/homebrew-tap
instead of inmas-cli/mas
Resolve:
- Remove
Distribution.plist
; replace with a heredoc / process substitution inscript/package
#677 - Ensure shell scripts aren't unduly influenced by external environment #658
- Replace uses of commands that are not shell builtins #656
- Switch all scripts from bash to zsh #654
- Cannot build 1.8.7+ on macOS < 12.3 because
readlink
doesn't accept-f
flag #636 - 1.8.7 GitHub Release & Homebrew custom tap binaries are arm64 instead of universal #635
- Custom Homebrew tap has incorrect versions in bottle URLs #634
- Suppress successful test output from
script/test
#628