diff --git a/.github/RELEASE_WORKFLOW.md b/.github/RELEASE_WORKFLOW.md new file mode 100644 index 0000000..0719b9a --- /dev/null +++ b/.github/RELEASE_WORKFLOW.md @@ -0,0 +1,348 @@ +# ๐Ÿš€ Automated APK Release Workflow + +This repository includes an advanced GitHub Actions workflow that automatically builds and releases signed APK files when specific conditions are met. This documentation covers setup, usage, and customization. + +## ๐Ÿ“‹ Table of Contents + +- [Overview](#overview) +- [Features](#features) +- [Prerequisites](#prerequisites) +- [Setup Instructions](#setup-instructions) +- [Usage](#usage) +- [Secrets Configuration](#secrets-configuration) +- [Version Management](#version-management) +- [Troubleshooting](#troubleshooting) +- [Customization](#customization) + +## ๐Ÿ” Overview + +The **Automated APK Release** workflow triggers when a Pull Request with specific criteria is merged to the `main` branch. It automatically: + +1. **Detects release triggers** (labels or title patterns) +2. **Determines version bump type** (major/minor/patch) +3. **Updates version numbers** in multiple files +4. **Builds a signed release APK** +5. **Creates a GitHub release** with comprehensive notes +6. **Uploads the APK** as a release asset + +## โœจ Features + +### ๐ŸŽฏ Smart Release Detection + +- **Label-based triggers**: Add `release` label to PR +- **Title-based triggers**: Include `[release]` in PR title +- **Automatic version bumping**: Based on commit messages and PR titles + +### ๐Ÿ“ˆ Intelligent Version Management + +- **Major bump**: `[major]` or `BREAKING CHANGE` in title +- **Minor bump**: `[minor]`, `feat`, or `feature` in title +- **Patch bump**: Default for bug fixes and small changes + +### ๐Ÿ” Security Features + +- **Signed APK builds** using your release keystore +- **Secure secret handling** with GitHub Secrets +- **Automatic cleanup** of sensitive files + +### ๐Ÿ“ Comprehensive Release Notes + +- **Auto-generated notes** from PR description +- **Version comparison** and technical details +- **Installation instructions** for end users +- **Build metadata** and checksums + +## ๐Ÿ› ๏ธ Prerequisites + +Before setting up the workflow, ensure you have: + +1. **Android keystore file** for signing releases +2. **GitHub repository** with admin access +3. **React Native project** with Android build configuration +4. **Node.js and npm** properly configured + +## ๐Ÿš€ Setup Instructions + +### Step 1: Prepare Your Keystore + +If you don't have a release keystore, create one: + +```bash +# Navigate to your Android project +cd android/app + +# Generate a new keystore (replace with your details) +keytool -genkeypair -v -storetype PKCS12 -keystore release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-key-alias + +# Convert keystore to base64 for GitHub Secrets +base64 -i release-key.jks -o release-key-base64.txt +``` + +### Step 2: Configure GitHub Secrets + +Add these secrets to your GitHub repository (`Settings > Secrets and variables > Actions`): + +| Secret Name | Description | Example | +| ------------------------- | ---------------------------- | ------------------------ | +| `RELEASE_KEYSTORE_BASE64` | Base64 encoded keystore file | `MIIFXTCCBEWgAwIBAgI...` | +| `RELEASE_STORE_PASSWORD` | Keystore password | `your-store-password` | +| `RELEASE_KEY_ALIAS` | Key alias name | `my-key-alias` | +| `RELEASE_KEY_PASSWORD` | Key password | `your-key-password` | + +### Step 3: Update Build Configuration + +Ensure your `android/app/build.gradle` has the signing configuration: + +```gradle +android { + // ... other configuration + + signingConfigs { + release { + storeFile file('../../keystore.properties') ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + } + } + + buildTypes { + release { + signingConfig signingConfigs.release + minifyEnabled false + shrinkResources false + } + } +} +``` + +### Step 4: Add the Workflow File + +The workflow file `release-apk.yml` should be placed in `.github/workflows/` directory (already created if you're reading this). + +## ๐ŸŽฎ Usage + +### Triggering a Release + +There are two ways to trigger an automated release: + +#### Method 1: Using Labels + +1. Create a Pull Request with your changes +2. Add the `release` label to the PR +3. Merge the PR to `main` branch +4. The workflow will automatically trigger + +#### Method 2: Using Title Patterns + +1. Create a Pull Request with `[release]` in the title +2. Example: `[release] Add new attendance tracking feature` +3. Merge the PR to `main` branch + +### Version Bump Control + +Control the version increment by including specific keywords in your PR title: + +- **Major version bump**: Include `[major]` or `BREAKING CHANGE` + - `1.0.3` โ†’ `2.0.0` + - Example: `[release][major] Complete UI redesign with breaking changes` + +- **Minor version bump**: Include `[minor]`, `feat`, or `feature` + - `1.0.3` โ†’ `1.1.0` + - Example: `[release] feat: Add new QR code sharing feature` + +- **Patch version bump**: Default behavior + - `1.0.3` โ†’ `1.0.4` + - Example: `[release] Fix attendance calculation bug` + +## ๐Ÿ” Secrets Configuration + +### Required Secrets + +| Secret | Purpose | How to Get | +| ------------------------- | ------------------ | ----------------------------------------- | +| `RELEASE_KEYSTORE_BASE64` | App signing | Convert your `.jks` file to base64 | +| `RELEASE_STORE_PASSWORD` | Keystore access | Password you set when creating keystore | +| `RELEASE_KEY_ALIAS` | Key identification | Alias you specified during key generation | +| `RELEASE_KEY_PASSWORD` | Key access | Password for the specific key alias | + +### Security Best Practices + +1. **Never commit** keystore files to your repository +2. **Use strong passwords** for keystore and key +3. **Backup your keystore** securely (losing it means you can't update your app) +4. **Rotate secrets** periodically +5. **Limit repository access** to trusted contributors + +## ๐Ÿ“‹ Version Management + +### Automatic Updates + +The workflow automatically updates version numbers in: + +1. **package.json**: `version` field +2. **android/app/build.gradle**: `versionName` and `versionCode` + +### Version Components + +- **versionName**: Semantic version (e.g., "1.2.3") +- **versionCode**: Integer that increments with each build +- **Git tag**: Created automatically (e.g., "v1.2.3") + +### Manual Version Control + +If you need to manually set a version: + +```bash +# Update package.json +npm version 1.5.0 --no-git-tag-version + +# Update Android build.gradle +# Edit versionName and versionCode manually +``` + +## ๐Ÿ”ง Troubleshooting + +### Common Issues + +#### 1. Build Failure: "Keystore not found" + +**Solution**: Verify your `RELEASE_KEYSTORE_BASE64` secret is correctly set. + +```bash +# Regenerate base64 keystore +base64 -i your-keystore.jks | tr -d '\n' > keystore-base64.txt +``` + +#### 2. Build Failure: "Signing failed" + +**Solution**: Check keystore password and alias secrets. + +#### 3. Version Update Failure + +**Solution**: Ensure the workflow has write permissions to the repository. + +#### 4. APK Not Signed + +**Solution**: Verify signing configuration in `build.gradle`. + +### Debug Mode + +Enable debug logging by adding this to your workflow: + +```yaml +- name: Debug Information + run: | + echo "Current directory: $(pwd)" + echo "Android files: $(ls -la android/)" + echo "Gradle version: $(cd android && ./gradlew --version)" +``` + +## ๐ŸŽจ Customization + +### Modify Release Triggers + +Edit the trigger conditions in the workflow: + +```yaml +# Add custom triggers +- name: Check Release Trigger + run: | + # Your custom logic here + if [[ "$TITLE" == *"[deploy]"* ]]; then + SHOULD_RELEASE=true + fi +``` + +### Custom Release Notes + +Modify the release notes template: + +```yaml +- name: Generate Release Notes + run: | + cat > release-notes.md << EOF + ## Your Custom Release Notes Template + ### Changes + ${{ github.event.pull_request.body }} + EOF +``` + +### Add Slack/Discord Notifications + +```yaml +- name: Notify Success + uses: 8398a7/action-slack@v3 + with: + status: success + text: '๐ŸŽ‰ New release v${{ steps.new-version.outputs.new }} is available!' + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} +``` + +### Multiple APK Variants + +Build different APK variants: + +```yaml +- name: Build Multiple Variants + run: | + cd android + ./gradlew assembleRelease + ./gradlew assembleDebug +``` + +## ๐Ÿ“ฑ End-User Instructions + +When a release is created, users can: + +1. **Download the APK** from the GitHub Releases page +2. **Enable "Install from Unknown Sources"** on their Android device +3. **Install the APK** directly +4. **Check the release notes** for new features and changes + +## ๐Ÿ”„ Workflow Lifecycle + +```mermaid +graph TD + A[PR Created] --> B{Contains release trigger?} + B -->|No| C[Normal PR workflow] + B -->|Yes| D[PR Merged?] + D -->|No| C + D -->|Yes| E[Check version bump type] + E --> F[Update version numbers] + F --> G[Build signed APK] + G --> H[Create Git tag] + H --> I[Create GitHub release] + I --> J[Upload APK asset] + J --> K[Cleanup sensitive files] +``` + +## ๐Ÿค Contributing + +To improve this workflow: + +1. **Test changes** in a fork first +2. **Document modifications** clearly +3. **Follow security best practices** +4. **Submit a PR** with detailed description + +## ๐Ÿ“ž Support + +If you encounter issues: + +1. **Check the workflow logs** in GitHub Actions +2. **Review this documentation** for common solutions +3. **Create an issue** with detailed error information +4. **Tag maintainers** for faster response + +--- + +**โš ๏ธ Important Notes:** + +- This workflow has **write access** to your repository +- **Backup your keystore** before implementing +- **Test thoroughly** in a development environment first +- **Keep secrets secure** and rotate them regularly + +**โœจ Happy Releasing!** ๐Ÿš€ diff --git a/.github/SECRETS_SETUP.md b/.github/SECRETS_SETUP.md new file mode 100644 index 0000000..b4db334 --- /dev/null +++ b/.github/SECRETS_SETUP.md @@ -0,0 +1,123 @@ +# ๐Ÿ” GitHub Secrets Setup Guide + +This guide helps you set up the required GitHub Secrets for the automated APK release workflow. + +## ๐Ÿ“‹ Required Secrets + +You need to add these 4 secrets to your GitHub repository: + +| Secret Name | Description | +| ------------------------- | -------------------------------------------- | +| `RELEASE_KEYSTORE_BASE64` | Your Android keystore file encoded in base64 | +| `RELEASE_STORE_PASSWORD` | Password for the keystore file | +| `RELEASE_KEY_ALIAS` | Alias name of the key in the keystore | +| `RELEASE_KEY_PASSWORD` | Password for the specific key alias | + +## ๐Ÿš€ Quick Setup Steps + +### Step 1: Access Repository Secrets + +1. Go to your GitHub repository +2. Click on **Settings** tab +3. In the left sidebar, click **Secrets and variables** โ†’ **Actions** +4. Click **New repository secret** + +### Step 2: Convert Keystore to Base64 + +If you already have a keystore file (`my-release-key.jks` or similar): + +```bash +# On Linux/MacOS +base64 -i android/app/my-release-key.jks | tr -d '\n' > keystore-base64.txt + +# On Windows (PowerShell) +[Convert]::ToBase64String([IO.File]::ReadAllBytes("android\app\my-release-key.jks")) > keystore-base64.txt +``` + +### Step 3: Add Each Secret + +Add these secrets one by one: + +#### 1. RELEASE_KEYSTORE_BASE64 + +- **Name**: `RELEASE_KEYSTORE_BASE64` +- **Value**: Content of the `keystore-base64.txt` file (long string) + +#### 2. RELEASE_STORE_PASSWORD + +- **Name**: `RELEASE_STORE_PASSWORD` +- **Value**: Your keystore password (e.g., `your-secure-password`) + +#### 3. RELEASE_KEY_ALIAS + +- **Name**: `RELEASE_KEY_ALIAS` +- **Value**: Your key alias (e.g., `my-key-alias`) + +#### 4. RELEASE_KEY_PASSWORD + +- **Name**: `RELEASE_KEY_PASSWORD` +- **Value**: Your key password (often same as store password) + +## ๐Ÿ”‘ Don't Have a Keystore? Create One! + +If you don't have a release keystore yet: + +```bash +# Navigate to your Android app directory +cd android/app + +# Generate a new keystore (replace values with your details) +keytool -genkeypair -v -storetype PKCS12 \ + -keystore my-release-key.jks \ + -keyalg RSA -keysize 2048 -validity 10000 \ + -alias my-key-alias \ + -dname "CN=Your Name, OU=YourApp, O=YourCompany, L=YourCity, S=YourState, C=YourCountry" + +# You'll be prompted for passwords - remember them! +``` + +**Important**: + +- Use strong passwords +- Store the keystore file safely (backup it!) +- Never lose this keystore - you can't update your app without it + +## โœ… Verification + +After adding all secrets, you should see 4 secrets in your repository settings: + +- โœ… RELEASE_KEYSTORE_BASE64 +- โœ… RELEASE_STORE_PASSWORD +- โœ… RELEASE_KEY_ALIAS +- โœ… RELEASE_KEY_PASSWORD + +## ๐Ÿ”ง Testing the Setup + +Create a test PR with `[release]` in the title and merge it to test if the workflow works correctly. + +## ๐Ÿšจ Security Notes + +- **Never commit** keystore files to your repository +- **Keep passwords secure** and don't share them +- **Backup your keystore** - losing it means you can't update your published app +- **Use different passwords** for store and key if possible + +## ๐Ÿ†˜ Need Help? + +If you encounter issues: + +1. Check that all 4 secrets are correctly named +2. Verify your keystore works locally first +3. Look at the GitHub Actions logs for specific error messages +4. Create an issue with the error details + +--- + +๐Ÿ’ก **Pro Tip**: You can test your keystore locally before adding it to GitHub: + +```bash +cd android +./gradlew assembleRelease +``` + +If this works, your keystore setup is correct! ๐ŸŽ‰ diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..c4ba702 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,82 @@ +# ๐Ÿ“ GitHub Workflows & Automation + +This directory contains automated workflows and documentation for the ScheduleX project. + +## ๐Ÿš€ Available Workflows + +### 1. **Automated APK Release** (`release-apk.yml`) + +Automatically builds and releases signed APK files when PRs with release triggers are merged. + +**Triggers:** + +- PR with `release` label merged to main +- PR with `[release]` in title merged to main +- Adding `release` label to an already-merged PR โœจ + +**Features:** + +- ๐Ÿ”„ Smart version bumping (major/minor/patch) +- ๐Ÿ” Signed APK builds +- ๐Ÿ“ Auto-generated release notes +- ๐Ÿท๏ธ Git tagging +- ๐Ÿ“ฑ GitHub Releases integration +- ๐Ÿ”„ Re-triggerable by adding labels to closed PRs +- ๐Ÿšซ Duplicate release prevention + +### 2. **Welcome Workflow** (`welcome.yml`) + +Welcomes new contributors and provides guidance. + +## ๐Ÿ“š Documentation + +| File | Description | +| -------------------------------------------- | ----------------------------------------------- | +| [`RELEASE_WORKFLOW.md`](RELEASE_WORKFLOW.md) | Complete guide for the automated release system | +| [`SECRETS_SETUP.md`](SECRETS_SETUP.md) | Quick setup guide for GitHub Secrets | + +## ๐Ÿš€ Quick Start for Releases + +1. **Setup Secrets** (one-time setup) + - Follow [`SECRETS_SETUP.md`](SECRETS_SETUP.md) + - Add 4 required secrets to your repository + +2. **Create Release PR** + - Add `release` label OR `[release]` in title + - Include version bump hints: `[major]`, `[minor]`, or leave for patch + +3. **Merge to Main** + - Workflow automatically triggers + - APK gets built and released + - Version gets updated across files + +4. **Re-trigger Releases** โœจ + - Add `release` label to any already-merged PR + - Workflow will re-run if no existing release found + - Duplicate releases are automatically prevented + +## ๐ŸŽฏ Version Bump Examples + +| PR Title | Version Change | +| ------------------------------------ | ------------------------- | +| `[release] Fix attendance bug` | `1.0.3` โ†’ `1.0.4` (patch) | +| `[release][minor] Add QR sharing` | `1.0.3` โ†’ `1.1.0` (minor) | +| `[release][major] Complete redesign` | `1.0.3` โ†’ `2.0.0` (major) | + +## ๐Ÿ”ง Current Project Status + +- โœ… Release workflow configured +- โœ… Signing setup ready +- โœ… Documentation complete +- โณ Secrets need to be added (see [SECRETS_SETUP.md](SECRETS_SETUP.md)) + +## ๐Ÿ†˜ Need Help? + +1. **For secrets setup**: Check [`SECRETS_SETUP.md`](SECRETS_SETUP.md) +2. **For workflow details**: Read [`RELEASE_WORKFLOW.md`](RELEASE_WORKFLOW.md) +3. **For issues**: Create a GitHub issue with details +4. **For questions**: Tag maintainers @anisharma07 or @Irtesaam + +--- + +๐ŸŽ‰ **Ready to automate your releases?** Follow the setup guides above! diff --git a/.github/workflows/release-apk.yml b/.github/workflows/release-apk.yml new file mode 100644 index 0000000..0557639 --- /dev/null +++ b/.github/workflows/release-apk.yml @@ -0,0 +1,337 @@ +name: ๐Ÿš€ Automated APK Release + +on: + pull_request: + types: [closed, labeled] + branches: [main] + +permissions: + contents: write # For pushing commits and tags + pull-requests: read # For reading PR information + +jobs: + check-release-trigger: + if: github.event.pull_request.merged == true || (github.event.action == 'labeled' && github.event.pull_request.merged == true) + runs-on: ubuntu-latest + outputs: + should-release: ${{ steps.check.outputs.should-release }} + version-bump: ${{ steps.check.outputs.version-bump }} + release-notes: ${{ steps.check.outputs.release-notes }} + steps: + - name: Check Release Trigger + id: check + run: | + # Check if PR has release label or [release] in title + LABELS="${{ join(github.event.pull_request.labels.*.name, ' ') }}" + TITLE="${{ github.event.pull_request.title }}" + PR_BODY="${{ github.event.pull_request.body }}" + ACTION="${{ github.event.action }}" + + echo "Action: $ACTION" + echo "Checking labels: $LABELS" + echo "Checking title: $TITLE" + echo "PR merged: ${{ github.event.pull_request.merged }}" # Determine version bump type from commit messages and PR title + VERSION_BUMP="patch" + if [[ "$TITLE" == *"[major]"* ]] || [[ "$TITLE" == *"BREAKING CHANGE"* ]]; then + VERSION_BUMP="major" + elif [[ "$TITLE" == *"[minor]"* ]] || [[ "$TITLE" == *"feat"* ]] || [[ "$TITLE" == *"feature"* ]]; then + VERSION_BUMP="minor" + fi + + # Check if should release + SHOULD_RELEASE=false + if [[ "$LABELS" == *"release"* ]] || [[ "$TITLE" == *"[release]"* ]]; then + SHOULD_RELEASE=true + fi + + # Special handling for label events - check if release label was just added + if [[ "$ACTION" == "labeled" ]]; then + ADDED_LABEL="${{ github.event.label.name }}" + echo "Label added: $ADDED_LABEL" + if [[ "$ADDED_LABEL" != "release" ]]; then + echo "Label '$ADDED_LABEL' is not a release trigger, skipping..." + SHOULD_RELEASE=false + fi + fi + + # Prepare release notes from PR body + RELEASE_NOTES=$(echo "$PR_BODY" | head -n 20) + + echo "should-release=$SHOULD_RELEASE" >> $GITHUB_OUTPUT + echo "version-bump=$VERSION_BUMP" >> $GITHUB_OUTPUT + echo "release-notes<> $GITHUB_OUTPUT + echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + build-and-release: + needs: check-release-trigger + if: needs.check-release-trigger.outputs.should-release == 'true' + runs-on: ubuntu-latest + + steps: + - name: ๐Ÿ—๏ธ Checkout Repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: ๐Ÿ” Check for Existing Release + id: check-existing + run: | + # Get current version first + CURRENT_VERSION=$(node -p "require('./package.json').version") + BUMP_TYPE="${{ needs.check-release-trigger.outputs.version-bump }}" + + # Parse current version + IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_VERSION" + MAJOR=${VERSION_PARTS[0]} + MINOR=${VERSION_PARTS[1]} + PATCH=${VERSION_PARTS[2]} + + # Calculate new version + case $BUMP_TYPE 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}" + + # Check if tag already exists + if git rev-parse "v$NEW_VERSION" >/dev/null 2>&1; then + echo "โš ๏ธ Tag v$NEW_VERSION already exists!" + echo "existing=true" >> $GITHUB_OUTPUT + + # Check if GitHub release exists + RELEASE_EXISTS=$(gh release view "v$NEW_VERSION" >/dev/null 2>&1 && echo "true" || echo "false") + echo "github-release-exists=$RELEASE_EXISTS" >> $GITHUB_OUTPUT + echo "skip-build=true" >> $GITHUB_OUTPUT + else + echo "โœ… No existing release found for v$NEW_VERSION" + echo "existing=false" >> $GITHUB_OUTPUT + echo "github-release-exists=false" >> $GITHUB_OUTPUT + echo "skip-build=false" >> $GITHUB_OUTPUT + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: ๐Ÿ”ง Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + + - name: โ˜• Setup Java JDK + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + + - name: ๐Ÿ” Get Current Version + id: current-version + run: | + CURRENT_VERSION=$(node -p "require('./package.json').version") + echo "current=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "Current version: $CURRENT_VERSION" + + - name: ๐Ÿ“ˆ Calculate New Version + id: new-version + run: | + CURRENT="${{ steps.current-version.outputs.current }}" + BUMP_TYPE="${{ needs.check-release-trigger.outputs.version-bump }}" + + # Parse current version + IFS='.' read -ra VERSION_PARTS <<< "$CURRENT" + MAJOR=${VERSION_PARTS[0]} + MINOR=${VERSION_PARTS[1]} + PATCH=${VERSION_PARTS[2]} + + # Calculate new version based on bump type + case $BUMP_TYPE 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 "new=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "New version: $NEW_VERSION" + + - name: ๐Ÿ“ Update Version in Files + run: | + NEW_VERSION="${{ steps.new-version.outputs.new }}" + + # Update package.json + npm version $NEW_VERSION --no-git-tag-version + + # Update Android versionName and versionCode + VERSION_CODE=$(grep "versionCode" android/app/build.gradle | grep -o '[0-9]\+') + NEW_VERSION_CODE=$((VERSION_CODE + 1)) + + sed -i "s/versionCode $VERSION_CODE/versionCode $NEW_VERSION_CODE/" android/app/build.gradle + sed -i "s/versionName \".*\"/versionName \"$NEW_VERSION\"/" android/app/build.gradle + + echo "Updated version to $NEW_VERSION (code: $NEW_VERSION_CODE)" + + - name: ๐Ÿ“ฆ Install Dependencies + if: steps.check-existing.outputs.skip-build == 'false' + run: | + npm ci + npm ls # List installed packages for debugging + + - name: โš ๏ธ Release Already Exists + if: steps.check-existing.outputs.skip-build == 'true' + run: | + echo "## โš ๏ธ Release Already Exists" + echo "A release for this version already exists. Skipping build to prevent duplicates." + echo "If you need to rebuild, please:" + echo "1. Delete the existing tag and release, OR" + echo "2. Increment the version manually and re-trigger" + + - name: ๐Ÿ”‘ Setup Keystore + if: steps.check-existing.outputs.skip-build == 'false' + run: | + # Create keystore from secrets + echo "${{ secrets.RELEASE_KEYSTORE_BASE64 }}" | base64 -d > android/app/release-key.jks + + # Create keystore.properties + cat > android/keystore.properties << EOF + storeFile=release-key.jks + storePassword=${{ secrets.RELEASE_STORE_PASSWORD }} + keyAlias=${{ secrets.RELEASE_KEY_ALIAS }} + keyPassword=${{ secrets.RELEASE_KEY_PASSWORD }} + EOF + + - name: ๐Ÿ”จ Build Release APK + run: | + cd android + chmod +x gradlew + ./gradlew clean + ./gradlew assembleRelease --stacktrace + + # Verify APK was created + if [ ! -f "app/build/outputs/apk/release/app-release.apk" ]; then + echo "โŒ APK build failed!" + exit 1 + fi + + # Rename APK with version + NEW_VERSION="${{ steps.new-version.outputs.new }}" + cp app/build/outputs/apk/release/app-release.apk app/build/outputs/apk/release/ScheduleX-v${NEW_VERSION}.apk + + # Get APK info + APK_SIZE=$(du -h app/build/outputs/apk/release/ScheduleX-v${NEW_VERSION}.apk | cut -f1) + echo "โœ… APK built successfully! Size: $APK_SIZE" + + - name: ๐Ÿท๏ธ Create Git Tag + run: | + NEW_VERSION="${{ steps.new-version.outputs.new }}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git add package.json android/app/build.gradle + git commit -m "๐Ÿ”– Release version v$NEW_VERSION" + git tag -a "v$NEW_VERSION" -m "Release version v$NEW_VERSION" + git push origin main + git push origin "v$NEW_VERSION" + + - name: ๐Ÿ“ Generate Release Notes + id: release-notes + run: | + NEW_VERSION="${{ steps.new-version.outputs.new }}" + CURRENT_VERSION="${{ steps.current-version.outputs.current }}" + + # Create comprehensive release notes + cat > release-notes.md << EOF + ## ๐Ÿš€ What's New in v$NEW_VERSION + + ### ๐Ÿ“‹ Changes from PR #${{ github.event.pull_request.number }} + **${{ github.event.pull_request.title }}** + + ${{ needs.check-release-trigger.outputs.release-notes }} + + ### ๐Ÿ“Š Release Information + - **Previous Version:** v$CURRENT_VERSION + - **New Version:** v$NEW_VERSION + - **Version Bump:** ${{ needs.check-release-trigger.outputs.version-bump }} + - **Build Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") + - **Commit SHA:** ${{ github.sha }} + + ### ๐Ÿ’ป Installation + 1. Download the APK file below + 2. Enable "Install from Unknown Sources" in Android settings + 3. Install the APK on your device + + ### ๐Ÿ”ง Technical Details + - **Min SDK:** 21 (Android 5.0) + - **Target SDK:** 34 (Android 14) + - **Architecture:** Universal APK + - **Signed:** Yes โœ… + + --- + *This release was automatically generated by GitHub Actions* + EOF + + echo "Release notes generated successfully" + + - name: ๐ŸŽ‰ Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ steps.new-version.outputs.new }} + name: ๐Ÿš€ ScheduleX v${{ steps.new-version.outputs.new }} + body_path: release-notes.md + files: | + android/app/build/outputs/apk/release/ScheduleX-v${{ steps.new-version.outputs.new }}.apk + draft: false + prerelease: false + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: ๐Ÿงน Cleanup + if: always() + run: | + # Remove sensitive files + rm -f android/app/release-key.jks + rm -f android/keystore.properties + echo "๐Ÿงน Cleanup completed" + + - name: ๐Ÿ“ฑ Post-Release Summary + run: | + NEW_VERSION="${{ steps.new-version.outputs.new }}" + APK_PATH="android/app/build/outputs/apk/release/ScheduleX-v${NEW_VERSION}.apk" + APK_SIZE=$(du -h "$APK_PATH" | cut -f1) + + echo "## ๐ŸŽ‰ Release Summary" + echo "โœ… **Version:** v$NEW_VERSION" + echo "โœ… **APK Size:** $APK_SIZE" + echo "โœ… **Release URL:** ${{ github.server_url }}/${{ github.repository }}/releases/tag/v$NEW_VERSION" + echo "โœ… **Status:** Successfully Released!" + + notify-failure: + needs: [check-release-trigger, build-and-release] + if: failure() && needs.check-release-trigger.outputs.should-release == 'true' + runs-on: ubuntu-latest + steps: + - name: ๐Ÿ“ข Notify Build Failure + run: | + echo "โŒ Release build failed for PR #${{ github.event.pull_request.number }}" + echo "Please check the workflow logs and fix the issues." diff --git a/.github/workflows/welcome.yml b/.github/workflows/welcome.yml deleted file mode 100644 index e69de29..0000000 diff --git a/.gitignore b/.gitignore index 6429efd..ffa7be6 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,12 @@ android/app/google-services.json android/keystore.properties android/app/my-release-key.jks +# Keystore files (NEVER commit these!) +keystore-base64.txt +*.keystore +*.jks +android/app/release-key.jks + # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the