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
74 changes: 74 additions & 0 deletions .github/CICD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# CI/CD Workflows

This repository includes GitHub Actions workflows for automated building and releasing of the QR Code Scanner app.

## Workflows

### 1. Build Test (`build.yml`)
- **Triggers**: Pull requests and pushes to main/master branches
- **Purpose**: Validates that the code builds successfully and runs tests
- **Outputs**: Debug APK as an artifact

### 2. Build and Release APK (`release.yml`)
- **Triggers**:
- When a release is published on GitHub
- When a tag starting with 'v' is pushed (e.g., `v1.0.0`)
- **Purpose**: Builds the release APK and attaches it to the GitHub release
- **Outputs**:
- Release APK attached to the GitHub release
- Release APK as an artifact for tag pushes

## Creating a Release

### Option 1: Using the Release Script (Recommended)

The repository includes a helper script to streamline the release process:

```bash
./scripts/release.sh v1.0.0-alpha-06
```

This script will:
- Validate the version format
- Check if you're on the main/master branch
- Optionally update the version in `app/build.gradle.kts`
- Create and push the git tag
- Provide links to track the build progress

### Option 2: Manual Process

To create a new release manually:

1. **Create and push a tag**:
```bash
git tag v1.0.0-alpha-06
git push origin v1.0.0-alpha-06
```

2. **Create a GitHub release**:
- Go to the repository's Releases page
- Click "Create a new release"
- Select the tag you just created
- Fill in the release title and description
- Click "Publish release"

3. **Automatic APK build**:
- The workflow will automatically trigger
- Build the release APK
- Attach the APK to the release

## APK Naming

The generated APK will be named: `qr-code-scanner-{version}.apk`

Where `{version}` is extracted from either:
- The git tag (if triggered by tag push)
- The `versionName` from `app/build.gradle.kts`

## Build Environment

The workflows use:
- Ubuntu latest
- Java 17 (Temurin distribution)
- Android SDK (via android-actions/setup-android)
- Gradle caching for faster builds
52 changes: 52 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Build Test

on:
pull_request:
branches: [ main, master ]
push:
branches: [ main, master ]

env:
GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4096m -Dorg.gradle.daemon=false"

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: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Make gradlew executable
run: chmod +x ./gradlew

- name: Run tests
run: ./gradlew test

- name: Build debug APK
run: ./gradlew assembleDebug

- name: Upload debug APK
uses: actions/upload-artifact@v4
with:
name: debug-apk
path: app/build/outputs/apk/debug/*.apk
86 changes: 86 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Build and Release APK

on:
release:
types: [published]
push:
tags:
- 'v*'

env:
GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4096m -Dorg.gradle.daemon=false"

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: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Make gradlew executable
run: chmod +x ./gradlew

- name: Clean and Build Release APK
run: |
./gradlew clean
./gradlew assembleRelease

- name: Get APK info
id: apk-info
run: |
APK_PATH=$(find app/build/outputs/apk/release -name "*.apk" | head -1)
if [ -z "$APK_PATH" ]; then
echo "APK not found!"
exit 1
fi
echo "apk_path=$APK_PATH" >> $GITHUB_OUTPUT

# Extract version info from the APK path or use git tag
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
else
VERSION=$(grep 'versionName' app/build.gradle.kts | sed 's/.*"\(.*\)".*/\1/')
fi
Comment on lines +59 to +63

Copilot AI Sep 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable GITHUB_REF should be referenced as ${{ github.ref }} instead of $GITHUB_REF for consistency with the condition on line 59.

Copilot uses AI. Check for mistakes.

APK_NAME="qr-code-scanner-${VERSION}.apk"
echo "apk_name=$APK_NAME" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Rename APK
run: |
mv "${{ steps.apk-info.outputs.apk_path }}" "app/build/outputs/apk/release/${{ steps.apk-info.outputs.apk_name }}"

- name: Upload APK to Release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v1
with:
files: app/build/outputs/apk/release/${{ steps.apk-info.outputs.apk_name }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload APK as Artifact (for tag pushes)
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v4
with:
name: qr-code-scanner-${{ steps.apk-info.outputs.version }}
path: app/build/outputs/apk/release/${{ steps.apk-info.outputs.apk_name }}
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Android QR Code Scanner by Dan Tech
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dantech0xff/compose-barcode-scanner)
[![Build Test](https://github.com/dantech0xff/compose-qr-code-scanner/actions/workflows/build.yml/badge.svg)](https://github.com/dantech0xff/compose-qr-code-scanner/actions/workflows/build.yml)
![](https://img.shields.io/badge/Kotlin-Compose-green)
![](https://img.shields.io/badge/Google--Billing-blue)
![](https://img.shields.io/badge/Camera--X-red)
![](https://img.shields.io/badge/MLKit-white)
![](https://img.shields.io/badge/Hilt-gray)
![](https://img.shields.io/badge/Flow-yellow)
![](https://img.shields.io/badge/Room--Database-black)
![](https://img.shields.io/badge/CI%2FCD-GitHub%20Actions-blue)

This project is built with Jetpack Compose, CameraX, ML Kit and my handsome attitude.
This is for my learning purpose in order to get familiar with Jetpack Compose, MLKit and CameraX.
Expand Down Expand Up @@ -49,6 +51,10 @@ Feel free to use it in your project.

### Download, Clone, or do anything for your own purpose, I don't care!

## Download APK

Get the latest APK from the [Releases](../../releases) page. Each release automatically includes a built APK file ready for installation.

### Love it? Give me a star, I will be happy!

### Happy Coding!
Expand Down
80 changes: 80 additions & 0 deletions scripts/release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/bin/bash

# Release script for QR Code Scanner
# Usage: ./scripts/release.sh <version>
# Example: ./scripts/release.sh v1.0.0-alpha-06

set -e

if [ $# -eq 0 ]; then
echo "Usage: $0 <version>"
echo "Example: $0 v1.0.0-alpha-06"
exit 1
fi

VERSION=$1

# Validate version format
if [[ ! $VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then
echo "Error: Version must start with 'v' and follow semantic versioning (e.g., v1.0.0-alpha-06)"
exit 1
fi

echo "Creating release for version: $VERSION"

# Check if tag already exists
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "Error: Tag $VERSION already exists"
exit 1
fi

# Get current branch
CURRENT_BRANCH=$(git branch --show-current)
echo "Current branch: $CURRENT_BRANCH"

# Ensure we're on main/master branch
if [[ "$CURRENT_BRANCH" != "main" && "$CURRENT_BRANCH" != "master" ]]; then
echo "Warning: You're not on main/master branch. Continue? (y/N)"
read -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted"
exit 1
fi
fi

# Ensure working directory is clean
if ! git diff-index --quiet HEAD --; then
echo "Error: Working directory is not clean. Please commit your changes first."
exit 1
fi

# Update version in build.gradle.kts if needed
echo "Current version in build.gradle.kts:"
grep 'versionName' app/build.gradle.kts || echo "Version not found"

echo "Do you want to update the version in build.gradle.kts? (y/N)"
read -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# Extract version without 'v' prefix
VERSION_NUMBER=${VERSION#v}
sed -i.bak "s/versionName = \".*\"/versionName = \"$VERSION_NUMBER\"/" app/build.gradle.kts

Copilot AI Sep 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sed command creates a backup file (.bak) but doesn't clean it up. Consider removing the backup file after successful execution or using a different approach that doesn't create backup files.

Suggested change
sed -i.bak "s/versionName = \".*\"/versionName = \"$VERSION_NUMBER\"/" app/build.gradle.kts
sed -i "" "s/versionName = \".*\"/versionName = \"$VERSION_NUMBER\"/" app/build.gradle.kts

Copilot uses AI. Check for mistakes.
echo "Updated versionName to $VERSION_NUMBER"

# Commit version update
git add app/build.gradle.kts
git commit -m "Bump version to $VERSION_NUMBER"
fi

# Create and push tag
echo "Creating tag: $VERSION"
git tag -a "$VERSION" -m "Release $VERSION"

echo "Pushing tag to origin..."
git push origin "$VERSION"

echo "✅ Tag $VERSION has been pushed!"
echo "🚀 GitHub Actions will now build the APK automatically."
echo "📱 You can find the APK in the releases page once the build completes."
echo "🔗 https://github.com/$(git config --get remote.origin.url | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/releases"

Copilot AI Sep 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The complex sed expression for extracting the repository path is fragile and may not handle all URL formats correctly. Consider using a more robust approach like gh repo view --json url if GitHub CLI is available, or splitting this into multiple simpler operations.

Suggested change
echo "🔗 https://github.com/$(git config --get remote.origin.url | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/releases"
# Extract repository path (owner/repo) robustly
if command -v gh >/dev/null 2>&1; then
REPO_PATH=$(gh repo view --json nameWithOwner -q .nameWithOwner)
else
REMOTE_URL=$(git config --get remote.origin.url)
# Remove .git suffix if present
REMOTE_URL=${REMOTE_URL%.git}
# Extract owner/repo from SSH or HTTPS URL
if [[ "$REMOTE_URL" =~ github\.com[:/](.+/.+) ]]; then
REPO_PATH="${BASH_REMATCH[1]}"
else
REPO_PATH="unknown/unknown"
fi
fi
echo "🔗 https://github.com/$REPO_PATH/releases"

Copilot uses AI. Check for mistakes.