Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
name: 🔍 CI - Build & Test

on:
push:
branches: [ main, develop, staging ]
pull_request:
branches: [ main, develop ]
workflow_dispatch: # Allow manual triggering

env:
APP_NAME: "ClickIt"
BUNDLE_ID: "com.jsonify.clickit"

jobs:
build-test:
name: 🔨 Build & Test on Xcode
runs-on: macos-15

strategy:
matrix:
build_mode: [debug, release]
build_system: [xcode, spm]

steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4

- name: 🔍 Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable

- name: 📋 Environment Info
run: |
echo "🖥️ Runner: macOS $(sw_vers -productVersion)"
echo "🔨 Xcode: $(xcodebuild -version | head -1)"
echo "🐍 Swift: $(swift --version | head -1)"
echo "🏗️ Build Mode: ${{ matrix.build_mode }}"
echo "📦 Build System: ${{ matrix.build_system }}"

- name: 🧪 Run Swift Tests
if: matrix.build_system == 'spm'
run: |
echo "🧪 Running Swift Package Manager tests..."
swift test --verbose

- name: 🧪 Run Xcode Tests
if: matrix.build_system == 'xcode'
run: |
echo "🧪 Running Xcode tests..."
xcodebuild test -project ClickIt.xcodeproj -scheme ClickIt -destination 'platform=macOS' || echo "⚠️ No tests configured in Xcode project"

- name: 🏗️ Build App Bundle
run: |
echo "🔨 Building ${{ env.APP_NAME }} (${{ matrix.build_mode }} mode, ${{ matrix.build_system }} system)..."
if [ "${{ matrix.build_system }}" = "xcode" ]; then
# For Xcode builds in CI, disable code signing and set deployment target
export CODE_SIGN_IDENTITY=""
export CODE_SIGNING_REQUIRED=NO
export CODE_SIGNING_ALLOWED=NO
export MACOSX_DEPLOYMENT_TARGET=15.0
fi
./build_app_unified.sh ${{ matrix.build_mode }} ${{ matrix.build_system }}

echo "📋 Build completed!"
ls -la dist/

- name: 🔍 Verify Build Output
run: |
echo "🔍 Verifying build output..."

if [ -d "dist/${{ env.APP_NAME }}.app" ]; then
echo "✅ App bundle created successfully"

# Check app bundle structure
echo "📁 App bundle contents:"
find "dist/${{ env.APP_NAME }}.app" -type f | head -10

# Check binary architecture
BINARY_PATH="dist/${{ env.APP_NAME }}.app/Contents/MacOS/${{ env.APP_NAME }}"
if [ -f "$BINARY_PATH" ]; then
echo "📱 Binary info:"
file "$BINARY_PATH"
echo "🏗️ Architecture:"
lipo -info "$BINARY_PATH" 2>/dev/null || echo "Single architecture binary"
else
echo "❌ Binary not found at $BINARY_PATH"
exit 1
fi

# Check code signing status
echo "🔐 Code signing status:"
codesign -dv "dist/${{ env.APP_NAME }}.app" 2>&1 || echo "⚠️ Not code signed"

else
echo "❌ App bundle not found!"
exit 1
fi

- name: 📦 Upload Build Artifacts
if: matrix.build_mode == 'release'
uses: actions/upload-artifact@v4
with:
name: "${{ env.APP_NAME }}-${{ matrix.build_system }}-${{ github.sha }}"
path: |
dist/${{ env.APP_NAME }}.app
dist/build-info.txt
retention-days: 7

lint-and-quality:
name: 🔍 Code Quality & Linting
runs-on: macos-15

steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4

- name: 🔍 Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable

- name: 📊 Swift Package Dependencies
run: |
echo "📊 Checking Swift Package dependencies..."
swift package show-dependencies || echo "⚠️ No Package.swift or dependencies found"

- name: 🔒 Security Check (Basic)
run: |
echo "🔒 Basic security checks..."
echo "🔍 Checking for hardcoded secrets..."

# Check for common secret patterns (basic check)
if grep -r -i "password\|secret\|token\|key" --include="*.swift" Sources/ || true; then
echo "⚠️ Found potential secrets - please review manually"
else
echo "✅ No obvious secrets found in Swift source"
fi

echo "🔍 Checking for insecure HTTP URLs..."
if grep -r "http://" --include="*.swift" Sources/ || true; then
echo "⚠️ Found HTTP URLs - consider using HTTPS"
else
echo "✅ No insecure HTTP URLs found"
fi

summary:
name: 📋 CI Summary
runs-on: ubuntu-latest
needs: [build-test, lint-and-quality]
if: always()

steps:
- name: 📊 CI Results Summary
run: |
echo "## 📋 CI Pipeline Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Build & Test | ${{ needs.build-test.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Code Quality | ${{ needs.lint-and-quality.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

if [ "${{ needs.build-test.result }}" = "success" ] && [ "${{ needs.lint-and-quality.result }}" = "success" ]; then
echo "🎉 **All checks passed!** The code is ready for release." >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ **Some checks failed.** Please review the results above." >> $GITHUB_STEP_SUMMARY
fi

echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🚀 Next Steps" >> $GITHUB_STEP_SUMMARY
echo "- **For Release**: Create a version tag (e.g., \`git tag v1.3.0 && git push origin v1.3.0\`)" >> $GITHUB_STEP_SUMMARY
echo "- **For Development**: Merge to main branch when ready" >> $GITHUB_STEP_SUMMARY
8 changes: 0 additions & 8 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,6 @@ jobs:
fail_ci_if_error: false
continue-on-error: true

- name: 🔍 SwiftLint
run: |
if ! command -v swiftlint &> /dev/null; then
echo "Installing SwiftLint..."
brew install swiftlint
fi
swiftlint lint --strict --reporter github-actions-logging
echo "✅ Linting passed"

# === Build Tests ===
build_tests:
Expand Down
162 changes: 162 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
name: 🚀 Build and Release ClickIt

on:
push:
tags:
- 'v*' # Trigger on version tags like v1.3.0
workflow_dispatch: # Allow manual triggering
inputs:
tag:
description: 'Tag to build (e.g., v1.3.0)'
required: true
type: string

env:
APP_NAME: "ClickIt"
BUNDLE_ID: "com.jsonify.clickit"

jobs:
build-and-release:
name: 🔨 Build Universal App & Create Release
runs-on: macos-latest

steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for proper tagging

- name: 🔍 Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable

- name: 📋 Extract Version from Tag
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG_NAME="${{ github.event.inputs.tag }}"
else
TAG_NAME=${GITHUB_REF#refs/tags/}
fi
VERSION=${TAG_NAME#v} # Remove 'v' prefix
echo "tag=${TAG_NAME}" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "📦 Building version: ${VERSION} (tag: ${TAG_NAME})"

- name: 🔧 Update Version in Build Script
run: |
sed -i '' "s/VERSION=\"1.0.0\"/VERSION=\"${{ steps.version.outputs.version }}\"/" build_app_unified.sh
echo "✅ Updated version to ${{ steps.version.outputs.version }}"

- name: 🏗️ Build Universal App with Xcode
run: |
echo "🔨 Building ${{ env.APP_NAME }} with Xcode..."
./build_app_unified.sh release xcode

echo "📦 Creating release archive..."
cd dist
zip -r ${{ env.APP_NAME }}.app.zip ${{ env.APP_NAME }}.app
cd ..

echo "📋 Build completed successfully!"
ls -la dist/

- name: 🔍 Verify Build
run: |
echo "🔍 Verifying app bundle..."
if [ -d "dist/${{ env.APP_NAME }}.app" ]; then
echo "✅ App bundle created successfully"
ls -la "dist/${{ env.APP_NAME }}.app/Contents/"

# Check if binary exists and get architecture info
if [ -f "dist/${{ env.APP_NAME }}.app/Contents/MacOS/${{ env.APP_NAME }}" ]; then
echo "📱 Binary architecture:"
file "dist/${{ env.APP_NAME }}.app/Contents/MacOS/${{ env.APP_NAME }}"
fi
else
echo "❌ App bundle not found!"
exit 1
fi

if [ -f "dist/${{ env.APP_NAME }}.app.zip" ]; then
echo "✅ Archive created successfully"
ls -lh "dist/${{ env.APP_NAME }}.app.zip"
else
echo "❌ Archive not found!"
exit 1
fi

- name: 📝 Generate Release Notes
id: release_notes
run: |
TAG_NAME="${{ steps.version.outputs.tag }}"
VERSION="${{ steps.version.outputs.version }}"

# Get the previous tag for changelog
PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")

echo "# ${{ env.APP_NAME }} ${TAG_NAME}" > release_notes.md
echo "" >> release_notes.md
echo "🎉 **Native macOS Auto-Clicker Application**" >> release_notes.md
echo "" >> release_notes.md
echo "## ✨ Features" >> release_notes.md
echo "- 🖱️ **Precision Clicking**: Sub-10ms timing accuracy" >> release_notes.md
echo "- 🌐 **Universal Binary**: Native support for Intel x64 + Apple Silicon" >> release_notes.md
echo "- 🎯 **Background Operation**: Works without requiring app focus" >> release_notes.md
echo "- ⚡ **Global Hotkeys**: ESC key controls for instant stop" >> release_notes.md
echo "- 🔧 **Advanced Configuration**: CPS rates, click types, and presets" >> release_notes.md
echo "- 👁️ **Visual Feedback**: Real-time overlay indicators" >> release_notes.md
echo "- 🔄 **Auto-Updates**: Built-in Sparkle framework integration" >> release_notes.md
echo "" >> release_notes.md
echo "## 📋 System Requirements" >> release_notes.md
echo "- **macOS**: 15.0 or later" >> release_notes.md
echo "- **Architecture**: Universal Binary (Intel x64 + Apple Silicon)" >> release_notes.md
echo "- **Permissions**: Accessibility and Screen Recording access required" >> release_notes.md
echo "" >> release_notes.md
echo "## 🚀 Installation" >> release_notes.md
echo "1. Download \`${{ env.APP_NAME }}.app.zip\` below" >> release_notes.md
echo "2. Extract and move \`${{ env.APP_NAME }}.app\` to Applications folder" >> release_notes.md
echo "3. First launch: Right-click → Open (to bypass Gatekeeper)" >> release_notes.md
echo "4. Grant Accessibility and Screen Recording permissions when prompted" >> release_notes.md
echo "" >> release_notes.md

if [ -n "$PREVIOUS_TAG" ]; then
echo "## 📈 Changes Since ${PREVIOUS_TAG}" >> release_notes.md
echo "\`\`\`" >> release_notes.md
git log --oneline ${PREVIOUS_TAG}..HEAD --pretty=format:"- %s" >> release_notes.md || echo "- Initial release" >> release_notes.md
echo "" >> release_notes.md
echo "\`\`\`" >> release_notes.md
echo "" >> release_notes.md
fi

echo "---" >> release_notes.md
echo "" >> release_notes.md
echo "🏗️ **Built with**: Xcode on GitHub Actions" >> release_notes.md
echo "📅 **Build Date**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> release_notes.md
echo "🔖 **Version**: ${VERSION}" >> release_notes.md
echo "🎯 **Target**: macOS 15.0+" >> release_notes.md

echo "release_notes_file=release_notes.md" >> $GITHUB_OUTPUT

- name: 🚀 Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.version.outputs.tag }}
name: "${{ env.APP_NAME }} ${{ steps.version.outputs.tag }}"
body_path: release_notes.md
draft: false
prerelease: false
make_latest: true
files: |
dist/${{ env.APP_NAME }}.app.zip
dist/build-info.txt
token: ${{ secrets.GITHUB_TOKEN }}

- name: ✅ Release Complete
run: |
echo "🎉 Release ${{ steps.version.outputs.tag }} completed successfully!"
echo "📂 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ steps.version.outputs.tag }}"
echo "📦 Assets uploaded:"
echo " - ${{ env.APP_NAME }}.app.zip (Universal macOS App)"
echo " - build-info.txt (Build metadata)"
Loading