Merge branch 'dev' into feature/session-persistence-new

This commit is contained in:
2026-03-11 10:56:48 +05:30
committed by GitHub
353 changed files with 29419 additions and 3689 deletions

99
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,99 @@
## 📋 Description
<!-- Provide a clear and concise description of your changes -->
---
## 🔗 Related Issues
<!-- Link any related issues using #issue_number -->
Closes #
Related to #
---
## 🎯 Type of Change
<!-- Mark the relevant option with an "x" -->
- [ ] 🐛 **Bug fix** (non-breaking change that fixes an issue)
- [ ]**Feature** (non-breaking change that adds functionality)
- [ ] 📝 **Documentation** (changes to docs, comments, or README)
- [ ] 🔧 **Refactor** (code change that doesn't affect functionality)
- [ ]**Performance** (improvement in performance or optimization)
- [ ] 🔐 **Security** (security fix or improvement)
- [ ] 🎨 **Style** (formatting, linting, or minor code style changes)
- [ ] 🏗️ **Architecture** (significant structural changes)
---
## 📦 Affected Areas
<!-- Mark the relevant areas that were modified -->
- [ ] 📱 **Mobile** (Flutter - Client/Worker app)
- [ ] 🌐 **Web** (React Dashboard)
- [ ] 🔌 **Backend** (APIs, Data Connect, Cloud Functions)
- [ ] 🗄️ **Database** (Schema changes, migrations)
- [ ] 🚀 **CI/CD** (GitHub Actions, deployment configs)
- [ ] 📚 **Documentation** (Docs, onboarding guides)
---
## ✅ Testing
<!-- Describe how you tested these changes -->
**Test Details:**
<!-- Provide specific test cases or scenarios -->
---
## 🔄 Breaking Changes
<!-- Are there any breaking changes? If yes, describe them -->
- [ ] No breaking changes
- [ ] Yes, breaking changes:
**Details:**
<!-- Describe migration path or deprecation period if applicable -->
---
## 🎯 Checklist
<!-- Complete this before requesting review -->
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex logic
- [ ] Documentation updated (if applicable)
- [ ] No new console warnings/errors
- [ ] Tests pass locally
- [ ] Branch is up-to-date with `dev`
- [ ] Commit messages are clear and descriptive
- [ ] Sensitive data is not committed
- [ ] Environment variables documented (if added)
---
## 📝 Additional Notes
<!-- Any additional context, decisions, or considerations -->
---
## 🔍 Review Checklist for Maintainers
- [ ] Code quality and readability
- [ ] Design patterns follow project conventions
- [ ] Performance implications reviewed
- [ ] Security concerns addressed
- [ ] Documentation is complete
- [ ] Breaking changes properly communicated
- [ ] Cross-platform compatibility (if applicable)

60
.github/scripts/attach-apk-to-release.sh vendored Executable file
View File

@@ -0,0 +1,60 @@
#!/bin/bash
# =============================================================================
# Attach APK to GitHub Release
# =============================================================================
# This script attaches a built APK to a GitHub Release with proper naming
#
# Usage:
# ./attach-apk-to-release.sh <tag_name> <app> <app_name> <version> <environment>
#
# Arguments:
# tag_name - Git tag name (e.g., krow-withus-worker-mobile/dev-v0.1.0)
# app - worker-mobile-app or client-mobile-app
# app_name - staff or client (internal build folder name)
# version - Version number (e.g., 0.1.0)
# environment - dev, stage, or prod
#
# Environment Variables:
# GH_TOKEN - GitHub token for gh CLI authentication
# =============================================================================
set -e
TAG_NAME="$1"
APP="$2"
APP_NAME="$3"
VERSION="$4"
ENV="$5"
if [ -z "$TAG_NAME" ] || [ -z "$APP" ] || [ -z "$APP_NAME" ] || [ -z "$VERSION" ] || [ -z "$ENV" ]; then
echo "❌ Error: Missing required arguments" >&2
echo "Usage: $0 <tag_name> <app> <app_name> <version> <environment>" >&2
exit 1
fi
# Find APK in build output
APK_PATH="apps/mobile/apps/${APP_NAME}/build/app/outputs/flutter-apk/app-release.apk"
if [ ! -f "$APK_PATH" ]; then
echo "❌ Error: APK not found at $APK_PATH" >&2
echo "Searching for APK files..." >&2
find apps/mobile/apps/${APP_NAME} -name "*.apk"
exit 1
fi
# Create proper APK name based on app type
if [ "$APP" = "worker-mobile-app" ]; then
APK_NAME="krow-withus-worker-mobile-${ENV}-v${VERSION}.apk"
else
APK_NAME="krow-withus-client-mobile-${ENV}-v${VERSION}.apk"
fi
# Copy APK with proper name
cp "$APK_PATH" "/tmp/$APK_NAME"
# Upload to GitHub Release
echo "📤 Uploading $APK_NAME to release $TAG_NAME..." >&2
gh release upload "$TAG_NAME" "/tmp/$APK_NAME" --clobber
echo "✅ APK attached to release: $APK_NAME" >&2

73
.github/scripts/create-release-summary.sh vendored Executable file
View File

@@ -0,0 +1,73 @@
#!/bin/bash
# Generate release summary for GitHub Actions
# Usage: ./create-release-summary.sh <app> <environment> <version> <tag_name>
set -e
APP=$1
ENV=$2
VERSION=$3
TAG_NAME=$4
if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$VERSION" ] || [ -z "$TAG_NAME" ]; then
echo "❌ Error: Missing required parameters"
echo "Usage: ./create-release-summary.sh <app> <environment> <version> <tag_name>"
exit 1
fi
# Determine display names
if [ "$APP" = "worker-mobile-app" ]; then
APP_DISPLAY="Worker Product"
APP_EMOJI="👷"
else
APP_DISPLAY="Client Product"
APP_EMOJI="💼"
fi
ENV_UPPER=$(echo "$ENV" | tr '[:lower:]' '[:upper:]')
RELEASE_NAME="Krow With Us - ${APP_DISPLAY} - ${ENV_UPPER} - v${VERSION}"
# Environment emoji
case "$ENV" in
dev)
ENV_EMOJI="🔧"
;;
stage)
ENV_EMOJI="🎭"
;;
prod)
ENV_EMOJI="🚀"
;;
*)
ENV_EMOJI="📦"
;;
esac
# Generate summary
cat << EOF >> $GITHUB_STEP_SUMMARY
## 🎉 Release Created Successfully
### ${APP_EMOJI} Application Details
- **App:** ${APP_DISPLAY}
- **Environment:** ${ENV_EMOJI} ${ENV_UPPER}
- **Version:** \`${VERSION}\`
- **Tag:** \`${TAG_NAME}\`
### 📦 Release Information
**Release Name:** ${RELEASE_NAME}
### ✅ Next Steps
1. 🔍 **Verify** the tag and release on GitHub
2. 🏗️ **Trigger** CodeMagic build (if configured)
3. 📱 **Monitor** app store deployment
4. 📚 **Update** project documentation if needed
5. 🎯 **Communicate** release to stakeholders
### 🔗 Quick Links
- [View Tag](../../releases/tag/${TAG_NAME})
- [Release Documentation](../../docs/release/MOBILE_RELEASE_PLAN.md)
- [CHANGELOG](../../apps/mobile/apps/${APP}/CHANGELOG.md)
EOF
echo "✅ Summary generated successfully"

71
.github/scripts/extract-release-notes.sh vendored Executable file
View File

@@ -0,0 +1,71 @@
#!/bin/bash
# Extract release notes from CHANGELOG for a specific version
# Usage: ./extract-release-notes.sh <app> <version> <environment> <tag_name> <output_file>
set -e
APP=$1
VERSION=$2
ENV=$3
TAG_NAME=$4
OUTPUT_FILE=$5
if [ -z "$APP" ] || [ -z "$VERSION" ] || [ -z "$ENV" ] || [ -z "$TAG_NAME" ] || [ -z "$OUTPUT_FILE" ]; then
echo "❌ Error: Missing required parameters" >&2
echo "Usage: ./extract-release-notes.sh <app> <version> <environment> <tag_name> <output_file>" >&2
exit 1
fi
# Determine CHANGELOG path and app name
if [ "$APP" = "worker-mobile-app" ]; then
CHANGELOG_PATH="apps/mobile/apps/staff/CHANGELOG.md"
APP_NAME="Staff Product (Worker)"
else
CHANGELOG_PATH="apps/mobile/apps/client/CHANGELOG.md"
APP_NAME="Client Product"
fi
# Try to extract release notes for this version
if [ -f "$CHANGELOG_PATH" ]; then
echo "📝 Found CHANGELOG at $CHANGELOG_PATH" >&2
# Extract section for this version
# Look for ## [vVERSION] or ## [VERSION] and collect content until next ## [ header
# Try with 'v' prefix first (common format), then without
CHANGELOG_CONTENT=$(awk "/^## \[v${VERSION}\]/{flag=1; next} /^## \[/{flag=0} flag" "$CHANGELOG_PATH")
# If still empty, try without 'v' prefix
if [ -z "$CHANGELOG_CONTENT" ]; then
CHANGELOG_CONTENT=$(awk "/^## \[${VERSION}\]/{flag=1; next} /^## \[/{flag=0} flag" "$CHANGELOG_PATH")
fi
if [ -z "$CHANGELOG_CONTENT" ]; then
echo "⚠️ Warning: No CHANGELOG entry found for version $VERSION" >&2
NOTES="**Environment:** $ENV
**Tag:** $TAG_NAME
## What is new in this release
⚠️ No CHANGELOG entry found for this version. Please update the CHANGELOG manually."
else
echo "✅ Extracted release notes for version $VERSION" >&2
NOTES="**Environment:** $ENV
**Tag:** $TAG_NAME
## What is new in this release
$CHANGELOG_CONTENT"
fi
else
echo "⚠️ Warning: CHANGELOG not found at $CHANGELOG_PATH" >&2
NOTES="**Environment:** $ENV
**Tag:** $TAG_NAME
## What is new in this release
⚠️ CHANGELOG file not found at $CHANGELOG_PATH"
fi
# Save to output file
echo "$NOTES" > "$OUTPUT_FILE"
echo "✅ Release notes saved to $OUTPUT_FILE" >&2

52
.github/scripts/extract-version.sh vendored Executable file
View File

@@ -0,0 +1,52 @@
#!/bin/bash
# Extract version from version file for products
# Usage: ./extract-version.sh <app>
# app: worker-mobile-app or client-mobile-app
set -e
APP=$1
if [ -z "$APP" ]; then
echo "❌ Error: App parameter required (worker-mobile-app or client-mobile-app)" >&2
exit 1
fi
# Determine pubspec path
if [ "$APP" = "worker-mobile-app" ]; then
PUBSPEC_PATH="apps/mobile/apps/staff/pubspec.yaml"
APP_NAME="Staff Product (Worker)"
else
PUBSPEC_PATH="apps/mobile/apps/client/pubspec.yaml"
APP_NAME="Client Product"
fi
# Check if pubspec exists
if [ ! -f "$PUBSPEC_PATH" ]; then
echo "❌ Error: pubspec.yaml not found at $PUBSPEC_PATH" >&2
echo "📁 Current directory: $(pwd)" >&2
echo "📂 Directory contents:" >&2
ls -la apps/mobile/apps/ 2>&1 | head -20 >&2
exit 1
fi
# Extract version (format: X.Y.Z+buildNumber or X.Y.Z-suffix)
VERSION_LINE=$(grep "^version:" "$PUBSPEC_PATH")
if [ -z "$VERSION_LINE" ]; then
echo "❌ Error: Could not find version in $PUBSPEC_PATH" >&2
exit 1
fi
# Extract full version including suffix/build number
VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//' | tr -d ' ')
# Validate version format (X.Y.Z with optional +build or -suffix)
# Use grep for better portability across different bash versions
if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(\+[a-zA-Z0-9]+|-[a-zA-Z0-9]+)?$'; then
echo "❌ Error: Invalid version format in pubspec.yaml: $VERSION" >&2
echo "Expected format: X.Y.Z, X.Y.Z+build, or X.Y.Z-suffix (e.g., 0.1.0, 0.1.0+12, 0.1.0-m3)" >&2
exit 1
fi
echo "✅ Extracted version from $PUBSPEC_PATH: $VERSION" >&2
echo "$VERSION"

22
.github/scripts/generate-tag-name.sh vendored Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
# Generate tag name for product release
# Usage: ./generate-tag-name.sh <app> <environment> <version>
set -e
APP=$1
ENV=$2
VERSION=$3
if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$VERSION" ]; then
echo "❌ Error: Missing required parameters" >&2
echo "Usage: ./generate-tag-name.sh <app> <environment> <version>" >&2
exit 1
fi
# Strip -mobile-app suffix from app name for cleaner tag names
# worker-mobile-app -> worker, client-mobile-app -> client
APP_TAG=$(echo "$APP" | sed 's/-mobile-app$//')
TAG_NAME="krow-withus-${APP_TAG}-mobile/${ENV}-v${VERSION}"
echo "$TAG_NAME"

106
.github/scripts/setup-apk-signing.sh vendored Executable file
View File

@@ -0,0 +1,106 @@
#!/bin/bash
# =============================================================================
# Setup APK Signing for GitHub Actions
# =============================================================================
# This script configures Android APK signing by decoding keystores from
# GitHub Secrets and setting up environment variables for build.gradle.kts
#
# Usage:
# ./setup-apk-signing.sh <app> <environment> <temp_dir>
#
# Arguments:
# app - worker-mobile-app or client-mobile-app
# environment - dev, stage, or prod
# temp_dir - Temporary directory for keystore files (e.g., ${{ runner.temp }})
#
# Environment Variables (must be set):
# WORKER_KEYSTORE_DEV_BASE64, WORKER_KEYSTORE_STAGING_BASE64, WORKER_KEYSTORE_PROD_BASE64
# WORKER_KEYSTORE_PASSWORD_DEV, WORKER_KEYSTORE_PASSWORD_STAGING, WORKER_KEYSTORE_PASSWORD_PROD
# WORKER_KEY_ALIAS_DEV, WORKER_KEY_ALIAS_STAGING, WORKER_KEY_ALIAS_PROD
# WORKER_KEY_PASSWORD_DEV, WORKER_KEY_PASSWORD_STAGING, WORKER_KEY_PASSWORD_PROD
# CLIENT_KEYSTORE_DEV_BASE64, CLIENT_KEYSTORE_STAGING_BASE64, CLIENT_KEYSTORE_PROD_BASE64
# CLIENT_KEYSTORE_PASSWORD_DEV, CLIENT_KEYSTORE_PASSWORD_STAGING, CLIENT_KEYSTORE_PASSWORD_PROD
# CLIENT_KEY_ALIAS_DEV, CLIENT_KEY_ALIAS_STAGING, CLIENT_KEY_ALIAS_PROD
# CLIENT_KEY_PASSWORD_DEV, CLIENT_KEY_PASSWORD_STAGING, CLIENT_KEY_PASSWORD_PROD
# =============================================================================
set -e
APP="$1"
ENV="$2"
TEMP_DIR="$3"
if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$TEMP_DIR" ]; then
echo "❌ Error: Missing required arguments" >&2
echo "Usage: $0 <app> <environment> <temp_dir>" >&2
exit 1
fi
echo "🔐 Setting up Android signing for $APP in $ENV environment..." >&2
# Determine which keystore to use
if [ "$APP" = "worker-mobile-app" ]; then
APP_TYPE="WORKER"
APP_NAME="STAFF" # CodeMagic uses STAFF in env var names
else
APP_TYPE="CLIENT"
APP_NAME="CLIENT"
fi
# Convert environment to uppercase for env var names
ENV_UPPER=$(echo "$ENV" | tr '[:lower:]' '[:upper:]')
if [ "$ENV_UPPER" = "STAGE" ]; then
ENV_UPPER="STAGING" # CodeMagic uses STAGING instead of STAGE
fi
# Get the keystore secret name dynamically
KEYSTORE_BASE64_VAR="${APP_TYPE}_KEYSTORE_${ENV_UPPER}_BASE64"
KEYSTORE_PASSWORD_VAR="${APP_TYPE}_KEYSTORE_PASSWORD_${ENV_UPPER}"
KEY_ALIAS_VAR="${APP_TYPE}_KEY_ALIAS_${ENV_UPPER}"
KEY_PASSWORD_VAR="${APP_TYPE}_KEY_PASSWORD_${ENV_UPPER}"
# Get values using indirect expansion
KEYSTORE_BASE64="${!KEYSTORE_BASE64_VAR}"
KEYSTORE_PASSWORD="${!KEYSTORE_PASSWORD_VAR}"
KEY_ALIAS="${!KEY_ALIAS_VAR}"
KEY_PASSWORD="${!KEY_PASSWORD_VAR}"
# Check if secrets are configured
if [ -z "$KEYSTORE_BASE64" ]; then
echo "⚠️ WARNING: Keystore secret $KEYSTORE_BASE64_VAR is not configured!" >&2
echo "⚠️ APK will be built UNSIGNED for $ENV environment." >&2
echo "⚠️ Please configure GitHub Secrets as documented in docs/RELEASE/APK_SIGNING_SETUP.md" >&2
exit 0
fi
# Create temporary directory for keystore
KEYSTORE_DIR="${TEMP_DIR}/keystores"
mkdir -p "$KEYSTORE_DIR"
KEYSTORE_PATH="$KEYSTORE_DIR/release.jks"
# Decode keystore from base64
echo "$KEYSTORE_BASE64" | base64 -d > "$KEYSTORE_PATH"
if [ ! -f "$KEYSTORE_PATH" ]; then
echo "❌ Failed to decode keystore!" >&2
exit 1
fi
echo "✅ Keystore decoded successfully" >&2
echo "📦 Keystore size: $(ls -lh "$KEYSTORE_PATH" | awk '{print $5}')" >&2
# Export environment variables for build.gradle.kts
# Note: build.gradle.kts expects variables WITHOUT app suffix
echo "CI=true" >> $GITHUB_ENV
echo "CM_KEYSTORE_PATH=$KEYSTORE_PATH" >> $GITHUB_ENV
echo "CM_KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD" >> $GITHUB_ENV
echo "CM_KEY_ALIAS=$KEY_ALIAS" >> $GITHUB_ENV
echo "CM_KEY_PASSWORD=$KEY_PASSWORD" >> $GITHUB_ENV
echo "✅ Signing environment configured for $APP_NAME ($ENV environment)" >&2
echo "🔑 Using key alias: $KEY_ALIAS" >&2
echo "📝 Environment variables exported:" >&2
echo " - CI=true" >&2
echo " - CM_KEYSTORE_PATH=$KEYSTORE_PATH" >&2
echo " - CM_KEY_ALIAS=$KEY_ALIAS" >&2

262
.github/scripts/setup-mobile-github-secrets.sh vendored Executable file
View File

@@ -0,0 +1,262 @@
#!/bin/bash
# =============================================================================
# GitHub Secrets Setup Helper
# =============================================================================
# This script helps you configure GitHub Secrets for APK signing
#
# Usage:
# ./setup-mobile-github-secrets.sh
#
# Reference: docs/RELEASE/APK_SIGNING_SETUP.md
# =============================================================================
set -e
REPO_ROOT=$(git rev-parse --show-toplevel)
cd "$REPO_ROOT"
echo "🔐 GitHub Secrets Setup Helper for APK Signing"
echo "================================================"
echo ""
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Track successful secret generations
SECRETS_FOUND=0
TOTAL_SECRETS=24
# =============================================================================
# Helper Functions
# =============================================================================
print_secret_config() {
local app=$1
local env=$2
local keystore_path=$3
local password=$4
local alias=$5
local key_password=$6
local app_upper=$(echo "$app" | tr '[:lower:]' '[:upper:]')
local env_upper=$(echo "$env" | tr '[:lower:]' '[:upper:]')
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " ${app_upper} Mobile - ${env_upper} Environment"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [ -f "$keystore_path" ]; then
echo -e "${GREEN}✅ Keystore found:${NC} $keystore_path"
# Show keystore info
echo ""
echo "📋 Keystore Information:"
keytool -list -v -keystore "$keystore_path" -storepass "$password" 2>/dev/null | head -n 15 || echo " (Use keytool to inspect)"
# Generate base64
echo ""
echo "📦 Base64 Encoded Keystore:"
echo ""
BASE64_OUTPUT=$(base64 -i "$keystore_path")
echo "$BASE64_OUTPUT"
echo ""
echo "GitHub Secrets to create:"
echo ""
echo " ${app_upper}_KEYSTORE_${env_upper}_BASE64"
echo " ${app_upper}_KEYSTORE_PASSWORD_${env_upper} = $password"
echo " ${app_upper}_KEY_ALIAS_${env_upper} = $alias"
echo " ${app_upper}_KEY_PASSWORD_${env_upper} = $key_password"
echo ""
# Increment success counter (4 secrets per keystore)
SECRETS_FOUND=$((SECRETS_FOUND + 4))
else
echo -e "${YELLOW}⚠️ Keystore not found:${NC} $keystore_path"
echo ""
echo "This keystore should be stored securely (CodeMagic or secure storage)."
echo ""
fi
}
# =============================================================================
# Worker Mobile (Staff App)
# =============================================================================
echo ""
echo "═══════════════════════════════════════════════════════"
echo " WORKER MOBILE (Staff App) Configuration"
echo "═══════════════════════════════════════════════════════"
# DEV Environment
print_secret_config \
"worker" \
"dev" \
"$REPO_ROOT/apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks" \
"krowwithus" \
"krow_staff_dev" \
"krowwithus"
# STAGING Environment
print_secret_config \
"worker" \
"staging" \
"$REPO_ROOT/keystores/krow_staff_staging.jks" \
"YOUR_STAGING_PASSWORD" \
"krow_staff_staging" \
"YOUR_STAGING_KEY_PASSWORD"
# PROD Environment
print_secret_config \
"worker" \
"prod" \
"$REPO_ROOT/keystores/krow_staff_prod.jks" \
"YOUR_PROD_PASSWORD" \
"krow_staff_prod" \
"YOUR_PROD_KEY_PASSWORD"
# =============================================================================
# Client Mobile
# =============================================================================
echo ""
echo "═══════════════════════════════════════════════════════"
echo " CLIENT MOBILE Configuration"
echo "═══════════════════════════════════════════════════════"
# DEV Environment
print_secret_config \
"client" \
"dev" \
"$REPO_ROOT/apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks" \
"krowwithus" \
"krow_client_dev" \
"krowwithus"
# STAGING Environment
print_secret_config \
"client" \
"staging" \
"$REPO_ROOT/keystores/krow_client_staging.jks" \
"YOUR_STAGING_PASSWORD" \
"krow_client_staging" \
"YOUR_STAGING_KEY_PASSWORD"
# PROD Environment
print_secret_config \
"client" \
"prod" \
"$REPO_ROOT/keystores/krow_client_prod.jks" \
"YOUR_PROD_PASSWORD" \
"krow_client_prod" \
"YOUR_PROD_KEY_PASSWORD"
# =============================================================================
# Summary
# =============================================================================
echo ""
echo "═══════════════════════════════════════════════════════"
echo " SUMMARY"
echo "═══════════════════════════════════════════════════════"
echo ""
echo "Total secrets needed: ${TOTAL_SECRETS}"
echo "Secrets successfully generated: ${SECRETS_FOUND}"
echo ""
echo " • 6 keystores (base64 encoded)"
echo " • 6 keystore passwords"
echo " • 6 key aliases"
echo " • 6 key passwords"
echo ""
if [ $SECRETS_FOUND -gt 0 ]; then
echo "Generated secrets to add to GitHub:"
echo ""
# Worker Dev Secrets
if [ -f "$REPO_ROOT/apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks" ]; then
echo " ✅ WORKER_KEYSTORE_DEV_BASE64"
echo " $(base64 -i "$REPO_ROOT/apps/mobile/apps/staff/android/app/krow_with_us_staff_dev.jks")"
echo ""
echo " ✅ WORKER_KEYSTORE_PASSWORD_DEV"
echo " krowwithus"
echo ""
echo " ✅ WORKER_KEY_ALIAS_DEV"
echo " krow_staff_dev"
echo ""
echo " ✅ WORKER_KEY_PASSWORD_DEV"
echo " krowwithus"
echo ""
fi
# Client Dev Secrets
if [ -f "$REPO_ROOT/apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks" ]; then
echo " ✅ CLIENT_KEYSTORE_DEV_BASE64"
echo " $(base64 -i "$REPO_ROOT/apps/mobile/apps/client/android/app/krow_with_us_client_dev.jks")"
echo ""
echo " ✅ CLIENT_KEYSTORE_PASSWORD_DEV"
echo " krowwithus"
echo ""
echo " ✅ CLIENT_KEY_ALIAS_DEV"
echo " krow_client_dev"
echo ""
echo " ✅ CLIENT_KEY_PASSWORD_DEV"
echo " krowwithus"
echo ""
fi
fi
if [ $SECRETS_FOUND -lt $TOTAL_SECRETS ]; then
echo "Missing secrets (keystores not found):"
echo ""
if [ ! -f "$REPO_ROOT/keystores/krow_staff_staging.jks" ]; then
echo " ⚠️ WORKER_KEYSTORE_STAGING_BASE64"
echo " ⚠️ WORKER_KEYSTORE_PASSWORD_STAGING"
echo " ⚠️ WORKER_KEY_ALIAS_STAGING"
echo " ⚠️ WORKER_KEY_PASSWORD_STAGING"
fi
if [ ! -f "$REPO_ROOT/keystores/krow_staff_prod.jks" ]; then
echo " ⚠️ WORKER_KEYSTORE_PROD_BASE64"
echo " ⚠️ WORKER_KEYSTORE_PASSWORD_PROD"
echo " ⚠️ WORKER_KEY_ALIAS_PROD"
echo " ⚠️ WORKER_KEY_PASSWORD_PROD"
fi
if [ ! -f "$REPO_ROOT/keystores/krow_client_staging.jks" ]; then
echo " ⚠️ CLIENT_KEYSTORE_STAGING_BASE64"
echo " ⚠️ CLIENT_KEYSTORE_PASSWORD_STAGING"
echo " ⚠️ CLIENT_KEY_ALIAS_STAGING"
echo " ⚠️ CLIENT_KEY_PASSWORD_STAGING"
fi
if [ ! -f "$REPO_ROOT/keystores/krow_client_prod.jks" ]; then
echo " ⚠️ CLIENT_KEYSTORE_PROD_BASE64"
echo " ⚠️ CLIENT_KEYSTORE_PASSWORD_PROD"
echo " ⚠️ CLIENT_KEY_ALIAS_PROD"
echo " ⚠️ CLIENT_KEY_PASSWORD_PROD"
fi
echo ""
echo "Retrieve missing keystores from CodeMagic Team Settings or secure storage."
fi
echo ""
echo "To configure GitHub Secrets:"
echo ""
echo " 1. Go to: https://github.com/Oloodi/krow-workforce/settings/secrets/actions"
echo " 2. Click 'New repository secret'"
echo " 3. Add each secret listed above"
echo ""
echo "For complete documentation, see:"
echo " docs/RELEASE/APK_SIGNING_SETUP.md"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

59
.github/scripts/verify-apk-signature.sh vendored Executable file
View File

@@ -0,0 +1,59 @@
#!/bin/bash
# =============================================================================
# Verify APK Signature
# =============================================================================
# This script verifies that an APK is properly signed and displays
# certificate information
#
# Usage:
# ./verify-apk-signature.sh <apk_path>
#
# Arguments:
# apk_path - Path to the APK file to verify
# =============================================================================
set -e
APK_PATH="$1"
if [ -z "$APK_PATH" ]; then
echo "❌ Error: Missing APK path" >&2
echo "Usage: $0 <apk_path>" >&2
exit 1
fi
if [ ! -f "$APK_PATH" ]; then
echo "❌ APK not found at: $APK_PATH" >&2
exit 1
fi
echo "🔍 Verifying APK signature..." >&2
# Check if APK is signed
if jarsigner -verify -verbose "$APK_PATH" 2>&1 | grep -q "jar verified"; then
echo "✅ APK is properly signed!" >&2
# Extract certificate details
echo "" >&2
echo "📜 Certificate Details:" >&2
jarsigner -verify -verbose -certs "$APK_PATH" 2>&1 | grep -A 3 "X.509" || true
# Get signer info
echo "" >&2
echo "🔑 Signer Information:" >&2
keytool -printcert -jarfile "$APK_PATH" | head -n 15
else
echo "⚠️ WARNING: APK signature verification failed or APK is unsigned!" >&2
echo "" >&2
echo "This may happen if:" >&2
echo " 1. GitHub Secrets are not configured for this environment" >&2
echo " 2. Keystore credentials are incorrect" >&2
echo " 3. Build configuration didn't apply signing" >&2
echo "" >&2
echo "See: docs/RELEASE/APK_SIGNING_SETUP.md for setup instructions" >&2
# Don't fail the build, just warn
# exit 1
fi

View File

@@ -2,6 +2,7 @@ name: Backend Foundation
on:
workflow_dispatch: # Manual trigger only — auto-triggers disabled (free plan)
workflow_dispatch:
jobs:
backend-foundation-makefile:

View File

@@ -0,0 +1,332 @@
name: 🚨 Hotfix Branch Creation
on:
workflow_dispatch:
inputs:
app:
description: '📦 Product'
required: true
type: choice
options:
- worker-mobile-app
- client-mobile-app
tag:
description: '🏷️ Current Tag (e.g., krow-withus-worker-mobile/prod-v0.1.0 or dev/stage)'
required: true
type: string
issue_description:
description: '📝 Brief issue description'
required: true
type: string
jobs:
create-hotfix-branch:
name: 🚨 Create Hotfix Branch
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🔍 Validate tag exists
id: validate_tag
run: |
TAG="${{ github.event.inputs.tag }}"
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
echo "❌ Error: Tag '$TAG' does not exist"
echo "Available tags:"
git tag -l "krow-withus-*-mobile/*" | tail -20
exit 1
fi
echo "✅ Tag exists: $TAG"
# Extract version from tag
VERSION=$(echo "$TAG" | grep -oP 'v\K[0-9]+\.[0-9]+\.[0-9]+' || echo "")
if [ -z "$VERSION" ]; then
echo "❌ Error: Could not extract version from tag"
exit 1
fi
echo "current_version=${VERSION}" >> $GITHUB_OUTPUT
echo "📌 Current version: $VERSION"
- name: 🔢 Calculate hotfix version
id: hotfix_version
run: |
CURRENT="${{ steps.validate_tag.outputs.current_version }}"
# Split version into parts
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
# Increment PATCH version
NEW_PATCH=$((PATCH + 1))
HOTFIX_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}"
echo "hotfix_version=${HOTFIX_VERSION}" >> $GITHUB_OUTPUT
echo "🆕 Hotfix version: $HOTFIX_VERSION"
- name: 🌿 Generate branch name
id: branch
run: |
APP="${{ github.event.inputs.app }}"
VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}"
# Strip -mobile-app suffix for cleaner branch names
APP_CLEAN=$(echo "$APP" | sed 's/-mobile-app$//')
BRANCH_NAME="hotfix/krow-withus-${APP_CLEAN}-mobile-v${VERSION}"
echo "branch_name=${BRANCH_NAME}" >> $GITHUB_OUTPUT
echo "🌿 Branch to create: $BRANCH_NAME"
- name: 🔍 Check if hotfix branch already exists
run: |
BRANCH="${{ steps.branch.outputs.branch_name }}"
if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then
echo "❌ Error: Branch $BRANCH already exists"
exit 1
fi
echo "✅ Branch does not exist, proceeding..."
- name: 🌿 Create hotfix branch from tag
run: |
TAG="${{ github.event.inputs.tag }}"
BRANCH="${{ steps.branch.outputs.branch_name }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Checkout the tag
git checkout "$TAG"
# Create new branch
git checkout -b "$BRANCH"
echo "✅ Created branch $BRANCH from tag $TAG"
- name: 📝 Update version files
id: update_versions
run: |
APP="${{ github.event.inputs.app }}"
HOTFIX_VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}"
if [ "$APP" = "worker-mobile-app" ]; then
PUBSPEC_PATH="apps/mobile/apps/staff/pubspec.yaml"
CHANGELOG_PATH="apps/mobile/apps/staff/CHANGELOG.md"
APP_NAME="Staff Product"
else
PUBSPEC_PATH="apps/mobile/apps/client/pubspec.yaml"
CHANGELOG_PATH="apps/mobile/apps/client/CHANGELOG.md"
APP_NAME="Client Product"
fi
# Update pubspec.yaml version
if [ -f "$PUBSPEC_PATH" ]; then
# Extract current version and build number
CURRENT_VERSION_LINE=$(grep "^version:" "$PUBSPEC_PATH")
CURRENT_BUILD=$(echo "$CURRENT_VERSION_LINE" | grep -oP '\+\K[0-9]+' || echo "1")
NEW_BUILD=$((CURRENT_BUILD + 1))
# Update version line
sed -i "s/^version:.*/version: ${HOTFIX_VERSION}+${NEW_BUILD}/" "$PUBSPEC_PATH"
echo "✅ Updated $PUBSPEC_PATH to ${HOTFIX_VERSION}+${NEW_BUILD}"
echo "updated_files=true" >> $GITHUB_OUTPUT
else
echo "⚠️ Warning: $PUBSPEC_PATH not found"
echo "updated_files=false" >> $GITHUB_OUTPUT
fi
- name: 📋 Add CHANGELOG entry
run: |
APP="${{ github.event.inputs.app }}"
HOTFIX_VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}"
ISSUE="${{ github.event.inputs.issue_description }}"
if [ "$APP" = "worker-mobile-app" ]; then
CHANGELOG_PATH="apps/mobile/apps/staff/CHANGELOG.md"
APP_NAME="Staff Product"
else
CHANGELOG_PATH="apps/mobile/apps/client/CHANGELOG.md"
APP_NAME="Client Product"
fi
if [ -f "$CHANGELOG_PATH" ]; then
DATE=$(date +%Y-%m-%d)
# Extract title and body
TITLE=$(head -n 1 "$CHANGELOG_PATH")
BODY=$(tail -n +2 "$CHANGELOG_PATH")
# Rebuild CHANGELOG with hotfix entry
echo "$TITLE" > "$CHANGELOG_PATH"
echo "" >> "$CHANGELOG_PATH"
echo "## [${HOTFIX_VERSION}] - ${DATE} - HOTFIX" >> "$CHANGELOG_PATH"
echo "" >> "$CHANGELOG_PATH"
echo "### Fixed" >> "$CHANGELOG_PATH"
echo "- ${ISSUE}" >> "$CHANGELOG_PATH"
echo "" >> "$CHANGELOG_PATH"
echo "---" >> "$CHANGELOG_PATH"
echo "" >> "$CHANGELOG_PATH"
echo "$BODY" >> "$CHANGELOG_PATH"
echo "✅ Added CHANGELOG entry for hotfix $HOTFIX_VERSION"
else
echo "⚠️ Warning: $CHANGELOG_PATH not found"
fi
- name: 💾 Commit version changes
run: |
HOTFIX_VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}"
ISSUE="${{ github.event.inputs.issue_description }}"
git add -A
git commit -m "chore: prepare hotfix v${HOTFIX_VERSION}
HOTFIX: ${ISSUE}
- Bump version to ${HOTFIX_VERSION}
- Add CHANGELOG entry
- Ready for bug fix commits
From tag: ${{ github.event.inputs.tag }}"
echo "✅ Committed version changes"
- name: 🚀 Push hotfix branch
run: |
BRANCH="${{ steps.branch.outputs.branch_name }}"
git push origin "$BRANCH"
echo "✅ Pushed branch: $BRANCH"
- name: 📄 Create Pull Request
id: create_pr
env:
GH_TOKEN: ${{ github.token }}
run: |
BRANCH="${{ steps.branch.outputs.branch_name }}"
HOTFIX_VERSION="${{ steps.hotfix_version.outputs.hotfix_version }}"
ISSUE="${{ github.event.inputs.issue_description }}"
APP="${{ github.event.inputs.app }}"
# Strip -mobile-app suffix for cleaner tag names
APP_CLEAN=$(echo "$APP" | sed 's/-mobile-app$//')
if [ "$APP" = "worker-mobile-app" ]; then
APP_DISPLAY="Worker Product"
else
APP_DISPLAY="Client Product"
fi
PR_TITLE="🚨 HOTFIX: ${APP_DISPLAY} v${HOTFIX_VERSION} - ${ISSUE}"
PR_BODY="## 🚨 HOTFIX - URGENT FIX
**App:** ${APP_DISPLAY}
**Version:** ${HOTFIX_VERSION}
**From:** \`${{ github.event.inputs.tag }}\`
### Issue
${ISSUE}
### Impact
<!-- Describe how many users are affected and severity -->
### Solution
<!-- Describe the fix (will be added as you commit fixes) -->
### Testing
<!-- Describe local verification -->
---
## ⚠️ Hotfix Process
1. ✅ Hotfix branch created
2. ⏳ **NEXT:** Make your bug fix commits to this branch
3. ⏳ Test the fix locally
4. ⏳ Request expedited review (< 15 minutes)
5. ⏳ Merge to main and create production tag
### To add your fix:
\`\`\`bash
git checkout $BRANCH
# Make your changes
git commit -m \"fix: [description]\"
git push origin $BRANCH
\`\`\`
### After merging:
\`\`\`bash
# Tag and release
git checkout main
git pull origin main
git tag -a krow-withus-${APP_CLEAN}-mobile/prod-v${HOTFIX_VERSION} -m \"HOTFIX: ${ISSUE}\"
git push origin krow-withus-${APP_CLEAN}-mobile/prod-v${HOTFIX_VERSION}
\`\`\`
---
**Ref:** [Hotfix Process Documentation](../docs/release/HOTFIX_PROCESS.md)"
# Create PR
PR_URL=$(gh pr create \
--base main \
--head "$BRANCH" \
--title "$PR_TITLE" \
--body "$PR_BODY" \
--label "hotfix,urgent,production")
echo "pr_url=${PR_URL}" >> $GITHUB_OUTPUT
echo "✅ Pull Request created: $PR_URL"
- name: 📊 Hotfix Summary
run: |
# Strip -mobile-app suffix for cleaner tag names
APP_CLEAN=$(echo "${{ github.event.inputs.app }}" | sed 's/-mobile-app$//')
echo "## 🚨 Hotfix Branch Created" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**App:** ${{ github.event.inputs.app }}" >> $GITHUB_STEP_SUMMARY
echo "**Issue:** ${{ github.event.inputs.issue_description }}" >> $GITHUB_STEP_SUMMARY
echo "**From Tag:** \`${{ github.event.inputs.tag }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Current Version:** ${{ steps.validate_tag.outputs.current_version }}" >> $GITHUB_STEP_SUMMARY
echo "**Hotfix Version:** ${{ steps.hotfix_version.outputs.hotfix_version }}" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** \`${{ steps.branch.outputs.branch_name }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🔧 Next Steps" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "1. **Checkout the hotfix branch:**" >> $GITHUB_STEP_SUMMARY
echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo " git fetch origin" >> $GITHUB_STEP_SUMMARY
echo " git checkout ${{ steps.branch.outputs.branch_name }}" >> $GITHUB_STEP_SUMMARY
echo " \`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "2. **Make your bug fix(es)** - Keep changes minimal!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "3. **Test locally** - Verify the fix works" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "4. **Request expedited review** - Target < 15 minutes" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "5. **Merge PR and create production tag:**" >> $GITHUB_STEP_SUMMARY
echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo " git checkout main" >> $GITHUB_STEP_SUMMARY
echo " git pull origin main" >> $GITHUB_STEP_SUMMARY
echo " git tag -a krow-withus-${APP_CLEAN}-mobile/prod-v${{ steps.hotfix_version.outputs.hotfix_version }} -m \"HOTFIX: ${{ github.event.inputs.issue_description }}\"" >> $GITHUB_STEP_SUMMARY
echo " git push origin krow-withus-${APP_CLEAN}-mobile/prod-v${{ steps.hotfix_version.outputs.hotfix_version }}" >> $GITHUB_STEP_SUMMARY
echo " \`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -n "${{ steps.create_pr.outputs.pr_url }}" ]; then
echo "**Pull Request:** ${{ steps.create_pr.outputs.pr_url }}" >> $GITHUB_STEP_SUMMARY
fi

View File

@@ -2,6 +2,7 @@ name: Mobile CI
on:
workflow_dispatch: # Manual trigger only — auto-triggers disabled (free plan)
workflow_dispatch:
jobs:
detect-changes:

289
.github/workflows/product-release.yml vendored Normal file
View File

@@ -0,0 +1,289 @@
name: 📦 Product Release
on:
workflow_dispatch:
inputs:
app:
description: '📦 Product'
required: true
type: choice
options:
- worker-mobile-app
- client-mobile-app
environment:
description: '🌍 Environment'
required: true
type: choice
options:
- dev
- stage
- prod
create_github_release:
description: '📦 Create GitHub Release'
required: true
type: boolean
default: true
prerelease:
description: '🔖 Mark as Pre-release'
required: false
type: boolean
default: false
jobs:
validate-and-create-release:
name: 🚀 Create Product Release
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.version.outputs.version }}
tag_name: ${{ steps.tag.outputs.tag_name }}
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🏃🏾‍♂️ Make scripts executable
run: |
chmod +x .github/scripts/*.sh
echo "✅ Scripts are now executable"
- name: 📖 Extract version from version file
id: version
run: |
VERSION=$(.github/scripts/extract-version.sh "${{ github.event.inputs.app }}")
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "📌 Extracted version: ${VERSION}"
- name: 🏷️ Generate tag name
id: tag
run: |
TAG_NAME=$(.github/scripts/generate-tag-name.sh \
"${{ github.event.inputs.app }}" \
"${{ github.event.inputs.environment }}" \
"${{ steps.version.outputs.version }}")
echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT
echo "🎯 Tag to create: ${TAG_NAME}"
- name: 🔍 Check if tag already exists
run: |
TAG_NAME="${{ steps.tag.outputs.tag_name }}"
if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
echo "❌ Error: Tag $TAG_NAME already exists"
echo "💡 Tip: Update the version in the version file before creating a new release"
exit 1
fi
echo "✅ Tag does not exist, proceeding..."
- name: 📋 Extract release notes from CHANGELOG
id: release_notes
run: |
.github/scripts/extract-release-notes.sh \
"${{ github.event.inputs.app }}" \
"${{ steps.version.outputs.version }}" \
"${{ github.event.inputs.environment }}" \
"${{ steps.tag.outputs.tag_name }}" \
"/tmp/release_notes.md"
echo "notes_file=/tmp/release_notes.md" >> $GITHUB_OUTPUT
- name: 🏷️ Create Git Tag
run: |
TAG_NAME="${{ steps.tag.outputs.tag_name }}"
APP="${{ github.event.inputs.app }}"
ENV="${{ github.event.inputs.environment }}"
VERSION="${{ steps.version.outputs.version }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "$TAG_NAME" -m "🚀 Release ${APP} product ${VERSION} to ${ENV}"
git push origin "$TAG_NAME"
echo "✅ Tag created and pushed: $TAG_NAME"
- name: 📦 Create GitHub Release
if: ${{ github.event.inputs.create_github_release == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
run: |
TAG_NAME="${{ steps.tag.outputs.tag_name }}"
APP="${{ github.event.inputs.app }}"
ENV="${{ github.event.inputs.environment }}"
VERSION="${{ steps.version.outputs.version }}"
# Generate release title
if [ "$APP" = "worker-mobile-app" ]; then
APP_DISPLAY="Worker Mobile Application"
else
APP_DISPLAY="Client Mobile Application"
fi
ENV_UPPER=$(echo "$ENV" | tr '[:lower:]' '[:upper:]')
RELEASE_NAME="Krow With Us - ${APP_DISPLAY} - ${ENV_UPPER} - v${VERSION}"
echo "📦 Creating GitHub Release: $RELEASE_NAME"
# Create release
if [ "${{ github.event.inputs.prerelease }}" = "true" ]; then
gh release create "$TAG_NAME" \
--title "$RELEASE_NAME" \
--notes-file "${{ steps.release_notes.outputs.notes_file }}" \
--prerelease
echo "🔖 Pre-release created successfully"
else
gh release create "$TAG_NAME" \
--title "$RELEASE_NAME" \
--notes-file "${{ steps.release_notes.outputs.notes_file }}"
echo "✅ Release created successfully"
fi
- name: 📊 Generate Release Summary
run: |
.github/scripts/create-release-summary.sh \
"${{ github.event.inputs.app }}" \
"${{ github.event.inputs.environment }}" \
"${{ steps.version.outputs.version }}" \
"${{ steps.tag.outputs.tag_name }}"
build-mobile-artifacts:
name: 📱 Build Mobile APK
runs-on: ubuntu-latest
needs: validate-and-create-release
if: ${{ github.event.inputs.app == 'worker-mobile-app' || github.event.inputs.app == 'client-mobile-app' }}
permissions:
contents: write
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🟢 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: 🔥 Install Firebase CLI
run: |
npm install -g firebase-tools
firebase --version
echo " Note: Firebase CLI installed for Data Connect SDK generation"
echo " If SDK generation fails, ensure Data Connect SDK files are committed to repo"
- name: ☕ Setup Java
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '17'
- name: 🐦 Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.38.x'
channel: 'stable'
cache: true
- name: 🔧 Install Melos
run: |
dart pub global activate melos
echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
- name: 📦 Install Dependencies
run: |
make mobile-install
- name: 🔐 Setup APK Signing
env:
# Worker Mobile (Staff App) Secrets
WORKER_KEYSTORE_DEV_BASE64: ${{ secrets.WORKER_KEYSTORE_DEV_BASE64 }}
WORKER_KEYSTORE_STAGING_BASE64: ${{ secrets.WORKER_KEYSTORE_STAGING_BASE64 }}
WORKER_KEYSTORE_PROD_BASE64: ${{ secrets.WORKER_KEYSTORE_PROD_BASE64 }}
WORKER_KEYSTORE_PASSWORD_DEV: ${{ secrets.WORKER_KEYSTORE_PASSWORD_DEV }}
WORKER_KEYSTORE_PASSWORD_STAGING: ${{ secrets.WORKER_KEYSTORE_PASSWORD_STAGING }}
WORKER_KEYSTORE_PASSWORD_PROD: ${{ secrets.WORKER_KEYSTORE_PASSWORD_PROD }}
WORKER_KEY_ALIAS_DEV: ${{ secrets.WORKER_KEY_ALIAS_DEV }}
WORKER_KEY_ALIAS_STAGING: ${{ secrets.WORKER_KEY_ALIAS_STAGING }}
WORKER_KEY_ALIAS_PROD: ${{ secrets.WORKER_KEY_ALIAS_PROD }}
WORKER_KEY_PASSWORD_DEV: ${{ secrets.WORKER_KEY_PASSWORD_DEV }}
WORKER_KEY_PASSWORD_STAGING: ${{ secrets.WORKER_KEY_PASSWORD_STAGING }}
WORKER_KEY_PASSWORD_PROD: ${{ secrets.WORKER_KEY_PASSWORD_PROD }}
# Client Mobile Secrets
CLIENT_KEYSTORE_DEV_BASE64: ${{ secrets.CLIENT_KEYSTORE_DEV_BASE64 }}
CLIENT_KEYSTORE_STAGING_BASE64: ${{ secrets.CLIENT_KEYSTORE_STAGING_BASE64 }}
CLIENT_KEYSTORE_PROD_BASE64: ${{ secrets.CLIENT_KEYSTORE_PROD_BASE64 }}
CLIENT_KEYSTORE_PASSWORD_DEV: ${{ secrets.CLIENT_KEYSTORE_PASSWORD_DEV }}
CLIENT_KEYSTORE_PASSWORD_STAGING: ${{ secrets.CLIENT_KEYSTORE_PASSWORD_STAGING }}
CLIENT_KEYSTORE_PASSWORD_PROD: ${{ secrets.CLIENT_KEYSTORE_PASSWORD_PROD }}
CLIENT_KEY_ALIAS_DEV: ${{ secrets.CLIENT_KEY_ALIAS_DEV }}
CLIENT_KEY_ALIAS_STAGING: ${{ secrets.CLIENT_KEY_ALIAS_STAGING }}
CLIENT_KEY_ALIAS_PROD: ${{ secrets.CLIENT_KEY_ALIAS_PROD }}
CLIENT_KEY_PASSWORD_DEV: ${{ secrets.CLIENT_KEY_PASSWORD_DEV }}
CLIENT_KEY_PASSWORD_STAGING: ${{ secrets.CLIENT_KEY_PASSWORD_STAGING }}
CLIENT_KEY_PASSWORD_PROD: ${{ secrets.CLIENT_KEY_PASSWORD_PROD }}
run: |
.github/scripts/setup-apk-signing.sh \
"${{ github.event.inputs.app }}" \
"${{ github.event.inputs.environment }}" \
"${{ runner.temp }}"
- name: 🏗️ Build APK
id: build_apk
run: |
APP="${{ github.event.inputs.app }}"
if [ "$APP" = "worker-mobile-app" ]; then
echo "📱 Building Staff (Worker) APK..."
make mobile-staff-build PLATFORM=apk MODE=release
APP_NAME="staff"
else
echo "📱 Building Client APK..."
make mobile-client-build PLATFORM=apk MODE=release
APP_NAME="client"
fi
# Find the generated APK (Flutter places it in build/app/outputs/flutter-apk/)
APK_PATH=$(find apps/mobile/apps/${APP_NAME}/build/app/outputs/flutter-apk -name "app-release.apk" 2>/dev/null | head -n 1)
# Fallback to searching entire apps directory if not found
if [ -z "$APK_PATH" ]; then
APK_PATH=$(find apps/mobile/apps/${APP_NAME} -name "app-release.apk" | head -n 1)
fi
if [ -z "$APK_PATH" ]; then
echo "❌ Error: APK not found!"
echo "Searched in apps/mobile/apps/${APP_NAME}/"
find apps/mobile/apps/${APP_NAME} -name "*.apk" || echo "No APK files found"
exit 1
fi
echo "✅ APK built successfully: $APK_PATH"
echo "app_name=${APP_NAME}" >> $GITHUB_OUTPUT
echo "apk_path=${APK_PATH}" >> $GITHUB_OUTPUT
- name: ✅ Verify APK Signature
run: |
.github/scripts/verify-apk-signature.sh "${{ steps.build_apk.outputs.apk_path }}"
- name: 📤 Upload APK as Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ github.event.inputs.app }}-${{ needs.validate-and-create-release.outputs.version }}-${{ github.event.inputs.environment }}
path: apps/mobile/apps/${{ steps.build_apk.outputs.app_name }}/build/app/outputs/flutter-apk/app-release.apk
if-no-files-found: error
retention-days: 30
- name: 📦 Attach APK to GitHub Release
if: ${{ github.event.inputs.create_github_release == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
run: |
.github/scripts/attach-apk-to-release.sh \
"${{ needs.validate-and-create-release.outputs.tag_name }}" \
"${{ github.event.inputs.app }}" \
"${{ steps.build_apk.outputs.app_name }}" \
"${{ needs.validate-and-create-release.outputs.version }}" \
"${{ github.event.inputs.environment }}"