Files
Krow-workspace/.github/workflows/product-release.yml

292 lines
11 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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: <EFBFBD> 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'
cache: 'npm'
cache-dependency-path: 'backend/*/package-lock.json'
- 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.24.5'
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 }}"