diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..bc82cd2 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,52 @@ +version: 2 +updates: + # GitHub Actions dependencies + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "ci" + include: "scope" + + # Swift Package Manager dependencies + - package-ecosystem: "swift" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "swift" + commit-message: + prefix: "deps" + include: "scope" + # Group all SPM dependency updates into a single PR + groups: + swift-dependencies: + patterns: + - "*" + + # NPM dependencies (for semantic-release if you add package.json) + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "npm" + commit-message: + prefix: "deps" + include: "scope" + ignore: + # Ignore major version updates for now + - dependency-name: "*" + update-types: ["version-update:semver-major"] diff --git a/.github/workflows/ExportOptions.plist b/.github/workflows/ExportOptions.plist new file mode 100644 index 0000000..9bfe209 --- /dev/null +++ b/.github/workflows/ExportOptions.plist @@ -0,0 +1,18 @@ + + + + + method + mac-application + signingStyle + manual + stripSwiftSymbols + + teamID + + uploadBitcode + + uploadSymbols + + + diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000..70cd41c --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,89 @@ +name: PR Checks + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +jobs: + pr-title-check: + name: Validate PR Title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Configure types according to conventional commits + types: | + feat + fix + docs + style + refactor + perf + test + build + ci + chore + revert + # Require a scope (optional, remove if you don't want to enforce scopes) + requireScope: false + # Configure subject pattern (default: require lowercase) + subjectPattern: ^(?![A-Z]).+$ + subjectPatternError: | + The subject "{subject}" found in the pull request title "{title}" + must start with a lowercase character. + + build-and-test: + name: Build and Test + runs-on: macos-14 # macOS 14 for backward compatibility (has Xcode 15.4 default, supports back to 15.0.1) + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Select Xcode version + run: sudo xcode-select -s /Applications/Xcode_15.4.app/Contents/Developer + + - name: Show Xcode version + run: xcodebuild -version + + - name: Restore Swift Package Cache + uses: actions/cache@v4 + with: + path: | + ~/Library/Developer/Xcode/DerivedData/**/SourcePackages + .build + key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }} + restore-keys: | + ${{ runner.os }}-spm- + + - name: Build Project + run: | + xcodebuild clean build \ + -project Kiwings.xcodeproj \ + -scheme Kiwings \ + -configuration Debug \ + -destination 'platform=macOS' \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + + - name: Run Tests + run: | + xcodebuild test \ + -project Kiwings.xcodeproj \ + -scheme Kiwings \ + -destination 'platform=macOS' \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + continue-on-error: true + + - name: Archive build artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: build-logs + path: | + ~/Library/Logs/DiagnosticReports + DerivedData/Logs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2e655b4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,161 @@ +name: Release + +on: + push: + branches: + - main + +jobs: + release: + name: Build and Release DMG + runs-on: macos-14 # macOS 14 for backward compatibility (has Xcode 15.4 default, supports back to 15.0.1) + if: "!contains(github.event.head_commit.message, 'skip ci')" + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Select Xcode version + run: sudo xcode-select -s /Applications/Xcode_15.4.app/Contents/Developer + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install semantic-release + run: | + npm install -g \ + semantic-release \ + @semantic-release/git \ + @semantic-release/changelog \ + @semantic-release/exec \ + conventional-changelog-conventionalcommits + + - name: Determine next version + id: version + run: | + npx semantic-release --dry-run --no-ci + VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.1.0") + VERSION=${VERSION#v} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Next version: $VERSION" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Update version in project + run: | + VERSION="${{ steps.version.outputs.version }}" + # Update Info.plist with new version + /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" "Kiwings/Info.plist" || true + /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $VERSION" "Kiwings/Info.plist" || true + + - name: Restore Swift Package Cache + uses: actions/cache@v4 + with: + path: | + ~/Library/Developer/Xcode/DerivedData/**/SourcePackages + .build + key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }} + restore-keys: | + ${{ runner.os }}-spm- + + - name: Build Release + run: | + xcodebuild clean archive \ + -project Kiwings.xcodeproj \ + -scheme Kiwings \ + -configuration Release \ + -archivePath ./build/Kiwings.xcarchive \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + + - name: Export App + run: | + xcodebuild -exportArchive \ + -archivePath ./build/Kiwings.xcarchive \ + -exportPath ./build/Release \ + -exportOptionsPlist .github/workflows/ExportOptions.plist + + - name: Create DMG + run: | + VERSION="${{ steps.version.outputs.version }}" + + # Create a temporary directory for DMG contents + mkdir -p dmg_temp + cp -R ./build/Release/Kiwings.app dmg_temp/ + + # Create Applications symlink + ln -s /Applications dmg_temp/Applications + + # Create DMG + hdiutil create -volname "Kiwings" \ + -srcfolder dmg_temp \ + -ov -format UDZO \ + "Kiwings-${VERSION}.dmg" + + echo "dmg_path=Kiwings-${VERSION}.dmg" >> $GITHUB_ENV + + - name: Calculate checksums + run: | + shasum -a 256 "${{ env.dmg_path }}" > "${{ env.dmg_path }}.sha256" + cat "${{ env.dmg_path }}.sha256" + + - name: Create Release Notes + id: release_notes + run: | + VERSION="${{ steps.version.outputs.version }}" + cat > release_notes.md << 'EOF' + ## Installation + + 1. Download the DMG file below + 2. Open the DMG file + 3. Drag Kiwings.app to your Applications folder + 4. Launch Kiwings from your Applications folder + + ## Checksums + + SHA-256: `$(cat ${{ env.dmg_path }}.sha256 | awk '{print $1}')` + + --- + + EOF + + # Add changelog if it exists + if [ -f CHANGELOG.md ]; then + echo "## Changes in this version" >> release_notes.md + echo "" >> release_notes.md + # Extract latest version changes from CHANGELOG + sed -n "/## \[${VERSION}\]/,/## \[/p" CHANGELOG.md | sed '$d' >> release_notes.md || true + fi + + - name: Semantic Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npx semantic-release + + - name: Upload DMG to Release + if: steps.version.outputs.version != '' + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ steps.version.outputs.version }} + files: | + ${{ env.dmg_path }} + ${{ env.dmg_path }}.sha256 + body_path: release_notes.md + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: Kiwings-${{ steps.version.outputs.version }} + path: | + ${{ env.dmg_path }} + ${{ env.dmg_path }}.sha256 diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..da9507c --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,79 @@ +{ + "branches": ["main"], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "releaseRules": [ + { "type": "feat", "release": "minor" }, + { "type": "fix", "release": "patch" }, + { "type": "perf", "release": "patch" }, + { "type": "revert", "release": "patch" }, + { "type": "docs", "release": "patch" }, + { "type": "chore", "release": false }, + { "type": "refactor", "release": "patch" }, + { "type": "test", "release": false }, + { "type": "build", "release": false }, + { "type": "ci", "release": false }, + { "breaking": true, "release": "major" } + ] + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "presetConfig": { + "types": [ + { "type": "feat", "section": "Features" }, + { "type": "fix", "section": "Bug Fixes" }, + { "type": "perf", "section": "Performance Improvements" }, + { "type": "revert", "section": "Reverts" }, + { "type": "docs", "section": "Documentation" }, + { "type": "style", "section": "Styles" }, + { "type": "refactor", "section": "Code Refactoring" }, + { "type": "test", "section": "Tests", "hidden": true }, + { "type": "build", "section": "Build System", "hidden": true }, + { "type": "ci", "section": "CI/CD", "hidden": true }, + { "type": "chore", "section": "Chores", "hidden": true } + ] + } + } + ], + [ + "@semantic-release/changelog", + { + "changelogFile": "CHANGELOG.md" + } + ], + [ + "@semantic-release/exec", + { + "prepareCmd": "echo ${nextRelease.version} > VERSION" + } + ], + [ + "@semantic-release/git", + { + "assets": ["CHANGELOG.md", "VERSION", "Kiwings/Info.plist"], + "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + } + ], + [ + "@semantic-release/github", + { + "assets": [ + { + "path": "Kiwings-*.dmg", + "label": "Kiwings DMG (macOS)" + }, + { + "path": "Kiwings-*.dmg.sha256", + "label": "SHA-256 Checksum" + } + ] + } + ] + ] +}