From b0ea64848db695227678b83da652a377c258966e Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Sun, 20 Jul 2025 06:36:52 +0300 Subject: [PATCH 01/10] Provide needed work to export the umbrella package as a SPM package --- Package.swift | 21 +++++++++++++++++++++ umbrella/build.gradle.kts | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 Package.swift diff --git a/Package.swift b/Package.swift new file mode 100644 index 00000000..664c5629 --- /dev/null +++ b/Package.swift @@ -0,0 +1,21 @@ +// swift-tools-version:5.5 +import PackageDescription + +let package = Package( + name: "QuranSync", + platforms: [ + .iOS(.v13) + ], + products: [ + .library( + name: "shared", + targets: ["shared"] + ) + ], + targets: [ + .binaryTarget( + name: "shared", + path: "umbrella/build/XCFrameworks/release/Shared.xcframework" + ) + ] +) diff --git a/umbrella/build.gradle.kts b/umbrella/build.gradle.kts index f4fff343..f3b4bd36 100644 --- a/umbrella/build.gradle.kts +++ b/umbrella/build.gradle.kts @@ -26,6 +26,25 @@ kotlin { } } +// Task to create XCFramework +tasks.register("createXCFramework") { + dependsOn("linkReleaseFrameworkIosArm64") + dependsOn("linkReleaseFrameworkIosSimulatorArm64") + + doLast { + val xcframeworkDir = file("build/XCFrameworks/release") + xcframeworkDir.mkdirs() + + exec { + commandLine("xcodebuild", "-create-xcframework", + "-framework", "build/bin/iosArm64/releaseFramework/Shared.framework", + "-framework", "build/bin/iosSimulatorArm64/releaseFramework/Shared.framework", + "-output", "build/XCFrameworks/release/Shared.xcframework" + ) + } + } +} + mavenPublishing { publishToMavenCentral() signAllPublications() From 96820dd07cdf3b30d0e022bb47fdc259c8a8426c Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Fri, 12 Sep 2025 06:58:35 +0300 Subject: [PATCH 02/10] Update workflows to build iOS frameworks on pushes --- .github/workflows/build.yml | 172 ++++++++++++++++++++++++++++---- .github/workflows/release.yml | 178 ++++++++++++++++++++++++++++++++++ Package.swift | 19 +++- docs/RELEASE_WORKFLOW.md | 150 ++++++++++++++++++++++++++++ scripts/dev-setup.sh | 94 ++++++++++++++++++ scripts/release.sh | 78 +++++++++++++++ 6 files changed, 665 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 docs/RELEASE_WORKFLOW.md create mode 100755 scripts/dev-setup.sh create mode 100755 scripts/release.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0758c20f..da222fea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,30 +1,160 @@ -name: Gradle CI +name: Build on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] + +concurrency: + group: build-${{ github.ref }} + cancel-in-progress: true # Cancel previous builds jobs: - build: + test: runs-on: macos-latest - steps: - - uses: actions/checkout@v5 - - - name: Set up JDK 17 - uses: actions/setup-java@v5 - with: - java-version: '17' - distribution: 'temurin' - cache: gradle - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + - uses: actions/checkout@v4 - - name: Clean project - run: ./gradlew clean - - - name: Run tests - run: ./gradlew allTests \ No newline at end of file + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: gradle + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Run Tests + run: ./gradlew allTests + + build-dev: + needs: test + runs-on: macos-latest + if: github.ref == 'refs/heads/main' + outputs: + build-version: ${{ steps.version.outputs.version }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: gradle + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Generate Build Version + id: version + run: | + # Use timestamp + short SHA for dev builds + TIMESTAMP=$(date +%Y%m%d-%H%M%S) + SHORT_SHA=${GITHUB_SHA:0:7} + BUILD_VERSION="dev-$TIMESTAMP-$SHORT_SHA" + echo "version=$BUILD_VERSION" >> $GITHUB_OUTPUT + echo "đŸ“Ļ Build version: $BUILD_VERSION" + + - name: Build XCFramework + run: ./gradlew :umbrella:createXCFramework + + - name: Prepare Distribution + run: | + cd umbrella/build/XCFrameworks/release + # Rename to match package expectation + mv Shared.xcframework QuranSync.xcframework + zip -r QuranSync-${{ steps.version.outputs.version }}.xcframework.zip QuranSync.xcframework + + - name: Calculate Checksum + id: checksum + run: | + CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip) + echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT + + - name: Update Package.swift for Dev Build + run: | + # Update Package.swift directly with dev build info + sed -i '' "s/{VERSION}/${{ steps.version.outputs.version }}/g" Package.swift + sed -i '' "s/{CHECKSUM_TO_BE_REPLACED_BY_CI}/${{ steps.checksum.outputs.checksum }}/g" Package.swift + + - name: Commit Package.swift for Dev Build + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add Package.swift + git commit -m "chore: update Package.swift for dev build ${{ steps.version.outputs.version }}" + git push origin main + + - name: Create Development Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.version.outputs.version }} + name: "Development Build ${{ steps.version.outputs.version }}" + prerelease: true + files: | + umbrella/build/XCFrameworks/release/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip + body: | + ## 🚧 Development Build + + **Commit:** ${{ github.sha }} + **Branch:** ${{ github.ref_name }} + **Checksum:** `${{ steps.checksum.outputs.checksum }}` + + ### Usage (SPM) + Package.swift has been automatically updated for this dev build: + ```swift + .package(url: "https://github.com/quran/mobile-sync", exact: "${{ steps.version.outputs.version }}") + ``` + + ### Alternative: Manual Binary Target + If you prefer manual control: + ```swift + .binaryTarget( + name: "QuranSync", + url: "https://github.com/quran/mobile-sync/releases/download/${{ steps.version.outputs.version }}/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip", + checksum: "${{ steps.checksum.outputs.checksum }}" + ) + ``` + + ### âš ī¸ Important Warnings + - **This is a development build** - use stable releases for production + - **Dev builds may be deleted without notice** - we only keep the 5 most recent + - **Package.swift will be overwritten** by the next dev build or release + - **No stability guarantees** - APIs may change between dev builds + - **For testing only** - not recommended for App Store submissions + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + cleanup-old-dev-builds: + needs: build-dev + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + steps: + - name: Cleanup Old Dev Builds + uses: actions/github-script@v7 + with: + script: | + const { data: releases } = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + }); + + // Keep last 5 dev builds, delete older ones + const devBuilds = releases + .filter(release => release.tag_name.startsWith('dev-')) + .sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) + .slice(5); // Skip first 5 (keep them) + + for (const release of devBuilds) { + console.log(`Deleting old dev build: ${release.tag_name}`); + await github.rest.repos.deleteRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + }); + } \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..11bc1df5 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,178 @@ +name: Release + +on: + workflow_dispatch: + inputs: + version_bump: + description: 'Version bump type' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + prerelease: + description: 'Is this a prerelease?' + required: false + default: false + type: boolean + +concurrency: + group: release + cancel-in-progress: false # Don't cancel releases + +jobs: + release: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: gradle + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Get Current Version + id: current_version + run: | + # Get latest tag, default to 0.0.0 if none exists + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + CURRENT_VERSION=${LATEST_TAG#v} # Remove 'v' prefix + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "📋 Current version: $CURRENT_VERSION" + + - name: Calculate Next Version + id: next_version + run: | + CURRENT="${{ steps.current_version.outputs.version }}" + BUMP="${{ github.event.inputs.version_bump }}" + + # Split version into parts + IFS='.' read -ra VERSION_PARTS <<< "$CURRENT" + MAJOR=${VERSION_PARTS[0]:-0} + MINOR=${VERSION_PARTS[1]:-0} + PATCH=${VERSION_PARTS[2]:-0} + + # Calculate new version based on bump type + case $BUMP in + "major") + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + ;; + "minor") + MINOR=$((MINOR + 1)) + PATCH=0 + ;; + "patch") + PATCH=$((PATCH + 1)) + ;; + esac + + NEW_VERSION="$MAJOR.$MINOR.$PATCH" + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "🚀 Next version: $NEW_VERSION" + + - name: Run Tests + run: ./gradlew allTests + + - name: Build XCFramework + run: ./gradlew :umbrella:createXCFramework + + - name: Prepare Distribution + run: | + cd umbrella/build/XCFrameworks/release + # Rename to match package expectation + mv Shared.xcframework QuranSync.xcframework + zip -r QuranSync.xcframework.zip QuranSync.xcframework + + - name: Calculate Checksum + id: checksum + run: | + CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSync.xcframework.zip) + echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT + + - name: Update Package.swift + run: | + sed -i '' "s/{VERSION}/v${{ steps.next_version.outputs.version }}/g" Package.swift + sed -i '' "s/{CHECKSUM_TO_BE_REPLACED_BY_CI}/${{ steps.checksum.outputs.checksum }}/g" Package.swift + + - name: Generate Release Notes + id: release_notes + run: | + # Get commits since last release + LAST_TAG="${{ steps.current_version.outputs.version }}" + if [ "$LAST_TAG" = "0.0.0" ]; then + COMMITS=$(git log --pretty=format:"- %s" --reverse) + else + COMMITS=$(git log v$LAST_TAG..HEAD --pretty=format:"- %s" --reverse) + fi + + # Create release notes + cat > release_notes.md << EOF + ## What's Changed + + $COMMITS + + ## Installation + + ### Swift Package Manager + Add to your \`Package.swift\`: + \`\`\`swift + dependencies: [ + .package(url: "https://github.com/quran/mobile-sync", from: "${{ steps.next_version.outputs.version }}") + ] + \`\`\` + + ### Xcode + 1. File → Add Package Dependencies + 2. Enter: \`https://github.com/quran/mobile-sync\` + 3. Select version: \`${{ steps.next_version.outputs.version }}\` + EOF + + - name: Commit Package.swift Updates + run: | + git add Package.swift + git commit -m "chore: update Package.swift for v${{ steps.next_version.outputs.version }}" || exit 0 + + - name: Create Tag + run: | + git tag -a "v${{ steps.next_version.outputs.version }}" -m "Release v${{ steps.next_version.outputs.version }}" + + - name: Push Changes + run: | + git push origin main + git push origin "v${{ steps.next_version.outputs.version }}" + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + tag_name: "v${{ steps.next_version.outputs.version }}" + name: "QuranSync v${{ steps.next_version.outputs.version }}" + prerelease: ${{ github.event.inputs.prerelease }} + files: | + umbrella/build/XCFrameworks/release/QuranSync.xcframework.zip + body_path: release_notes.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Summary + run: | + echo "✅ Released QuranSync v${{ steps.next_version.outputs.version }}" + echo "đŸˇī¸ Tag: v${{ steps.next_version.outputs.version }}" + echo "đŸ“Ļ Asset: QuranSync.xcframework.zip" + echo "🔗 Release: https://github.com/quran/mobile-sync/releases/tag/v${{ steps.next_version.outputs.version }}" \ No newline at end of file diff --git a/Package.swift b/Package.swift index 664c5629..f46a516b 100644 --- a/Package.swift +++ b/Package.swift @@ -1,6 +1,9 @@ // swift-tools-version:5.5 import PackageDescription +// Set to true for local development +let useLocalBuild = false + let package = Package( name: "QuranSync", platforms: [ @@ -8,14 +11,20 @@ let package = Package( ], products: [ .library( - name: "shared", - targets: ["shared"] + name: "QuranSync", + targets: ["QuranSync"] ) ], - targets: [ + targets: useLocalBuild ? [ .binaryTarget( - name: "shared", + name: "QuranSync", path: "umbrella/build/XCFrameworks/release/Shared.xcframework" ) + ] : [ + .binaryTarget( + name: "QuranSync", + url: "https://github.com/quran/mobile-sync/releases/download/{VERSION}/QuranSync.xcframework.zip", + checksum: "{CHECKSUM_TO_BE_REPLACED_BY_CI}" + ) ] -) +) \ No newline at end of file diff --git a/docs/RELEASE_WORKFLOW.md b/docs/RELEASE_WORKFLOW.md new file mode 100644 index 00000000..63b82d7f --- /dev/null +++ b/docs/RELEASE_WORKFLOW.md @@ -0,0 +1,150 @@ +# Release Workflow Guide + +## How Releases Work + +### 🔄 Development Builds (Automatic) +- **Trigger**: Every push to `main` branch +- **Tag Format**: `dev-YYYYMMDD-HHMMSS-SHORTSHA` (e.g., `dev-20240315-143022-abc1234`) +- **Package.swift**: Automatically updated with dev build info +- **Cancellation**: New builds cancel previous ones +- **Cleanup**: Only keeps 5 most recent dev builds +- **Usage**: For testing latest changes with standard SPM integration + +### 🚀 Stable Releases (Manual) +- **Trigger**: Manual workflow dispatch +- **Tag Format**: `v1.2.3` (semantic versioning) +- **No cancellation**: Releases run to completion +- **Persistence**: Stable releases are never auto-deleted + +## Triggering Releases + +### Option 1: GitHub Web Interface +1. Go to **Actions** tab in GitHub +2. Click **Release** workflow +3. Click **Run workflow** button +4. Choose: + - **Branch**: `main` (default) + - **Version bump**: `patch`, `minor`, or `major` + - **Prerelease**: `true` or `false` + +### Option 2: GitHub CLI (Recommended) +```bash +# Install GitHub CLI if needed +brew install gh +gh auth login + +# Trigger releases +gh workflow run release.yml -f version_bump=patch +gh workflow run release.yml -f version_bump=minor -f prerelease=true +gh workflow run release.yml -f version_bump=major +``` + +### Option 3: Helper Script (Easiest) +```bash +# Use our helper script +./scripts/release.sh patch # 1.0.0 → 1.0.1 +./scripts/release.sh minor # 1.0.0 → 1.1.0 +./scripts/release.sh major # 1.0.0 → 2.0.0 + +# Check status +./scripts/release.sh status # View releases and workflow runs +./scripts/release.sh cancel # Cancel running releases if needed +``` + +## What Happens During Builds/Releases + +### Development Build Steps (Automatic on main push): +1. **Testing**: Runs full test suite (`./gradlew allTests`) +2. **Building**: Creates XCFramework (`./gradlew :umbrella:createXCFramework`) +3. **Package Update**: Updates `Package.swift` with dev build version and checksum +4. **Git Operations**: + - Commits Package.swift changes + - Pushes updated Package.swift to main + - Creates dev build tag (e.g., `dev-20240315-143022-abc1234`) +5. **Release Creation**: + - Creates GitHub prerelease with dev build + - Uploads XCFramework zip file + - Includes checksum in release notes + +### Stable Release Steps (Manual trigger): +1. **Version Calculation**: Bumps version based on current git tags +2. **Testing**: Runs full test suite (`./gradlew allTests`) +3. **Building**: Creates XCFramework (`./gradlew :umbrella:createXCFramework`) +4. **Package Update**: Updates `Package.swift` with stable version and checksum +5. **Git Operations**: + - Commits Package.swift changes + - Creates new git tag (e.g., `v1.2.3`) + - Pushes to repository +6. **Release Creation**: + - Creates GitHub release with generated notes + - Uploads XCFramework zip file + - Marks as prerelease if specified + +### The Bot Email Explained +```yaml +git config user.email "41898282+github-actions[bot]@users.noreply.github.com" +``` +This is GitHub's official bot email address. When the workflow commits Package.swift changes, it shows up in git history as coming from `github-actions[bot]` instead of a real user account. + +## Version Bumping Logic + +The release workflow automatically determines the next version: + +```bash +# Current version: v1.2.3 + +./scripts/release.sh patch # → v1.2.4 (bug fixes) +./scripts/release.sh minor # → v1.3.0 (new features, backward compatible) +./scripts/release.sh major # → v2.0.0 (breaking changes) +``` + +## Development Workflow Examples + +### Daily Development +```bash +# 1. Work on features, merge PRs to main +git checkout -b feature/new-sync-algorithm +# ... make changes ... +git push origin feature/new-sync-algorithm +# ... create PR, merge to main ... + +# 2. Dev build automatically created: dev-20240315-143022-abc1234 + +# 3. Test in iOS project using dev build +./scripts/dev-setup.sh list-dev # See available builds +./scripts/dev-setup.sh dev dev-20240315-143022-abc1234 + +# Or use standard SPM (Package.swift is auto-updated): +# .package(url: "https://github.com/quran/mobile-sync", exact: "dev-20240315-143022-abc1234") + +# 4. When ready for stable release +./scripts/release.sh patch # Creates v1.0.1 +``` + +### Release Cadence Suggestions +- **Patch releases**: Bug fixes, small improvements (weekly/bi-weekly) +- **Minor releases**: New features, API additions (monthly/quarterly) +- **Major releases**: Breaking changes, major rewrites (quarterly/yearly) + +## Troubleshooting + +### Release Failed? +```bash +./scripts/release.sh status # Check what happened +gh run view [RUN_ID] --log # View detailed logs +``` + +### Need to Cancel Release? +```bash +./scripts/release.sh cancel # Stops running releases +``` + +### Wrong Version Released? +- You can create a new release immediately +- Old releases are never auto-deleted +- Consider using prerelease flag for testing + +### Dev Build Missing? +- Check if build failed: Go to Actions tab +- Older dev builds are auto-deleted (only 5 kept) +- Use `./scripts/dev-setup.sh list-dev` to see available builds \ No newline at end of file diff --git a/scripts/dev-setup.sh b/scripts/dev-setup.sh new file mode 100755 index 00000000..fd1144f6 --- /dev/null +++ b/scripts/dev-setup.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# Development setup script for QuranSync + +IOS_PROJECT_PATH="../YourIOSProject" # Adjust path as needed +FRAMEWORK_NAME="QuranSync" + +case "$1" in + "local") + echo "🔨 Building local XCFramework..." + ./gradlew :umbrella:createXCFramework + + echo "📝 Updating Package.swift for local development..." + sed -i '' 's/let useLocalBuild = false/let useLocalBuild = true/' Package.swift + + if [ -d "$IOS_PROJECT_PATH" ]; then + echo "🔄 Updating iOS project dependencies..." + cd "$IOS_PROJECT_PATH" + xcodebuild -resolvePackageDependencies + echo "✅ Local development setup complete!" + fi + ;; + + "remote") + echo "📝 Updating Package.swift for remote dependencies..." + sed -i '' 's/let useLocalBuild = true/let useLocalBuild = false/' Package.swift + + if [ -d "$IOS_PROJECT_PATH" ]; then + echo "🔄 Updating iOS project dependencies..." + cd "$IOS_PROJECT_PATH" + xcodebuild -resolvePackageDependencies + echo "✅ Remote development setup complete!" + fi + ;; + + "build") + echo "🔨 Building XCFramework..." + ./gradlew :umbrella:createXCFramework + echo "✅ Build complete!" + ;; + + "dev") + if [ -z "$2" ]; then + echo "❌ Please specify a dev build version" + echo "Usage: $0 dev " + echo "Example: $0 dev dev-20240101-123456-abc1234" + exit 1 + fi + + DEV_VERSION="$2" + echo "🔄 Switching to dev build: $DEV_VERSION" + + # Fetch the Package.swift that was updated for this specific dev build + echo "📝 Fetching Package.swift for $DEV_VERSION..." + + # Get the commit hash of the dev build tag + COMMIT_HASH=$(git ls-remote origin refs/tags/$DEV_VERSION | cut -f1) + + if [ -n "$COMMIT_HASH" ]; then + # Fetch the Package.swift from that specific commit + curl -s "https://raw.githubusercontent.com/quran/mobile-sync/$COMMIT_HASH/Package.swift" -o Package.swift + + # Ensure we're not in local mode + sed -i '' 's/let useLocalBuild = true/let useLocalBuild = false/' Package.swift + + echo "✅ Updated Package.swift to use $DEV_VERSION" + echo "📝 Package.swift automatically configured with correct checksum" + else + echo "❌ Could not find dev build $DEV_VERSION" + echo " Make sure the version exists: https://github.com/quran/mobile-sync/releases/tag/$DEV_VERSION" + exit 1 + fi + ;; + + "list-dev") + echo "📋 Available dev builds:" + curl -s "https://api.github.com/repos/quran/mobile-sync/releases" | \ + grep -E '"tag_name"|"name"' | \ + grep -A1 '"dev-' | \ + sed 's/.*"tag_name": "\(.*\)".*/\1/' | \ + sed 's/.*"name": "\(.*\)".*/ \1/' | \ + head -20 + ;; + + *) + echo "Usage: $0 {local|remote|build|dev|list-dev}" + echo " local - Switch to local development mode" + echo " remote - Switch to remote dependencies" + echo " build - Build XCFramework only" + echo " dev - Switch to specific dev build" + echo " list-dev - List available dev builds" + exit 1 + ;; +esac \ No newline at end of file diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 00000000..d3b7968d --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +# Release helper script for QuranSync + +set -e + +REPO="quran/mobile-sync" + +case "$1" in + "patch"|"minor"|"major") + BUMP_TYPE="$1" + PRERELEASE="${2:-false}" + + echo "🚀 Triggering $BUMP_TYPE release..." + + if [ "$PRERELEASE" = "true" ]; then + echo "âš ī¸ This will be marked as a prerelease" + fi + + # Use GitHub CLI to trigger workflow + gh workflow run release.yml \ + -f version_bump="$BUMP_TYPE" \ + -f prerelease="$PRERELEASE" + + echo "✅ Release workflow triggered!" + echo "🔗 Monitor progress: https://github.com/$REPO/actions" + ;; + + "status") + echo "📊 Recent releases:" + gh release list --limit 10 + echo "" + echo "đŸ—ī¸ Current workflow runs:" + gh run list --workflow=release.yml --limit 5 + ;; + + "dev-builds") + echo "🚧 Recent dev builds:" + gh release list --limit 10 | grep "dev-" || echo "No dev builds found" + ;; + + "cancel") + echo "âšī¸ Cancelling running release workflows..." + RUNS=$(gh run list --workflow=release.yml --status=in_progress --json databaseId --jq '.[].databaseId') + + if [ -z "$RUNS" ]; then + echo "No running release workflows found" + else + for RUN_ID in $RUNS; do + echo "Cancelling run $RUN_ID..." + gh run cancel $RUN_ID + done + echo "✅ Cancelled running workflows" + fi + ;; + + *) + echo "Usage: $0 {patch|minor|major|status|dev-builds|cancel}" + echo "" + echo "Commands:" + echo " patch - Create a patch release (1.0.0 → 1.0.1)" + echo " minor - Create a minor release (1.0.0 → 1.1.0)" + echo " major - Create a major release (1.0.0 → 2.0.0)" + echo " status - Show recent releases and workflow status" + echo " dev-builds - Show recent development builds" + echo " cancel - Cancel running release workflows" + echo "" + echo "Examples:" + echo " $0 patch # Normal patch release" + echo " $0 minor true # Minor prerelease" + echo " $0 major # Major release" + echo "" + echo "Prerequisites:" + echo " - Install GitHub CLI: brew install gh" + echo " - Authenticate: gh auth login" + exit 1 + ;; +esac \ No newline at end of file From 79e9d3d51a977a916c4a89f36cab77c0f270f936 Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Sat, 13 Sep 2025 10:45:26 +0300 Subject: [PATCH 03/10] Rename exported iOS package to QuranSyncUmbrella --- Package.swift | 16 ++++++++-------- umbrella/build.gradle.kts | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Package.swift b/Package.swift index f46a516b..6c8aed22 100644 --- a/Package.swift +++ b/Package.swift @@ -5,26 +5,26 @@ import PackageDescription let useLocalBuild = false let package = Package( - name: "QuranSync", + name: "QuranSyncUmbrella", platforms: [ .iOS(.v13) ], products: [ .library( - name: "QuranSync", - targets: ["QuranSync"] + name: "QuranSyncUmbrella", + targets: ["QuranSyncUmbrella"] ) ], targets: useLocalBuild ? [ .binaryTarget( - name: "QuranSync", - path: "umbrella/build/XCFrameworks/release/Shared.xcframework" + name: "QuranSyncUmbrella", + path: "umbrella/build/XCFrameworks/release/QuranSyncUmbrella.xcframework" ) ] : [ .binaryTarget( - name: "QuranSync", - url: "https://github.com/quran/mobile-sync/releases/download/{VERSION}/QuranSync.xcframework.zip", + name: "QuranSyncUmbrella", + url: "https://github.com/quran/mobile-sync/releases/download/{VERSION}/QuranSyncUmbrella.xcframework.zip", checksum: "{CHECKSUM_TO_BE_REPLACED_BY_CI}" ) ] -) \ No newline at end of file +) diff --git a/umbrella/build.gradle.kts b/umbrella/build.gradle.kts index cd9cdbbf..4c822a74 100644 --- a/umbrella/build.gradle.kts +++ b/umbrella/build.gradle.kts @@ -10,7 +10,7 @@ kotlin { iosSimulatorArm64() ).forEach { iosTarget -> iosTarget.binaries.framework { - baseName = "Shared" + baseName = "QuranSyncUmbrella" isStatic = true export(projects.syncengine) @@ -39,9 +39,9 @@ tasks.register("createXCFramework") { exec { commandLine("xcodebuild", "-create-xcframework", - "-framework", "build/bin/iosArm64/releaseFramework/Shared.framework", - "-framework", "build/bin/iosSimulatorArm64/releaseFramework/Shared.framework", - "-output", "build/XCFrameworks/release/Shared.xcframework" + "-framework", "build/bin/iosArm64/releaseFramework/QuranSyncUmbrella.framework", + "-framework", "build/bin/iosSimulatorArm64/releaseFramework/QuranSyncUmbrella.framework", + "-output", "build/XCFrameworks/release/QuranSyncUmbrella.xcframework" ) } } @@ -58,4 +58,4 @@ mavenPublishing { inceptionYear = "2025" url = "https://github.com/quran/mobile-sync" } -} \ No newline at end of file +} From 07d9098ca86f3379accbf7912aef3aaca1d49950 Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Sat, 13 Sep 2025 11:25:28 +0300 Subject: [PATCH 04/10] Fix some other parts: rename QuranSync to QuranSyncUmbrella --- .github/workflows/build.yml | 14 ++++++-------- .github/workflows/release.yml | 13 ++++++------- docs/RELEASE_WORKFLOW.md | 2 +- scripts/dev-setup.sh | 4 ++-- scripts/release.sh | 2 +- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da222fea..6783857d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,14 +66,12 @@ jobs: - name: Prepare Distribution run: | cd umbrella/build/XCFrameworks/release - # Rename to match package expectation - mv Shared.xcframework QuranSync.xcframework - zip -r QuranSync-${{ steps.version.outputs.version }}.xcframework.zip QuranSync.xcframework + zip -r QuranSyncUmbrella-${{ steps.version.outputs.version }}.xcframework.zip QuranSyncUmbrella.xcframework - name: Calculate Checksum id: checksum run: | - CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip) + CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSyncUmbrella-${{ steps.version.outputs.version }}.xcframework.zip) echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT - name: Update Package.swift for Dev Build @@ -97,7 +95,7 @@ jobs: name: "Development Build ${{ steps.version.outputs.version }}" prerelease: true files: | - umbrella/build/XCFrameworks/release/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip + umbrella/build/XCFrameworks/release/QuranSyncUmbrella-${{ steps.version.outputs.version }}.xcframework.zip body: | ## 🚧 Development Build @@ -115,8 +113,8 @@ jobs: If you prefer manual control: ```swift .binaryTarget( - name: "QuranSync", - url: "https://github.com/quran/mobile-sync/releases/download/${{ steps.version.outputs.version }}/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip", + name: "QuranSyncUmbrella", + url: "https://github.com/quran/mobile-sync/releases/download/${{ steps.version.outputs.version }}/QuranSyncUmbrella-${{ steps.version.outputs.version }}.xcframework.zip", checksum: "${{ steps.checksum.outputs.checksum }}" ) ``` @@ -157,4 +155,4 @@ jobs: repo: context.repo.repo, release_id: release.id, }); - } \ No newline at end of file + } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 11bc1df5..b39ff2ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,14 +96,13 @@ jobs: - name: Prepare Distribution run: | cd umbrella/build/XCFrameworks/release - # Rename to match package expectation - mv Shared.xcframework QuranSync.xcframework - zip -r QuranSync.xcframework.zip QuranSync.xcframework + # XCFramework is already named correctly: QuranSyncUmbrella.xcframework + zip -r QuranSyncUmbrella.xcframework.zip QuranSyncUmbrella.xcframework - name: Calculate Checksum id: checksum run: | - CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSync.xcframework.zip) + CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSyncUmbrella.xcframework.zip) echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT - name: Update Package.swift @@ -165,14 +164,14 @@ jobs: name: "QuranSync v${{ steps.next_version.outputs.version }}" prerelease: ${{ github.event.inputs.prerelease }} files: | - umbrella/build/XCFrameworks/release/QuranSync.xcframework.zip + umbrella/build/XCFrameworks/release/QuranSyncUmbrella.xcframework.zip body_path: release_notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Summary run: | - echo "✅ Released QuranSync v${{ steps.next_version.outputs.version }}" + echo "✅ Released QuranSyncUmbrella v${{ steps.next_version.outputs.version }}" echo "đŸˇī¸ Tag: v${{ steps.next_version.outputs.version }}" - echo "đŸ“Ļ Asset: QuranSync.xcframework.zip" + echo "đŸ“Ļ Asset: QuranSyncUmbrella.xcframework.zip" echo "🔗 Release: https://github.com/quran/mobile-sync/releases/tag/v${{ steps.next_version.outputs.version }}" \ No newline at end of file diff --git a/docs/RELEASE_WORKFLOW.md b/docs/RELEASE_WORKFLOW.md index 63b82d7f..477c77d0 100644 --- a/docs/RELEASE_WORKFLOW.md +++ b/docs/RELEASE_WORKFLOW.md @@ -1,4 +1,4 @@ -# Release Workflow Guide +# Release Workflow Guide - QuranSyncUmbrella ## How Releases Work diff --git a/scripts/dev-setup.sh b/scripts/dev-setup.sh index fd1144f6..212bea81 100755 --- a/scripts/dev-setup.sh +++ b/scripts/dev-setup.sh @@ -1,9 +1,9 @@ #!/bin/bash -# Development setup script for QuranSync +# Development setup script for QuranSyncUmbrella IOS_PROJECT_PATH="../YourIOSProject" # Adjust path as needed -FRAMEWORK_NAME="QuranSync" +FRAMEWORK_NAME="QuranSyncUmbrella" case "$1" in "local") diff --git a/scripts/release.sh b/scripts/release.sh index d3b7968d..f42d580d 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Release helper script for QuranSync +# Release helper script for QuranSyncUmbrella set -e From 5f35d6da7af199051e4fcfe7541ac735603433f8 Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Sun, 14 Sep 2025 07:32:00 +0300 Subject: [PATCH 05/10] Uncheck dev-setup.sh --- scripts/dev-setup.sh | 94 -------------------------------------------- 1 file changed, 94 deletions(-) delete mode 100755 scripts/dev-setup.sh diff --git a/scripts/dev-setup.sh b/scripts/dev-setup.sh deleted file mode 100755 index 212bea81..00000000 --- a/scripts/dev-setup.sh +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/bash - -# Development setup script for QuranSyncUmbrella - -IOS_PROJECT_PATH="../YourIOSProject" # Adjust path as needed -FRAMEWORK_NAME="QuranSyncUmbrella" - -case "$1" in - "local") - echo "🔨 Building local XCFramework..." - ./gradlew :umbrella:createXCFramework - - echo "📝 Updating Package.swift for local development..." - sed -i '' 's/let useLocalBuild = false/let useLocalBuild = true/' Package.swift - - if [ -d "$IOS_PROJECT_PATH" ]; then - echo "🔄 Updating iOS project dependencies..." - cd "$IOS_PROJECT_PATH" - xcodebuild -resolvePackageDependencies - echo "✅ Local development setup complete!" - fi - ;; - - "remote") - echo "📝 Updating Package.swift for remote dependencies..." - sed -i '' 's/let useLocalBuild = true/let useLocalBuild = false/' Package.swift - - if [ -d "$IOS_PROJECT_PATH" ]; then - echo "🔄 Updating iOS project dependencies..." - cd "$IOS_PROJECT_PATH" - xcodebuild -resolvePackageDependencies - echo "✅ Remote development setup complete!" - fi - ;; - - "build") - echo "🔨 Building XCFramework..." - ./gradlew :umbrella:createXCFramework - echo "✅ Build complete!" - ;; - - "dev") - if [ -z "$2" ]; then - echo "❌ Please specify a dev build version" - echo "Usage: $0 dev " - echo "Example: $0 dev dev-20240101-123456-abc1234" - exit 1 - fi - - DEV_VERSION="$2" - echo "🔄 Switching to dev build: $DEV_VERSION" - - # Fetch the Package.swift that was updated for this specific dev build - echo "📝 Fetching Package.swift for $DEV_VERSION..." - - # Get the commit hash of the dev build tag - COMMIT_HASH=$(git ls-remote origin refs/tags/$DEV_VERSION | cut -f1) - - if [ -n "$COMMIT_HASH" ]; then - # Fetch the Package.swift from that specific commit - curl -s "https://raw.githubusercontent.com/quran/mobile-sync/$COMMIT_HASH/Package.swift" -o Package.swift - - # Ensure we're not in local mode - sed -i '' 's/let useLocalBuild = true/let useLocalBuild = false/' Package.swift - - echo "✅ Updated Package.swift to use $DEV_VERSION" - echo "📝 Package.swift automatically configured with correct checksum" - else - echo "❌ Could not find dev build $DEV_VERSION" - echo " Make sure the version exists: https://github.com/quran/mobile-sync/releases/tag/$DEV_VERSION" - exit 1 - fi - ;; - - "list-dev") - echo "📋 Available dev builds:" - curl -s "https://api.github.com/repos/quran/mobile-sync/releases" | \ - grep -E '"tag_name"|"name"' | \ - grep -A1 '"dev-' | \ - sed 's/.*"tag_name": "\(.*\)".*/\1/' | \ - sed 's/.*"name": "\(.*\)".*/ \1/' | \ - head -20 - ;; - - *) - echo "Usage: $0 {local|remote|build|dev|list-dev}" - echo " local - Switch to local development mode" - echo " remote - Switch to remote dependencies" - echo " build - Build XCFramework only" - echo " dev - Switch to specific dev build" - echo " list-dev - List available dev builds" - exit 1 - ;; -esac \ No newline at end of file From ff8cfdcfc584a182fb5ddeb2ab0f4da2b09c239c Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Mon, 15 Sep 2025 05:07:19 +0300 Subject: [PATCH 06/10] Rename epxorted Swift package back to QuranSync --- .github/workflows/build.yml | 10 +++++----- .github/workflows/release.yml | 11 +++++------ Package.swift | 14 +++++++------- docs/RELEASE_WORKFLOW.md | 2 +- scripts/release.sh | 2 +- umbrella/build.gradle.kts | 2 +- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77810d64..0653ac7d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,12 +66,12 @@ jobs: - name: Prepare Distribution run: | cd umbrella/build/XCFrameworks/release - zip -r QuranSyncUmbrella-${{ steps.version.outputs.version }}.xcframework.zip QuranSyncUmbrella.xcframework + zip -r QuranSync-${{ steps.version.outputs.version }}.xcframework.zip QuranSync.xcframework - name: Calculate Checksum id: checksum run: | - CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSyncUmbrella-${{ steps.version.outputs.version }}.xcframework.zip) + CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip) echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT - name: Update Package.swift for Dev Build @@ -95,7 +95,7 @@ jobs: name: "Development Build ${{ steps.version.outputs.version }}" prerelease: true files: | - umbrella/build/XCFrameworks/release/QuranSyncUmbrella-${{ steps.version.outputs.version }}.xcframework.zip + umbrella/build/XCFrameworks/release/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip body: | ## 🚧 Development Build @@ -113,8 +113,8 @@ jobs: If you prefer manual control: ```swift .binaryTarget( - name: "QuranSyncUmbrella", - url: "https://github.com/quran/mobile-sync/releases/download/${{ steps.version.outputs.version }}/QuranSyncUmbrella-${{ steps.version.outputs.version }}.xcframework.zip", + name: "QuranSync", + url: "https://github.com/quran/mobile-sync/releases/download/${{ steps.version.outputs.version }}/QuranSync-${{ steps.version.outputs.version }}.xcframework.zip", checksum: "${{ steps.checksum.outputs.checksum }}" ) ``` diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b39ff2ef..f2e0b96b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,13 +96,12 @@ jobs: - name: Prepare Distribution run: | cd umbrella/build/XCFrameworks/release - # XCFramework is already named correctly: QuranSyncUmbrella.xcframework - zip -r QuranSyncUmbrella.xcframework.zip QuranSyncUmbrella.xcframework + zip -r QuranSync.xcframework.zip QuranSync.xcframework - name: Calculate Checksum id: checksum run: | - CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSyncUmbrella.xcframework.zip) + CHECKSUM=$(swift package compute-checksum umbrella/build/XCFrameworks/release/QuranSync.xcframework.zip) echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT - name: Update Package.swift @@ -164,14 +163,14 @@ jobs: name: "QuranSync v${{ steps.next_version.outputs.version }}" prerelease: ${{ github.event.inputs.prerelease }} files: | - umbrella/build/XCFrameworks/release/QuranSyncUmbrella.xcframework.zip + umbrella/build/XCFrameworks/release/QuranSync.xcframework.zip body_path: release_notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Summary run: | - echo "✅ Released QuranSyncUmbrella v${{ steps.next_version.outputs.version }}" + echo "✅ Released QuranSync v${{ steps.next_version.outputs.version }}" echo "đŸˇī¸ Tag: v${{ steps.next_version.outputs.version }}" - echo "đŸ“Ļ Asset: QuranSyncUmbrella.xcframework.zip" + echo "đŸ“Ļ Asset: QuranSync.xcframework.zip" echo "🔗 Release: https://github.com/quran/mobile-sync/releases/tag/v${{ steps.next_version.outputs.version }}" \ No newline at end of file diff --git a/Package.swift b/Package.swift index 6c8aed22..0b365e13 100644 --- a/Package.swift +++ b/Package.swift @@ -5,25 +5,25 @@ import PackageDescription let useLocalBuild = false let package = Package( - name: "QuranSyncUmbrella", + name: "QuranSync", platforms: [ .iOS(.v13) ], products: [ .library( - name: "QuranSyncUmbrella", - targets: ["QuranSyncUmbrella"] + name: "QuranSync", + targets: ["QuranSync"] ) ], targets: useLocalBuild ? [ .binaryTarget( - name: "QuranSyncUmbrella", - path: "umbrella/build/XCFrameworks/release/QuranSyncUmbrella.xcframework" + name: "QuranSync", + path: "umbrella/build/XCFrameworks/release/QuranSync.xcframework" ) ] : [ .binaryTarget( - name: "QuranSyncUmbrella", - url: "https://github.com/quran/mobile-sync/releases/download/{VERSION}/QuranSyncUmbrella.xcframework.zip", + name: "QuranSync", + url: "https://github.com/quran/mobile-sync/releases/download/{VERSION}/QuranSync.xcframework.zip", checksum: "{CHECKSUM_TO_BE_REPLACED_BY_CI}" ) ] diff --git a/docs/RELEASE_WORKFLOW.md b/docs/RELEASE_WORKFLOW.md index 477c77d0..ac71493a 100644 --- a/docs/RELEASE_WORKFLOW.md +++ b/docs/RELEASE_WORKFLOW.md @@ -1,4 +1,4 @@ -# Release Workflow Guide - QuranSyncUmbrella +# Release Workflow Guide - QuranSync ## How Releases Work diff --git a/scripts/release.sh b/scripts/release.sh index f42d580d..d3b7968d 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Release helper script for QuranSyncUmbrella +# Release helper script for QuranSync set -e diff --git a/umbrella/build.gradle.kts b/umbrella/build.gradle.kts index 4c822a74..dfe9bf4e 100644 --- a/umbrella/build.gradle.kts +++ b/umbrella/build.gradle.kts @@ -10,7 +10,7 @@ kotlin { iosSimulatorArm64() ).forEach { iosTarget -> iosTarget.binaries.framework { - baseName = "QuranSyncUmbrella" + baseName = "QuranSync" isStatic = true export(projects.syncengine) From 8ee08289a146377efee72e75f545a40837c6a167 Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Mon, 15 Sep 2025 05:08:47 +0300 Subject: [PATCH 07/10] Switch to a local build with an env var --- .github/workflows/release.yml | 2 +- Package.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f2e0b96b..abb83ac9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -173,4 +173,4 @@ jobs: echo "✅ Released QuranSync v${{ steps.next_version.outputs.version }}" echo "đŸˇī¸ Tag: v${{ steps.next_version.outputs.version }}" echo "đŸ“Ļ Asset: QuranSync.xcframework.zip" - echo "🔗 Release: https://github.com/quran/mobile-sync/releases/tag/v${{ steps.next_version.outputs.version }}" \ No newline at end of file + echo "🔗 Release: https://github.com/quran/mobile-sync/releases/tag/v${{ steps.next_version.outputs.version }}" diff --git a/Package.swift b/Package.swift index 0b365e13..3329d62f 100644 --- a/Package.swift +++ b/Package.swift @@ -1,8 +1,8 @@ // swift-tools-version:5.5 import PackageDescription -// Set to true for local development -let useLocalBuild = false +// Check environment variable for local development mode (defaults to false) +let useLocalBuild = ProcessInfo.processInfo.environment["QURAN_SYNC_LOCAL_BUILD"] == "true" let package = Package( name: "QuranSync", From afc91a3f62cda87bdfbab0f361d388008ad1a881 Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Mon, 15 Sep 2025 05:30:37 +0300 Subject: [PATCH 08/10] Fix cacche issue of running XCFramework of umbrella --- umbrella/build.gradle.kts | 53 ++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/umbrella/build.gradle.kts b/umbrella/build.gradle.kts index dfe9bf4e..c8cbb837 100644 --- a/umbrella/build.gradle.kts +++ b/umbrella/build.gradle.kts @@ -1,3 +1,7 @@ +import org.gradle.api.tasks.TaskAction +import org.gradle.process.ExecOperations +import javax.inject.Inject + plugins { alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.vanniktech.maven.publish) @@ -29,24 +33,49 @@ kotlin { } // Task to create XCFramework -tasks.register("createXCFramework") { - dependsOn("linkReleaseFrameworkIosArm64") - dependsOn("linkReleaseFrameworkIosSimulatorArm64") - - doLast { - val xcframeworkDir = file("build/XCFrameworks/release") - xcframeworkDir.mkdirs() - - exec { +abstract class CreateXCFrameworkTask : DefaultTask() { + @get:InputDirectory + abstract val arm64Framework: DirectoryProperty + + @get:InputDirectory + abstract val simulatorFramework: DirectoryProperty + + @get:OutputDirectory + abstract val outputDirectory: DirectoryProperty + + @get:Inject + abstract val execOperations: ExecOperations + + @TaskAction + fun createXCFramework() { + val outputFramework = outputDirectory.file("QuranSync.xcframework").get().asFile + + // Clean existing XCFramework if it exists + if (outputFramework.exists()) { + outputFramework.deleteRecursively() + } + + outputDirectory.get().asFile.mkdirs() + + execOperations.exec { commandLine("xcodebuild", "-create-xcframework", - "-framework", "build/bin/iosArm64/releaseFramework/QuranSyncUmbrella.framework", - "-framework", "build/bin/iosSimulatorArm64/releaseFramework/QuranSyncUmbrella.framework", - "-output", "build/XCFrameworks/release/QuranSyncUmbrella.xcframework" + "-framework", arm64Framework.get().asFile.absolutePath, + "-framework", simulatorFramework.get().asFile.absolutePath, + "-output", outputFramework.absolutePath ) } } } +tasks.register("createXCFramework") { + dependsOn("linkReleaseFrameworkIosArm64") + dependsOn("linkReleaseFrameworkIosSimulatorArm64") + + arm64Framework.set(layout.buildDirectory.dir("bin/iosArm64/releaseFramework/QuranSync.framework")) + simulatorFramework.set(layout.buildDirectory.dir("bin/iosSimulatorArm64/releaseFramework/QuranSync.framework")) + outputDirectory.set(layout.buildDirectory.dir("XCFrameworks/release")) +} + mavenPublishing { publishToMavenCentral() signAllPublications() From 33e334aaf1db02ff20a1e2fc907d9dda5075af6b Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Sat, 20 Sep 2025 19:11:26 +0300 Subject: [PATCH 09/10] Change dev builds to be manually triggered --- .github/workflows/build.yml | 19 ++++++++++++------- scripts/release.sh | 25 ++++++++++++++++++++----- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0653ac7d..a6ac5211 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,15 @@ name: Build on: - push: - branches: [main] pull_request: branches: [main] + workflow_dispatch: + inputs: + create_dev_build: + description: 'Create development build' + required: false + default: false + type: boolean concurrency: group: build-${{ github.ref }} @@ -32,7 +37,7 @@ jobs: build-dev: needs: test runs-on: macos-latest - if: github.ref == 'refs/heads/main' + if: github.event.inputs.create_dev_build == 'true' outputs: build-version: ${{ steps.version.outputs.version }} steps: @@ -121,7 +126,7 @@ jobs: ### âš ī¸ Important Warnings - **This is a development build** - use stable releases for production - - **Dev builds may be deleted without notice** - we only keep the 5 most recent + - **Dev builds may be deleted without notice** - we only keep the 3 most recent - **Package.swift will be overwritten** by the next dev build or release - **No stability guarantees** - APIs may change between dev builds - **For testing only** - not recommended for App Store submissions @@ -131,7 +136,7 @@ jobs: cleanup-old-dev-builds: needs: build-dev runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' + if: github.event.inputs.create_dev_build == 'true' steps: - name: Cleanup Old Dev Builds uses: actions/github-script@v7 @@ -142,11 +147,11 @@ jobs: repo: context.repo.repo, }); - // Keep last 5 dev builds, delete older ones + // Keep last 3 dev builds, delete older ones const devBuilds = releases .filter(release => release.tag_name.startsWith('dev-')) .sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) - .slice(5); // Skip first 5 (keep them) + .slice(3); // Skip first 3 (keep them) for (const release of devBuilds) { console.log(`Deleting old dev build: ${release.tag_name}`); diff --git a/scripts/release.sh b/scripts/release.sh index d3b7968d..98ed08d8 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -10,21 +10,34 @@ case "$1" in "patch"|"minor"|"major") BUMP_TYPE="$1" PRERELEASE="${2:-false}" - + echo "🚀 Triggering $BUMP_TYPE release..." - + if [ "$PRERELEASE" = "true" ]; then echo "âš ī¸ This will be marked as a prerelease" fi - + # Use GitHub CLI to trigger workflow gh workflow run release.yml \ -f version_bump="$BUMP_TYPE" \ -f prerelease="$PRERELEASE" - + echo "✅ Release workflow triggered!" echo "🔗 Monitor progress: https://github.com/$REPO/actions" ;; + + "dev") + echo "🚧 Triggering development build..." + echo "âš ī¸ This will create a dev build and update Package.swift" + echo "đŸ“Ļ Only the 3 most recent dev builds are kept" + + # Use GitHub CLI to trigger workflow + gh workflow run build.yml \ + -f create_dev_build="true" + + echo "✅ Development build workflow triggered!" + echo "🔗 Monitor progress: https://github.com/$REPO/actions" + ;; "status") echo "📊 Recent releases:" @@ -55,12 +68,13 @@ case "$1" in ;; *) - echo "Usage: $0 {patch|minor|major|status|dev-builds|cancel}" + echo "Usage: $0 {patch|minor|major|dev|status|dev-builds|cancel}" echo "" echo "Commands:" echo " patch - Create a patch release (1.0.0 → 1.0.1)" echo " minor - Create a minor release (1.0.0 → 1.1.0)" echo " major - Create a major release (1.0.0 → 2.0.0)" + echo " dev - Create a development build" echo " status - Show recent releases and workflow status" echo " dev-builds - Show recent development builds" echo " cancel - Cancel running release workflows" @@ -69,6 +83,7 @@ case "$1" in echo " $0 patch # Normal patch release" echo " $0 minor true # Minor prerelease" echo " $0 major # Major release" + echo " $0 dev # Development build" echo "" echo "Prerequisites:" echo " - Install GitHub CLI: brew install gh" From da9ce3dd51cf342122e4e6de8671e08c1072bfa8 Mon Sep 17 00:00:00 2001 From: "Mohannad A. Hassan" Date: Mon, 22 Sep 2025 13:19:41 +0300 Subject: [PATCH 10/10] Verify XCFramework builds fine on pr workflows --- .github/workflows/build.yml | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a6ac5211..863ff7d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,23 +20,45 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - + - name: Setup Java uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' cache: gradle - + - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - + - name: Run Tests run: ./gradlew allTests --stacktrace --continue - build-dev: + build-verification: needs: test runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: gradle + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build All Modules + run: ./gradlew build --stacktrace + + - name: Build XCFramework + run: ./gradlew :umbrella:createXCFramework --stacktrace + + build-dev: + needs: [test, build-verification] + runs-on: macos-latest if: github.event.inputs.create_dev_build == 'true' outputs: build-version: ${{ steps.version.outputs.version }}