Skip to content

Merge dev: v3.0.0 — 10 new tools, 43 total, state preservation #39

Merge dev: v3.0.0 — 10 new tools, 43 total, state preservation

Merge dev: v3.0.0 — 10 new tools, 43 total, state preservation #39

Workflow file for this run

name: Build & Test
permissions:
contents: write
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
jobs:
build-cli:
name: Build CLI
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- name: Build CLI (Release)
run: swift build -c release
- name: Run CLI smoke tests
run: |
.build/release/dx --version
.build/release/dx uuid
.build/release/dx hash "test"
.build/release/dx base64 encode "hello"
.build/release/dx epoch now
- name: Upload CLI binary
uses: actions/upload-artifact@v4
with:
name: dx-cli
path: .build/release/dx
build-app:
name: Build macOS App
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- name: Install XcodeGen
run: brew install xcodegen
- name: Generate Xcode Project
run: xcodegen generate
- name: Build App (Release)
run: |
xcodebuild -project DXTools.xcodeproj \
-scheme DXTools \
-configuration Release \
-derivedDataPath build/DerivedData \
build
- name: Run Tests
run: |
xcodebuild -project DXTools.xcodeproj \
-scheme DXToolsTests \
-configuration Debug \
-derivedDataPath build/DerivedData \
CI_ENVIRONMENT=YES \
test
release:
name: Create Release
needs: [build-cli, build-app]
runs-on: macos-15
if: startsWith(github.ref, 'refs/tags/v') || (github.ref == 'refs/heads/main' && startsWith(github.event.head_commit.message, 'release:'))
steps:
- uses: actions/checkout@v4
- name: Install XcodeGen
run: brew install xcodegen
- name: Build CLI
run: swift build -c release
- name: Build App
run: |
xcodegen generate
xcodebuild -project DXTools.xcodeproj \
-scheme DXTools \
-configuration Release \
-derivedDataPath build/DerivedData \
build
- name: Build .icns from asset catalog
run: |
ICONSET="build/AppIcon.iconset"
mkdir -p "$ICONSET"
SRC="DXTools/Assets.xcassets/AppIcon.appiconset"
for f in icon_16x16.png icon_16x16@2x.png icon_32x32.png icon_32x32@2x.png \
icon_128x128.png icon_128x128@2x.png icon_256x256.png icon_256x256@2x.png \
icon_512x512.png icon_512x512@2x.png; do
cp "$SRC/$f" "$ICONSET/$f"
done
iconutil --convert icns "$ICONSET" --output build/AppIcon.icns
- name: Package DMG
run: |
APP_PATH="build/DerivedData/Build/Products/Release/DX Tools.app"
if [ ! -d "$APP_PATH" ]; then
echo "❌ App not found at: $APP_PATH"
find build/DerivedData -name "*.app" -type d 2>/dev/null
exit 1
fi
echo "✅ Found app: $APP_PATH"
mkdir -p build/dmg-staging
cp -R "$APP_PATH" "build/dmg-staging/"
ln -s /Applications "build/dmg-staging/Applications"
# Set volume icon
if [ -f build/AppIcon.icns ]; then
cp build/AppIcon.icns "build/dmg-staging/.VolumeIcon.icns"
SetFile -a C "build/dmg-staging" 2>/dev/null || true
fi
hdiutil create -volname "DX Tools" \
-srcfolder "build/dmg-staging" \
-ov -format UDZO \
"build/DXTools.dmg"
rm -rf "build/dmg-staging"
ls -la build/DXTools.dmg
echo "✅ DMG created: $(du -h build/DXTools.dmg | cut -f1)"
- name: Extract version
id: version
run: echo "version=$(grep 'MARKETING_VERSION' project.yml | head -1 | awk '{print $2}' | tr -d '\"')" >> $GITHUB_OUTPUT
- name: Generate release notes
id: notes
run: |
# Get commits since last tag
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -n "$PREV_TAG" ]; then
CHANGES=$(git log "$PREV_TAG"..HEAD --pretty=format:"- %s" --no-merges | grep -v "^- chore:" | grep -v "^- Merge" | head -20)
else
CHANGES="- Initial release"
fi
# Write to file for multiline support
cat > build/release-notes.md << 'HEADER'
## DX Tools v${{ steps.version.outputs.version }}
### Downloads
- **DXTools.dmg** — macOS app (drag to Applications)
- **dx** — CLI binary (copy to `~/bin/` or `/usr/local/bin/`)
### Install via Homebrew
```
brew tap openstruct/tap && brew install dx-tools
```
### Changes
HEADER
echo "$CHANGES" >> build/release-notes.md
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.version.outputs.version }}
name: DX Tools v${{ steps.version.outputs.version }}
make_latest: true
body_path: build/release-notes.md
files: |
build/DXTools.dmg
.build/release/dx
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}