Skip to content

Weekly Development Release #59

Weekly Development Release

Weekly Development Release #59

Workflow file for this run

name: Nightly Development Release
# Automated nightly builds for development channel testing
# Runs at 2 AM UTC if there are changes since last development release
# Keeps last 7 development releases, deletes older ones
# Uses self-hosted runner like the release workflow
on:
schedule:
# Run every day at 2 AM UTC if there are changes
- cron: '0 2 * * *'
workflow_dispatch:
# Allow manual triggering
env:
XCODE_VERSION: '26.2'
MACOS_VERSION: '14.0'
permissions:
contents: write
jobs:
check-changes:
name: Check for Changes
runs-on: ubuntu-latest
outputs:
should_build: ${{ steps.check.outputs.has_changes }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for changes since last dev release
id: check
run: |
# Get the latest development release tag
LATEST_DEV_TAG=$(git tag -l '*-dev.*' --sort=-version:refname | head -1)
if [ -z "$LATEST_DEV_TAG" ]; then
echo "No previous development releases found"
echo "has_changes=true" >> $GITHUB_OUTPUT
exit 0
fi
# Check if there are meaningful commits since the last dev release
# Ignore appcast files which are auto-updated by the build process
MEANINGFUL_CHANGES=$(git diff --name-only ${LATEST_DEV_TAG}..HEAD | grep -v -E '^appcast-dev' | wc -l)
if [ "$MEANINGFUL_CHANGES" -gt 0 ]; then
echo "Found meaningful changes since $LATEST_DEV_TAG (excluding appcast files)"
git diff --name-only ${LATEST_DEV_TAG}..HEAD | grep -v -E '^appcast-dev' | sed 's/^/ - /'
echo "has_changes=true" >> $GITHUB_OUTPUT
else
echo "No meaningful changes since $LATEST_DEV_TAG (only appcast updates)"
echo "has_changes=false" >> $GITHUB_OUTPUT
fi
build-and-release:
name: Build, Sign, and Release
needs: check-changes
if: needs.check-changes.outputs.should_build == 'true'
runs-on: [self-hosted]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ env.XCODE_VERSION }}
- name: Download Metal Toolchain
run: |
echo "Downloading Metal Toolchain for Xcode ${{ env.XCODE_VERSION }}..."
sudo xcodebuild -downloadComponent MetalToolchain || echo "Metal Toolchain already installed or download failed"
- name: Increment development version
run: |
./scripts/increment-dev-version.sh
DEV_VERSION=$(cat Info.plist | grep -A1 CFBundleShortVersionString | tail -1 | sed 's/.*<string>\(.*\)<\/string>/\1/')
echo "DEV_VERSION=$DEV_VERSION" >> $GITHUB_ENV
echo "Building version: $DEV_VERSION"
- name: Build development release
run: make build-release
- name: Validate Python Bundle
run: ./scripts/validate_python_bundle.sh Release
- name: Sign and notarize
run: |
if [ -f /Users/andrew/.sam_runner_env ]; then
source /Users/andrew/.sam_runner_env
fi
make sign-only-release
- name: Verify distribution files
run: |
if [ ! -f "dist/SAM-${DEV_VERSION}.dmg" ]; then
echo "ERROR: DMG not found"
exit 1
fi
if [ ! -f "dist/SAM-${DEV_VERSION}.zip" ]; then
echo "ERROR: ZIP not found"
exit 1
fi
echo "Distribution files ready:"
ls -lh dist/SAM-${DEV_VERSION}.*
- name: Update development appcast
env:
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
run: |
# Create temporary file for private key
TEMP_KEY_FILE=$(mktemp)
echo "$SPARKLE_PRIVATE_KEY" > "$TEMP_KEY_FILE"
chmod 600 "$TEMP_KEY_FILE"
# Update appcast-dev-items.xml with new development release
./scripts/update_dev_appcast.sh "${DEV_VERSION}" "dist/SAM-${DEV_VERSION}.zip" "$TEMP_KEY_FILE"
# Generate appcast-dev.xml from items + stable releases
./scripts/generate-dev-appcast.sh
# Clean up temporary key file
rm -f "$TEMP_KEY_FILE"
- name: Commit and push appcast changes
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add appcast-dev-items.xml appcast-dev.xml
if git diff --staged --quiet; then
echo "No changes to development appcast files"
else
git commit -m "chore(dev-release): update appcast-dev.xml for v${DEV_VERSION}"
git push origin HEAD:main
fi
- name: Create GitHub pre-release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.DEV_VERSION }}
name: SAM ${{ env.DEV_VERSION }} (Development)
body: |
⚠️ **This is a DEVELOPMENT pre-release build**
Development builds are released automatically and may contain:
- Bugs and instability
- Incomplete features
- Breaking changes
**Do not use development builds for production work.**
Enable development updates in SAM → Preferences → General → "Receive development updates"
### Changes Since Last Development Release
See commit history for details.
draft: false
prerelease: true
files: |
dist/SAM-${{ env.DEV_VERSION }}.zip
dist/SAM-${{ env.DEV_VERSION }}.dmg
cleanup-old-releases:
name: Cleanup Old Development Releases
needs: build-and-release
runs-on: ubuntu-latest
steps:
- name: Delete old development releases
uses: actions/github-script@v7
with:
script: |
const KEEP_COUNT = 7; // Keep last 7 development releases
// Get all releases
const { data: releases } = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
});
// Filter for development pre-releases
const devReleases = releases.filter(r =>
r.prerelease && r.tag_name.includes('-dev.')
);
// Sort by created date (newest first)
devReleases.sort((a, b) =>
new Date(b.created_at) - new Date(a.created_at)
);
// Delete releases beyond KEEP_COUNT
for (let i = KEEP_COUNT; i < devReleases.length; i++) {
const release = devReleases[i];
console.log(`Deleting old development release: ${release.tag_name}`);
// Delete the release
await github.rest.repos.deleteRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.id,
});
// Delete the tag
try {
await github.rest.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `tags/${release.tag_name}`,
});
} catch (error) {
console.log(`Could not delete tag ${release.tag_name}: ${error.message}`);
}
}
console.log(`Kept ${Math.min(KEEP_COUNT, devReleases.length)} development releases`);