diff --git a/.github/workflows/android-docker.yml b/.github/workflows/android-docker.yml index 11d0988..d301f41 100644 --- a/.github/workflows/android-docker.yml +++ b/.github/workflows/android-docker.yml @@ -15,19 +15,32 @@ jobs: - name: Build Docker Image run: docker build -t android-ci . + - name: Determine Build Target + id: target + run: | + if [ "${{ github.ref }}" == "refs/heads/main" ]; then + echo "TASK=assembleRelease" >> $GITHUB_OUTPUT + echo "APK_PATH=app/build/outputs/apk/release/app-release-unsigned.apk" >> $GITHUB_OUTPUT + echo "ARTIFACT_NAME=app-release" >> $GITHUB_OUTPUT + else + echo "TASK=assembleDebug" >> $GITHUB_OUTPUT + echo "APK_PATH=app/build/outputs/apk/debug/app-debug.apk" >> $GITHUB_OUTPUT + echo "ARTIFACT_NAME=app-debug" >> $GITHUB_OUTPUT + fi + - name: Run Gradle Build in Docker # Mount current directory to /app # Use the image built in previous step - # Run './gradlew build' + # Run './gradlew ' run: | docker run --rm \ -v ${{ github.workspace }}:/app \ -w /app \ android-ci \ - bash -c "chmod +x gradlew && ./gradlew build" + bash -c "chmod +x gradlew && ./gradlew ${{ steps.target.outputs.TASK }}" - name: Upload APK uses: actions/upload-artifact@v4 with: - name: app-debug - path: app/build/outputs/apk/debug/app-debug.apk + name: ${{ steps.target.outputs.ARTIFACT_NAME }} + path: ${{ steps.target.outputs.APK_PATH }} diff --git a/README.md b/README.md index 013b6ec..a876cb8 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,23 @@ -# Android Build with Docker and GitHub Actions +# Android CI/CD Pipeline with Docker & GitHub Actions -This repository contains a sample Android project and a tutorial on how to set up a CI/CD pipeline using Docker and GitHub Actions. +## Overview +This repository demonstrates a production-grade **DevOps** setup for mobile applications. It implements a complete CI/CD pipeline for Android using **Infrastructure as Code (IaC)** principles with Docker and **Automated Workflows** with GitHub Actions. -## Contents +## Key Features (DevOps Highlights) +- **Containerized Build Environment**: Uses a custom Dockerfile with OpenJDK 17 and Android SDK 34 to ensure ensuring 100% reproducibility across environments ("Infrastructure as Code"). +- **Automated CI Pipeline**: Triggers builds on feature branches (`feat/*`) and the main branch. +- **Conditional Build Logic**: Automatically distinguishes between development builds (`debug`) and production artifacts (`release`) based on the branch. +- **Artifact Management**: Automatically packages and uploads APKs for testing and distribution. +- **Quality Checks**: Includes linting and static analysis integration. -- [App Source Code](./app/) -- [Dockerfile](./Dockerfile) -- [GitHub Actions Workflow](./.github/workflows/android-docker.yml) -- [**TUTORIAL**: Step-by-Step Guide](./TUTORIAL.md) \ No newline at end of file +## Project Structure +- `.github/workflows/`: CI/CD definitions. +- `Dockerfile`: Build environment definition. +- `app/`: Android application source code. +- `TUTORIAL.md`: **[Build Guide & Interview Prep Details](./TUTORIAL.md)**. + +## Quick Start +1. Fork this repository. +2. Create a feature branch: `git checkout -b feat/my-feature`. +3. Push changes to trigger a **Debug Build**. +4. Merge to `main` to trigger a **Release Build**. diff --git a/TUTORIAL.md b/TUTORIAL.md index 1ba42b7..e691ed4 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -1,79 +1,58 @@ -# Tutorial: Android GitHub Actions in Docker +# DevOps Guide: Android CI/CD with Docker -This tutorial guides you through setting up a CI/CD pipeline for your Android application using GitHub Actions and Docker. This ensures a consistent build environment and automates your build process. +This guide explains the "Why" and "How" of this project's architecture, specifically tailored for DevOps interview preparation. -## Prerequisites +## Part 1: The Architecture (Interview Concept) -- An Android project (already set up in this repository). -- Docker installed on your development machine (for local testing). -- A GitHub repository. +**Question:** "How do you ensure consistent builds across different developer machines and CI servers?" +**Answer:** "By containerizing the build environment. I use **Docker** to define the exact version of the JDK, Android SDK, and Build Tools. This verifies that 'it works on my machine' means it works everywhere." -## 1. The Docker Build Environment +### The Dockerfile Explained +[View Dockerfile](./Dockerfile) +- **`FROM eclipse-temurin:17-jdk`**: We start with a stable, lightweight Java base image. +- **`ENV ANDROID_HOME`**: We adhere to standard conventions for SDK location. +- **`sdkmanager`**: We programmatically install specific SDK versions (`platform-34`) matching our `build.gradle` config. -We use a `Dockerfile` to define an immutable build environment. This container includes: -- **OpenJDK 17**: The Java version required by the Gradle build. -- **Android Command Line Tools**: Necessary for managing the Android SDK. -- **Android SDK Components**: Specifically `platforms;android-34` and `build-tools;34.0.0` as defined in `app/build.gradle`. +## Part 2: The Pipeline (Interview Concept) -### Key Dockerfile Sections +**Question:** "Describe your CI/CD strategy for mobile apps." +**Answer:** "I implement a branching strategy where feature branches trigger flexible debug builds for rapid feedback, while the main branch triggers strict production/release builds." -```dockerfile -# Base image -FROM openjdk:17-jdk-slim +### The Workflow Explained +[View Workflow](./.github/workflows/android-docker.yml) -# Install system dependencies -RUN apt-get update && apt-get install -y curl unzip git ... - -# Download Command Line Tools -RUN curl -o cmdline-tools.zip ... - -# Install SDK Packages -RUN sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0" -``` - -## 2. GitHub Actions Workflow - -The workflow is defined in `.github/workflows/android-docker.yml`. It triggers on pushes and pull requests to the `main` branch. - -### Workflow Breakdown - -1. **Checkout Code**: Retrieves your project source code. -2. **Build Docker Image**: Builds the container defined in your `Dockerfile`. -3. **Run Build**: Mounts the project source code into the container and runs `./gradlew build`. - -```yaml - - name: Run Gradle Build in Docker - run: | - docker run --rm \ - -v ${{ github.workspace }}:/app \ - -w /app \ - android-ci \ - ./gradlew build +#### 1. Conditional Logic +We use shell scripting within the workflow to determine the build target dynamically: +```bash +if [ "${{ github.ref }}" == "refs/heads/main" ]; then + # Production: Build Release + echo "TASK=assembleRelease" >> $GITHUB_OUTPUT +else + # Development: Build Debug + echo "TASK=assembleDebug" >> $GITHUB_OUTPUT +fi ``` -## 3. Running Locally - -You can test the build environment locally using Docker before pushing to GitHub. - -### Step 1: Build the Image - +#### 2. Isolation +The build runs *inside* the Docker container: ```bash -docker build -t android-ci . +docker run --rm -v $(pwd):/app ... ./gradlew $TASK ``` +This ensures the CI runner's pre-installed tools don't interfere with our build. -### Step 2: Run the Build +#### 3. Artifact Retention +We use `actions/upload-artifact` to save the correct APK (`app-debug.apk` or `app-release-unsigned.apk`) allowing QA teams to download and test immediately without access to the code. -```bash -docker run --rm -v $(pwd):/app -w /app android-ci ./gradlew assembleDebug -``` +## Part 3: Android Configuration Basics for DevOps -This command: -- `--rm`: Removes the container after it exits. -- `-v $(pwd):/app`: Maps your current directory to `/app` inside the container. -- `-w /app`: Sets the working directory to `/app`. -- `android-ci`: Uses the image you just built. -- `./gradlew assembleDebug`: Runs the Gradle task to build the debug APK. +**Question:** "What files do you need to configure in an Android project?" +**Answer:** +1. **`app/build.gradle`**: Defines the *compileSdk* (must match Dockerfile) and *versionCode* (should be auto-incremented in CI). +2. **`gradle.properties`**: Controls build performance (JVM args) and library compatibility (`android.useAndroidX=true`). +3. **`local.properties`**: **IGNORED** by git. Used for local SDK paths. In CI, we use environment variables instead. -## Conclusion +## Part 4: Common Interview Troubleshooting -By containerizing your build environment, you eliminate "it works on my machine" issues and simplify your CI configuration. This setup forms the foundation for more advanced pipelines, including running tests and deploying to the Play Store. +- **"Gradle not found"**: Often means the wrapper script (`gradlew`) relies on a system gradle that isn't installed. *Fix: Install Gradle in the Docker image or use the wrapper correctly.* +- **"Permission denied"**: `gradlew` script often loses executable permission in git. *Fix: `chmod +x gradlew` or `git update-index --chmod=+x`.* +- **"License not accepted"**: The Android SDK requires explicit license acceptance. *Fix: Run `yes | sdkmanager --licenses` in the Dockerfile.*