Skip to content

feat: package macOS builds as DMG and fix release workflow#5

Merged
wysaid merged 3 commits into
masterfrom
feat/macos-dmg-release
Feb 26, 2026
Merged

feat: package macOS builds as DMG and fix release workflow#5
wysaid merged 3 commits into
masterfrom
feat/macos-dmg-release

Conversation

@wysaid

@wysaid wysaid commented Feb 25, 2026

Copy link
Copy Markdown
Owner

Summary

Improves the macOS release experience by packaging apps as DMG files and fixing several issues in the release workflow.

Changes

build_dmg.sh (new)

  • Reusable script that wraps the full macOS packaging pipeline
  • Default mode (no args): auto-runs macdeployqt, resolves Frameworks/ symlinks (prevents broken symlinks in DMG), ad-hoc signs, and creates a DMG via hdiutil — targets filterGenerator.app and filterRuleTest.app in ./build/
  • Single-app mode (--app-path / --output): used by CI where macdeployqt runs in a dedicated prior step
  • Flags: --no-deploy, --no-sign, --volname, -h

.github/workflows/macos-build.yml

  • Replace tar -czf packaging with DMG packaging via build_dmg.sh for both arm64 and x86_64 jobs
  • macdeployqt step is retained as a separate step before packaging (CI already had it; single-app mode does not re-run it)

.github/workflows/release.yml

  • Add draft: false — releases now publish immediately without requiring manual promotion from draft state
  • Add artifacts/**/*.dmg to the files: glob so macOS DMGs are attached to the GitHub Release page

tools/README.md (new)

  • Deprecation notice for pre-built binaries in tools/; directs users to the GitHub Releases page

README.md

  • Add CI status badges: Release, macOS Build, Linux Build, Windows Build

Testing

  • Locally verified ./build_dmg.sh default mode: produces 29 MB DMGs with Qt frameworks correctly embedded (was 1.3 MB without macdeployqt)
  • CI workflow structure unchanged — macdeployqt step runs before build_dmg.sh in single-app mode

- Add build_dmg.sh: runs macdeployqt, resolves Frameworks symlinks,
  ad-hoc signs, and creates a DMG via hdiutil. Default mode packages
  filterGenerator.app and filterRuleTest.app from ./build/ with full
  Qt deploy. Single-app mode (--app-path/--output) is used by CI.
- Update macos-build.yml: replace tar.gz with DMG via build_dmg.sh
  for both arm64 and x86_64 jobs (macdeployqt step retained before).
- Update release.yml: add draft:false so releases publish immediately;
  add artifacts/**/*.dmg glob so macOS DMGs attach to Release page.
- Add tools/README.md: deprecation notice pointing to Releases page.
- Update README.md: add CI status badges for Release/macOS/Linux/Windows.
Copilot AI review requested due to automatic review settings February 25, 2026 14:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the macOS release/distribution pipeline by switching macOS artifacts from .tar.gz bundles to .dmg images, and updates the release workflow so macOS DMGs are attached to GitHub Releases. It also adds documentation and CI badges to better direct users to official downloads.

Changes:

  • Add build_dmg.sh to package .app bundles into .dmg files (with optional deploy/sign behavior).
  • Update macOS build workflow to upload DMG artifacts instead of tarballs; update release workflow to include **/*.dmg in release assets.
  • Add tools/README.md deprecation notice and add CI workflow badges to README.md.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
build_dmg.sh New macOS DMG packaging script intended for local use and CI single-app packaging.
.github/workflows/macos-build.yml Switch macOS CI packaging/upload from .tar.gz to .dmg via build_dmg.sh.
.github/workflows/release.yml Publish releases non-draft and attach .dmg artifacts to GitHub Releases.
tools/README.md New deprecation notice pointing users to GitHub Releases for binaries.
README.md Add workflow status badges.

Comment thread build_dmg.sh Outdated
Comment on lines +91 to +92
_REAL="$(realpath "$_F")"
rm "$_F"

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolve_frameworks_symlinks calls realpath under set -e, so if a Frameworks/ symlink is broken (the situation this function is meant to fix), realpath will exit non-zero and abort the entire script before the symlink can be replaced. Handle realpath failure explicitly (e.g., conditional + warning + continue, or use readlink and validate existence) so broken symlinks don’t hard-fail packaging.

Suggested change
_REAL="$(realpath "$_F")"
rm "$_F"
if ! _REAL="$(realpath "$_F" 2>/dev/null)"; then
echo " warning: failed to resolve symlink $(basename "$_F"); leaving as-is" >&2
continue
fi
if [[ ! -e "$_REAL" ]]; then
echo " warning: target of symlink $(basename "$_F") does not exist: $_REAL" >&2
continue
fi
rm -f "$_F"

Copilot uses AI. Check for mistakes.
Comment thread build_dmg.sh
Comment on lines +110 to +115
echo "→ macdeployqt: $_APP"
"$_QDEPLOY" "$_APP" -verbose=1

echo " Resolving Frameworks symlinks..."
resolve_frameworks_symlinks "$_APP"
}

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In single-app mode (the mode used by CI), the script never calls resolve_frameworks_symlinks because it only runs inside deploy_app. If macdeployqt leaves Frameworks/ symlinks (or dangling .DS_Store links) that need fixing, CI-produced DMGs won’t get that cleanup. Consider calling resolve_frameworks_symlinks from package_dmg (or adding an explicit cleanup step/flag) so both modes produce equivalent, reliable bundles.

Copilot uses AI. Check for mistakes.
Comment thread build_dmg.sh
Comment on lines +34 to +46
while [[ $# -gt 0 ]]; do
case "$1" in
--app-path)
APP_PATH="$2"
shift 2
;;
--output)
OUTPUT_PATH="$2"
shift 2
;;
--volname)
VOLNAME="$2"
shift 2

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argument parsing assumes options that take a value always have a following parameter (e.g., --app-path uses $2). With set -u, invoking the script with a missing value will terminate with an “unbound variable” error rather than a clear usage message. Add explicit validation for missing option values and print --help / a friendly error.

Copilot uses AI. Check for mistakes.
@wysaid wysaid force-pushed the feat/macos-dmg-release branch from 71489a9 to ff3dd70 Compare February 26, 2026 02:40
- Add explicit validation for missing option values (--app-path, --output, --volname)
- Handle realpath failure gracefully in resolve_frameworks_symlinks
- Call resolve_frameworks_symlinks in package_dmg for single-app mode (CI)
@wysaid wysaid merged commit f26fa41 into master Feb 26, 2026
5 checks passed
@wysaid wysaid deleted the feat/macos-dmg-release branch February 26, 2026 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants