diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c700014 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +name: CI + +on: + push: + branches: [ master, main, develop ] + pull_request: + branches: [ master, main, develop ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Cache Gradle packages + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Run tests + run: ./gradlew test --stacktrace + + - name: Build Debug APK + run: ./gradlew assembleDebug --stacktrace + + - name: Upload Debug APK + if: github.event_name == 'push' + uses: actions/upload-artifact@v4 + with: + name: Debug-APK + path: app/build/outputs/apk/debug/*.apk + retention-days: 7 \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ba0c5a5 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,91 @@ +name: Build and Release APK + +on: + push: + tags: + - 'v*' + branches: + - 'release/*' + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Cache Gradle packages + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Build Release APK + run: ./gradlew assembleRelease --stacktrace + + - name: Verify APK was built + run: | + if [ ! -f app/build/outputs/apk/release/*.apk ]; then + echo "No APK found in release directory" + ls -la app/build/outputs/apk/release/ || echo "Release directory does not exist" + exit 1 + fi + + - name: Get APK path + id: apk-path + run: | + APK_PATH=$(find app/build/outputs/apk/release -name '*.apk' | head -1) + echo "APK found at: $APK_PATH" + echo "path=$APK_PATH" >> $GITHUB_OUTPUT + + - name: Get version name + id: version + run: | + VERSION_NAME=$(grep 'versionName' app/build.gradle | sed 's/.*versionName "\(.*\)".*/\1/') + echo "name=$VERSION_NAME" >> $GITHUB_OUTPUT + + - name: Upload APK to existing Release + if: github.event_name == 'release' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload ${{ github.event.release.tag_name }} "${{ steps.apk-path.outputs.path }}" --clobber + + - name: Create Release and Upload APK (for tag pushes) + if: startsWith(github.ref, 'refs/tags/') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create ${{ github.ref_name }} \ + --title "Release ${{ github.ref_name }}" \ + --notes "Automatic release for version ${{ github.ref_name }} + + ## Changes + - Android APK build for release" \ + "${{ steps.apk-path.outputs.path }}#Numer-${{ steps.version.outputs.name }}.apk" + + - name: Upload APK as Artifact + uses: actions/upload-artifact@v4 + with: + name: Numer-APK-${{ steps.version.outputs.name }} + path: ${{ steps.apk-path.outputs.path }} + retention-days: 30 \ No newline at end of file diff --git a/README.md b/README.md index 6c3dbe0..3c40c68 100644 --- a/README.md +++ b/README.md @@ -1 +1,44 @@ -### Fastest zero abstraction number conversion android native app \ No newline at end of file +### Fastest zero abstraction number conversion android native app + +![CI](https://github.com/simonvar/Numer/workflows/CI/badge.svg) +![Release](https://github.com/simonvar/Numer/workflows/Build%20and%20Release%20APK/badge.svg) + +## CI/CD Pipeline + +This project includes automated GitHub Actions workflows for continuous integration and deployment: + +### Workflows + +1. **CI Workflow** (`.github/workflows/ci.yml`) + - Triggers on push/PR to `master`, `main`, or `develop` branches + - Runs tests and builds debug APK + - Uploads debug APK as artifact for verification + +2. **Release Workflow** (`.github/workflows/release.yml`) + - Triggers on: + - Push to `release/*` branches + - Git tags starting with `v*` (e.g., `v2.0`, `v2.1`) + - Manual GitHub releases + - Builds release APK with optimizations enabled + - Automatically creates GitHub releases for version tags + - Uploads APK to GitHub releases page + +### Creating a Release + +To create a new release: + +1. **Using Git Tags**: Push a tag starting with `v` + ```bash + git tag v2.1 + git push origin v2.1 + ``` + +2. **Using Release Branches**: Push to a release branch + ```bash + git checkout -b release/v2.1 + git push origin release/v2.1 + ``` + +3. **Manual Release**: Create a release manually in GitHub UI + +The workflow will automatically build and attach the APK to the release. \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index cfb2dc2..6cf8a4e 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -69,4 +69,9 @@ dependencies { implementation "androidx.recyclerview:recyclerview:1.2.1" implementation "com.google.android.material:material:1.7.0" + + // Testing dependencies + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' }