From 73bd4315186e5cb0e88d980c0a90e324425772ff Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 11:10:03 -0500 Subject: [PATCH 01/11] docs(mobile): add M3 milestone CHANGELOGs for staff and client apps --- apps/mobile/apps/client_app/CHANGELOG.md | 110 +++++++++++++++++++++++ apps/mobile/apps/staff_app/CHANGELOG.md | 74 +++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 apps/mobile/apps/client_app/CHANGELOG.md create mode 100644 apps/mobile/apps/staff_app/CHANGELOG.md diff --git a/apps/mobile/apps/client_app/CHANGELOG.md b/apps/mobile/apps/client_app/CHANGELOG.md new file mode 100644 index 00000000..6388273c --- /dev/null +++ b/apps/mobile/apps/client_app/CHANGELOG.md @@ -0,0 +1,110 @@ +# Client Mobile App - Change Log + +## [0.0.1-M3] - Milestone 3 - 2026-02-15 + +### Added - Authentication & Onboarding +- Business email and password authentication +- Client account registration +- Business onboarding flow +- Company information setup + +### Added - Home Dashboard +- Welcome screen with business name +- Coverage statistics for today: + - Coverage percentage + - Workers checked in vs needed + - Open positions count +- Late workers alerts with visual indicators +- Today's estimated labor cost +- Upcoming shifts section +- Quick action buttons: + - RAPID (urgent same-day coverage) + - Create Order + - Hubs management + +### Added - Hub Management +- Hubs page accessible from settings +- Hub creation flow: + - Hub name input + - Address autocomplete with Google Maps Places API + - Hub creation confirmation +- Hubs list view showing all created hubs +- Hub card display with name, address, and tag ID + +### Added - Order Creation +- Orders tab in bottom navigation +- "+ Post" button to create new orders +- Order type selection screen: + - One-Time orders (implemented) + - RAPID orders (placeholder) + - Recurring orders (planned) + - Permanent orders (planned) +- One-Time Order creation form: + - Order name + - Date picker + - Hub selection + - Position management: + - Role selection + - Worker count + - Start/end time + - Shift duration calculation + - Cost estimation +- Order creation confirmation + +### Added - Order Management +- Orders list view with: + - Order cards showing date, location, time + - Worker count (filled/needed) + - Coverage percentage bar + - Status indicators (OPEN, FILLED, IN PROGRESS) +- Order details view: + - Event name and location + - Roles and worker requirements + - Clock in/out times + - Estimated cost + - Coverage percentage + - Map integration with directions + +### Added - Coverage Monitoring +- Coverage tab in bottom navigation +- Real-time worker status dashboard: + - Checked In (green indicator) + - En Route (yellow indicator) + - Late (red indicator) + - Not Arrived status +- Color-coded status badges +- Worker information cards +- Active shift monitoring + +### Added - Navigation +- Bottom navigation bar with tabs: + - Coverage + - Billing + - Home + - Orders + - Reports +- Settings menu accessible from home screen +- Back navigation handling + +### Added - Settings +- Settings page with options: + - Hubs management + - Profile editing + - Notifications preferences + - Log out + +### Technical Features +- Firebase authentication integration +- Data Connect backend integration +- Google Maps Places API for address autocomplete +- Real-time worker status tracking +- Cost calculation engine +- Coverage percentage calculations + +### Known Limitations +- Orders require hub assignment +- Currently supports one-time orders only +- Order approval flow not yet implemented +- RAPID, Recurring, and Permanent order types are placeholders + +--- diff --git a/apps/mobile/apps/staff_app/CHANGELOG.md b/apps/mobile/apps/staff_app/CHANGELOG.md new file mode 100644 index 00000000..8d4c26e9 --- /dev/null +++ b/apps/mobile/apps/staff_app/CHANGELOG.md @@ -0,0 +1,74 @@ +# Staff Mobile App - Change Log + +## [0.0.1-M3] - Milestone 3 - 2026-02-15 + +### Added - Authentication & Onboarding +- Phone number authentication with OTP verification +- Staff onboarding flow with profile setup +- Personal information collection (name, bio, languages) +- Preferred work locations selection +- Skills and industry selection + +### Added - Home Dashboard +- Welcome screen with personalized greeting +- Today's shifts section showing confirmed shifts +- Tomorrow's shifts preview +- Recommended shifts section based on profile +- Quick action buttons (Find Shifts, Availability, Messages, Earnings) + +### Added - Shift Management +- Find Shifts functionality to discover available work +- Shift details view showing: + - Business name and location + - Hourly rate and estimated earnings + - Date, start time, end time + - Job requirements + - Map integration with directions +- Shift booking/application process +- Booking confirmation dialog +- My Shifts view with week-by-week navigation +- Color-coded shift status (Confirmed, Pending, Completed) + +### Added - Clock In/Out +- Clock In page with slider interaction +- Clock Out page with slider interaction +- Automatic timestamp recording +- Shift status updates upon clock in/out +- Visual status indicators (green for checked in) + +### Added - Profile Management +- Profile tab with personal information +- Emergency Contact management: + - Contact name + - Relationship + - Phone number +- Bank Account linking for direct deposit +- Tax Forms section: + - W-4 form access + - I-9 form access +- Time Card view: + - Historical shift records + - Hours worked tracking + - Earnings history + +### Added - Navigation +- Bottom navigation bar with 5 tabs: + - Shifts + - Payments + - Home + - Clock In + - Profile +- Tab bar hiding on specific pages + +### Technical Features +- Firebase authentication integration +- Data Connect backend integration +- Google Maps integration for locations +- Phone verification system +- OTP code handling + +### Known Limitations +- Newly created orders don't appear immediately in Find Shifts (requires vendor approval) +- Limited to one-time order types in this milestone + +--- From dbbf54287f93c86e9cca064e4445b2966097255a Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 12:40:13 -0500 Subject: [PATCH 02/11] Add GitHub workflows, release scripts, PR template Add CI/CD and release automation assets: new GitHub Actions workflows (backend-foundation, hotfix-branch-creation, mobile-ci, product-release, web-quality), shell scripts for version/tag/release-note extraction and release-summary generation (.github/scripts/*), and a Pull Request template. Implements hotfix branch creation from tags, automatic tag name generation, version extraction from pubspec.yaml, CHANGELOG-based release notes extraction, selective mobile CI (detects changed files, builds and lints only affected Dart files), backend service test dry-runs, and automated GitHub release creation with summaries. --- .github/PULL_REQUEST_TEMPLATE.md | 101 ++++++ .github/scripts/create-release-summary.sh | 73 ++++ .github/scripts/extract-release-notes.sh | 65 ++++ .github/scripts/extract-version.sh | 48 +++ .github/scripts/generate-tag-name.sh | 22 ++ .github/workflows/backend-foundation.yml | 64 ++++ .github/workflows/hotfix-branch-creation.yml | 331 +++++++++++++++++++ .github/workflows/mobile-ci.yml | 248 ++++++++++++++ .github/workflows/product-release.yml | 145 ++++++++ .github/workflows/web-quality.yml | 59 ++++ 10 files changed, 1156 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100755 .github/scripts/create-release-summary.sh create mode 100755 .github/scripts/extract-release-notes.sh create mode 100755 .github/scripts/extract-version.sh create mode 100755 .github/scripts/generate-tag-name.sh create mode 100644 .github/workflows/backend-foundation.yml create mode 100644 .github/workflows/hotfix-branch-creation.yml create mode 100644 .github/workflows/mobile-ci.yml create mode 100644 .github/workflows/product-release.yml create mode 100644 .github/workflows/web-quality.yml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..c7a2d1c5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,101 @@ +## ๐Ÿ“‹ Description + + + + +--- + +## ๐ŸŽฏ Type of Change + + + +- [ ] ๐Ÿ› **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 + + + +- [ ] ๐Ÿ“ฑ **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) + +--- + +## ๐Ÿ”— Related Issues + + + +Closes # +Related to # + +--- + +## โœ… Testing + + + +**Test Details:** + + + +--- + +## ๐Ÿ”„ Breaking Changes + + + +- [ ] No breaking changes +- [ ] Yes, breaking changes: + +**Details:** + + + +--- + +## ๐ŸŽฏ Checklist + + + +- [ ] 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 + + + + +--- + +## ๐Ÿ” Review Checklist for Maintainers + +- [ ] Code quality and readability +- [ ] Design patterns follow project conventions +- [ ] Test coverage is adequate +- [ ] Performance implications reviewed +- [ ] Security concerns addressed +- [ ] Documentation is complete +- [ ] Breaking changes properly communicated +- [ ] Cross-platform compatibility (if applicable) diff --git a/.github/scripts/create-release-summary.sh b/.github/scripts/create-release-summary.sh new file mode 100755 index 00000000..ddefb1d9 --- /dev/null +++ b/.github/scripts/create-release-summary.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# Generate release summary for GitHub Actions +# Usage: ./create-release-summary.sh + +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 " + 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" diff --git a/.github/scripts/extract-release-notes.sh b/.github/scripts/extract-release-notes.sh new file mode 100755 index 00000000..f29530fe --- /dev/null +++ b/.github/scripts/extract-release-notes.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# Extract release notes from CHANGELOG for a specific version +# Usage: ./extract-release-notes.sh + +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" + echo "Usage: ./extract-release-notes.sh " + 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" + + # Extract section for this version + # Look for ## [VERSION] and collect until next ## [ or end of file + NOTES=$(awk "/## \[${VERSION}\]/,/^## \[/" "$CHANGELOG_PATH" | sed '1d;$d' | sed '/^$/d') + + if [ -z "$NOTES" ]; then + echo "โš ๏ธ Warning: No CHANGELOG entry found for version $VERSION" + NOTES="Release $VERSION for $APP_NAME + +โš ๏ธ No CHANGELOG entry found for this version. Please update the CHANGELOG manually. + +**Environment:** $ENV +**Tag:** $TAG_NAME" + else + echo "โœ… Extracted release notes for version $VERSION" + NOTES="# $APP_NAME - Release $VERSION + +$NOTES + +--- + +**Environment:** $ENV +**Tag:** $TAG_NAME" + fi +else + echo "โš ๏ธ Warning: CHANGELOG not found at $CHANGELOG_PATH" + NOTES="Release $VERSION for $APP_NAME + +**Environment:** $ENV +**Tag:** $TAG_NAME" +fi + +# Save to output file +echo "$NOTES" > "$OUTPUT_FILE" +echo "โœ… Release notes saved to $OUTPUT_FILE" diff --git a/.github/scripts/extract-version.sh b/.github/scripts/extract-version.sh new file mode 100755 index 00000000..88d97dd8 --- /dev/null +++ b/.github/scripts/extract-version.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# Extract version from version file for products +# Usage: ./extract-version.sh +# 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)" + 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" + exit 1 +fi + +# Extract version (format: X.Y.Z+buildNumber) +VERSION_LINE=$(grep "^version:" "$PUBSPEC_PATH") +if [ -z "$VERSION_LINE" ]; then + echo "โŒ Error: Could not find version in $PUBSPEC_PATH" + exit 1 +fi + +# Extract just the semantic version (before the +) +VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//' | sed 's/+.*//' | tr -d ' ') + +# Validate version format +if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "โŒ Error: Invalid version format in pubspec.yaml: $VERSION" + echo "Expected format: X.Y.Z (e.g., 0.1.0)" + exit 1 +fi + +echo "โœ… Extracted version from $PUBSPEC_PATH: $VERSION" +echo "$VERSION" diff --git a/.github/scripts/generate-tag-name.sh b/.github/scripts/generate-tag-name.sh new file mode 100755 index 00000000..c779b542 --- /dev/null +++ b/.github/scripts/generate-tag-name.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Generate tag name for product release +# Usage: ./generate-tag-name.sh + +set -e + +APP=$1 +ENV=$2 +VERSION=$3 + +if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$VERSION" ]; then + echo "โŒ Error: Missing required parameters" + echo "Usage: ./generate-tag-name.sh " + 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" diff --git a/.github/workflows/backend-foundation.yml b/.github/workflows/backend-foundation.yml new file mode 100644 index 00000000..0e408f8f --- /dev/null +++ b/.github/workflows/backend-foundation.yml @@ -0,0 +1,64 @@ +name: Backend Foundation + +on: + pull_request: + branches: + - dev + - main + push: + branches: + - dev + - main + +jobs: + backend-foundation-makefile: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Validate backend make targets + run: | + make backend-help + make help | grep "backend-" + + - name: Dry-run backend automation targets + run: | + make -n backend-enable-apis ENV=dev + make -n backend-bootstrap-dev ENV=dev + make -n backend-deploy-core ENV=dev + make -n backend-deploy-commands ENV=dev + make -n backend-deploy-workers ENV=dev + make -n backend-smoke-core ENV=dev + make -n backend-smoke-commands ENV=dev + make -n backend-logs-core ENV=dev + + backend-services-tests: + runs-on: ubuntu-latest + strategy: + matrix: + service: + - backend/core-api + - backend/command-api + defaults: + run: + working-directory: ${{ matrix.service }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: ${{ matrix.service }}/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Run tests + env: + AUTH_BYPASS: "true" + LLM_MOCK: "true" + run: npm test diff --git a/.github/workflows/hotfix-branch-creation.yml b/.github/workflows/hotfix-branch-creation.yml new file mode 100644 index 00000000..2cb77a7a --- /dev/null +++ b/.github/workflows/hotfix-branch-creation.yml @@ -0,0 +1,331 @@ +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) + + # Create hotfix entry + HOTFIX_ENTRY="## [${HOTFIX_VERSION}] - ${DATE} - HOTFIX + +### Fixed +- ${ISSUE} + +--- + +" + + # Insert after the first line (title) + sed -i "1 a\\ +\\ +$HOTFIX_ENTRY" "$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 + + +### Solution + + +### Testing + + +--- + +## โš ๏ธ 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 diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml new file mode 100644 index 00000000..1a439740 --- /dev/null +++ b/.github/workflows/mobile-ci.yml @@ -0,0 +1,248 @@ +name: Mobile CI + +on: + pull_request: + paths: + - 'apps/mobile/**' + - '.github/workflows/mobile-ci.yml' + push: + branches: + - main + paths: + - 'apps/mobile/**' + - '.github/workflows/mobile-ci.yml' + +jobs: + detect-changes: + name: ๐Ÿ” Detect Mobile Changes + runs-on: ubuntu-latest + outputs: + mobile-changed: ${{ steps.detect.outputs.mobile-changed }} + changed-files: ${{ steps.detect.outputs.changed-files }} + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: ๐Ÿ”Ž Detect changes in apps/mobile + id: detect + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + # For PR, compare all changes against base branch (not just latest commit) + # Using three-dot syntax (...) shows all files changed in the PR branch + BASE_REF="${{ github.event.pull_request.base.ref }}" + CHANGED_FILES=$(git diff --name-only origin/$BASE_REF...HEAD 2>/dev/null || echo "") + else + # For push, compare with previous commit + if [[ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]]; then + # Initial commit, check all files + CHANGED_FILES=$(git ls-tree -r --name-only HEAD) + else + CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }}) + fi + fi + + # Filter for files in apps/mobile + MOBILE_CHANGED=$(echo "$CHANGED_FILES" | grep -c "^apps/mobile/" || echo "0") + + if [[ $MOBILE_CHANGED -gt 0 ]]; then + echo "mobile-changed=true" >> $GITHUB_OUTPUT + # Get list of changed Dart files in apps/mobile + MOBILE_FILES=$(echo "$CHANGED_FILES" | grep "^apps/mobile/" | grep "\.dart$" || echo "") + echo "changed-files<> $GITHUB_OUTPUT + echo "$MOBILE_FILES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "โœ… Changes detected in apps/mobile/" + echo "๐Ÿ“ Changed files:" + echo "$MOBILE_FILES" + else + echo "mobile-changed=false" >> $GITHUB_OUTPUT + echo "changed-files=" >> $GITHUB_OUTPUT + echo "โญ๏ธ No changes detected in apps/mobile/ - skipping checks" + fi + + compile: + name: ๐Ÿ—๏ธ Compile Mobile App + runs-on: macos-latest + needs: detect-changes + if: needs.detect-changes.outputs.mobile-changed == 'true' + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + + - name: ๐Ÿฆ‹ Set up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.38.x' + channel: 'stable' + cache: true + + - name: ๐Ÿ”ง Install Firebase CLI + run: | + npm install -g firebase-tools + + - name: ๐Ÿ“ฆ Get Flutter dependencies + run: | + make mobile-install + + - name: ๐Ÿ”จ Run compilation check + run: | + set -o pipefail + + echo "๐Ÿ—๏ธ Building client app for Android (dev mode)..." + if ! make mobile-client-build PLATFORM=apk MODE=debug 2>&1 | tee client_build.txt; then + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "โŒ CLIENT APP BUILD FAILED" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + exit 1 + fi + + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + + echo "๐Ÿ—๏ธ Building staff app for Android (dev mode)..." + if ! make mobile-staff-build PLATFORM=apk MODE=debug 2>&1 | tee staff_build.txt; then + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "โŒ STAFF APP BUILD FAILED" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + exit 1 + fi + + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "โœ… Build check PASSED - Both apps built successfully" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + + lint: + name: ๐Ÿงน Lint Changed Files + runs-on: macos-latest + needs: detect-changes + if: needs.detect-changes.outputs.mobile-changed == 'true' && needs.detect-changes.outputs.changed-files != '' + steps: + - name: ๐Ÿ“ฅ Checkout repository + uses: actions/checkout@v4 + + - name: ๐Ÿฆ‹ Set up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.38.x' + channel: 'stable' + cache: true + + - name: ๐Ÿ”ง Install Firebase CLI + run: | + npm install -g firebase-tools + + - name: ๐Ÿ“ฆ Get Flutter dependencies + run: | + make mobile-install + + - name: ๐Ÿ” Lint changed Dart files + run: | + set -o pipefail + + # Get the list of changed files + CHANGED_FILES="${{ needs.detect-changes.outputs.changed-files }}" + + if [[ -z "$CHANGED_FILES" ]]; then + echo "โญ๏ธ No Dart files changed, skipping lint" + exit 0 + fi + + echo "๐ŸŽฏ Running lint on changed files:" + echo "$CHANGED_FILES" + echo "" + + # Run dart analyze on each changed file + HAS_ERRORS=false + FAILED_FILES=() + + while IFS= read -r file; do + if [[ -n "$file" && "$file" == *.dart && -f "$file" ]]; then + echo "๐Ÿ“ Analyzing: $file" + + if ! dart analyze "$file" 2>&1 | tee -a lint_output.txt; then + HAS_ERRORS=true + FAILED_FILES+=("$file") + fi + echo "" + fi + done <<< "$CHANGED_FILES" + + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + + # Check if there were any errors + if [[ "$HAS_ERRORS" == "true" ]]; then + echo "โŒ LINT ERRORS FOUND IN ${#FAILED_FILES[@]} FILE(S):" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + for file in "${FAILED_FILES[@]}"; do + echo " โŒ $file" + done + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "" + echo "See details above for each file" + exit 1 + else + echo "โœ… Lint check PASSED for all changed files" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + fi + + status-check: + name: ๐Ÿ“Š CI Status Check + runs-on: ubuntu-latest + needs: [detect-changes, compile, lint] + if: always() + steps: + - name: ๐Ÿ” Check mobile changes detected + run: | + if [[ "${{ needs.detect-changes.outputs.mobile-changed }}" == "true" ]]; then + echo "โœ… Mobile changes detected - running full checks" + else + echo "โญ๏ธ No mobile changes detected - skipping checks" + fi + + - name: ๐Ÿ—๏ธ Report compilation status + if: needs.detect-changes.outputs.mobile-changed == 'true' + run: | + if [[ "${{ needs.compile.result }}" == "success" ]]; then + echo "โœ… Compilation check: PASSED" + else + echo "โŒ Compilation check: FAILED" + exit 1 + fi + + - name: ๐Ÿงน Report lint status + if: needs.detect-changes.outputs.mobile-changed == 'true' && needs.detect-changes.outputs.changed-files != '' + run: | + if [[ "${{ needs.lint.result }}" == "success" ]]; then + echo "โœ… Lint check: PASSED" + else + echo "โŒ Lint check: FAILED" + exit 1 + fi + + - name: ๐ŸŽ‰ Final status + if: always() + run: | + echo "" + echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" + echo "โ•‘ ๐Ÿ“Š Mobile CI Pipeline Summary โ•‘" + echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" + echo "" + echo "๐Ÿ” Change Detection: ${{ needs.detect-changes.result }}" + echo "๐Ÿ—๏ธ Compilation: ${{ needs.compile.result }}" + echo "๐Ÿงน Lint Check: ${{ needs.lint.result }}" + echo "" + + if [[ "${{ needs.detect-changes.result }}" != "success" || \ + ("${{ needs.detect-changes.outputs.mobile-changed }}" == "true" && \ + ("${{ needs.compile.result }}" != "success" || "${{ needs.lint.result }}" != "success")) ]]; then + echo "โŒ Pipeline FAILED" + exit 1 + else + echo "โœ… Pipeline PASSED" + fi + diff --git a/.github/workflows/product-release.yml b/.github/workflows/product-release.yml new file mode 100644 index 00000000..966e405a --- /dev/null +++ b/.github/workflows/product-release.yml @@ -0,0 +1,145 @@ +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 + + 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 }}" diff --git a/.github/workflows/web-quality.yml b/.github/workflows/web-quality.yml new file mode 100644 index 00000000..7280b333 --- /dev/null +++ b/.github/workflows/web-quality.yml @@ -0,0 +1,59 @@ +name: Web Quality + +on: + pull_request: + branches: + - dev + - main + push: + branches: + - dev + - main + +jobs: + web-quality: + runs-on: ubuntu-latest + defaults: + run: + working-directory: apps/web + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + run_install: false + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + cache-dependency-path: apps/web/pnpm-lock.yaml + + - name: Setup Firebase CLI + working-directory: . + run: npm install -g firebase-tools + + - name: Generate Data Connect SDK + working-directory: . + run: | + cp backend/dataconnect/dataconnect.dev.yaml backend/dataconnect/dataconnect.yaml + firebase dataconnect:sdk:generate --non-interactive + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm lint + + - name: Typecheck + run: pnpm typecheck + + - name: Test + run: pnpm test + + - name: Build + run: pnpm build From 4cc2dafa1861fe11bee2da417e727c7609f9b85b Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 12:40:59 -0500 Subject: [PATCH 03/11] Normalize mobile app pubspec versions to 0.0.1-m3 Standardize prerelease version tags for mobile apps. Updated client and staff pubspecs to use 0.0.1-m3 instead of their previous Iliana*-M3 suffixed versions: - apps/mobile/apps/client/pubspec.yaml: 0.0.1-IlianaClientM3 -> 0.0.1-m3 - apps/mobile/apps/staff/pubspec.yaml: 0.0.1-IlianaStaffM3 -> 0.0.1-m3 This keeps version naming consistent across the mobile projects. --- apps/mobile/apps/client/pubspec.yaml | 2 +- apps/mobile/apps/staff/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mobile/apps/client/pubspec.yaml b/apps/mobile/apps/client/pubspec.yaml index 101a2b77..3826d314 100644 --- a/apps/mobile/apps/client/pubspec.yaml +++ b/apps/mobile/apps/client/pubspec.yaml @@ -1,7 +1,7 @@ name: krowwithus_client description: "Krow Client Application" publish_to: "none" -version: 0.0.1-IlianaClientM3 +version: 0.0.1-m3 resolution: workspace environment: diff --git a/apps/mobile/apps/staff/pubspec.yaml b/apps/mobile/apps/staff/pubspec.yaml index 8bc77687..ad7d8e5a 100644 --- a/apps/mobile/apps/staff/pubspec.yaml +++ b/apps/mobile/apps/staff/pubspec.yaml @@ -1,7 +1,7 @@ name: krowwithus_staff description: "Krow Staff Application" publish_to: 'none' -version: 0.0.1-IlianaStaffM3 +version: 0.0.1-m3 resolution: workspace environment: From bdacedbced77637e66dd1b47603e655e4a4ec56a Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 14:03:21 -0500 Subject: [PATCH 04/11] Add mobile APK signing, build and release scripts Add four new helper scripts for mobile APK workflows: setup-apk-signing.sh (decode keystores and export signing env vars), verify-apk-signature.sh (check and display APK certificate info), attach-apk-to-release.sh (rename and upload APK to a GitHub Release), and setup-mobile-github-secrets.sh (helper to generate/show required GitHub Secrets). Update product-release.yml to expose version/tag outputs and add a build-mobile-artifacts job that sets up Java/Flutter, installs deps, configures signing from repository secrets, builds APKs for worker/client apps, verifies signatures, uploads artifacts, and optionally attaches the APK to the GitHub Release. Secrets and envvar naming conventions are handled to support dev/staging/prod keystores; documentation references (docs/RELEASE/APK_SIGNING_SETUP.md) are noted in scripts. --- .github/scripts/attach-apk-to-release.sh | 60 ++++ .github/scripts/setup-apk-signing.sh | 102 +++++++ .../scripts/setup-mobile-github-secrets.sh | 262 ++++++++++++++++++ .github/scripts/verify-apk-signature.sh | 59 ++++ .github/workflows/product-release.yml | 146 ++++++++++ 5 files changed, 629 insertions(+) create mode 100755 .github/scripts/attach-apk-to-release.sh create mode 100755 .github/scripts/setup-apk-signing.sh create mode 100755 .github/scripts/setup-mobile-github-secrets.sh create mode 100755 .github/scripts/verify-apk-signature.sh diff --git a/.github/scripts/attach-apk-to-release.sh b/.github/scripts/attach-apk-to-release.sh new file mode 100755 index 00000000..174023aa --- /dev/null +++ b/.github/scripts/attach-apk-to-release.sh @@ -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 +# +# 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" + echo "Usage: $0 " + 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" + echo "Searching for APK files..." + 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..." +gh release upload "$TAG_NAME" "/tmp/$APK_NAME" --clobber + +echo "โœ… APK attached to release: $APK_NAME" diff --git a/.github/scripts/setup-apk-signing.sh b/.github/scripts/setup-apk-signing.sh new file mode 100755 index 00000000..fe982f6a --- /dev/null +++ b/.github/scripts/setup-apk-signing.sh @@ -0,0 +1,102 @@ +#!/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 +# +# 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" + echo "Usage: $0 " + exit 1 +fi + +echo "๐Ÿ” Setting up Android signing for $APP in $ENV environment..." + +# 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!" + echo "โš ๏ธ APK will be built UNSIGNED for $ENV environment." + echo "โš ๏ธ Please configure GitHub Secrets as documented in docs/RELEASE/APK_SIGNING_SETUP.md" + 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!" + exit 1 +fi + +echo "โœ… Keystore decoded successfully" +echo "๐Ÿ“ฆ Keystore size: $(ls -lh "$KEYSTORE_PATH" | awk '{print $5}')" + +# Export environment variables for build.gradle.kts +# Using CodeMagic-compatible variable names +echo "CI=true" >> $GITHUB_ENV +echo "CM_KEYSTORE_PATH_${APP_NAME}=$KEYSTORE_PATH" >> $GITHUB_ENV +echo "CM_KEYSTORE_PASSWORD_${APP_NAME}=$KEYSTORE_PASSWORD" >> $GITHUB_ENV +echo "CM_KEY_ALIAS_${APP_NAME}=$KEY_ALIAS" >> $GITHUB_ENV +echo "CM_KEY_PASSWORD_${APP_NAME}=$KEY_PASSWORD" >> $GITHUB_ENV + +echo "โœ… Signing environment configured for $APP_NAME ($ENV environment)" +echo "๐Ÿ”‘ Using key alias: $KEY_ALIAS" diff --git a/.github/scripts/setup-mobile-github-secrets.sh b/.github/scripts/setup-mobile-github-secrets.sh new file mode 100755 index 00000000..3645bb82 --- /dev/null +++ b/.github/scripts/setup-mobile-github-secrets.sh @@ -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 "" diff --git a/.github/scripts/verify-apk-signature.sh b/.github/scripts/verify-apk-signature.sh new file mode 100755 index 00000000..16832d02 --- /dev/null +++ b/.github/scripts/verify-apk-signature.sh @@ -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 +# +# 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" + echo "Usage: $0 " + exit 1 +fi + +if [ ! -f "$APK_PATH" ]; then + echo "โŒ APK not found at: $APK_PATH" + exit 1 +fi + +echo "๐Ÿ” Verifying APK signature..." + +# Check if APK is signed +if jarsigner -verify -verbose "$APK_PATH" 2>&1 | grep -q "jar verified"; then + echo "โœ… APK is properly signed!" + + # Extract certificate details + echo "" + echo "๐Ÿ“œ Certificate Details:" + jarsigner -verify -verbose -certs "$APK_PATH" 2>&1 | grep -A 3 "X.509" || true + + # Get signer info + echo "" + echo "๐Ÿ”‘ Signer Information:" + keytool -printcert -jarfile "$APK_PATH" | head -n 15 + +else + echo "โš ๏ธ WARNING: APK signature verification failed or APK is unsigned!" + echo "" + echo "This may happen if:" + echo " 1. GitHub Secrets are not configured for this environment" + echo " 2. Keystore credentials are incorrect" + echo " 3. Build configuration didn't apply signing" + echo "" + echo "See: docs/RELEASE/APK_SIGNING_SETUP.md for setup instructions" + + # Don't fail the build, just warn + # exit 1 +fi diff --git a/.github/workflows/product-release.yml b/.github/workflows/product-release.yml index 966e405a..f3f3930c 100644 --- a/.github/workflows/product-release.yml +++ b/.github/workflows/product-release.yml @@ -35,6 +35,9 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + outputs: + version: ${{ steps.version.outputs.version }} + tag_name: ${{ steps.tag.outputs.tag_name }} steps: - name: ๐Ÿ“ฅ Checkout repository @@ -143,3 +146,146 @@ jobs: "${{ 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 }}" From be430300589f2681a8d6210c6863cab2a012a327 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 14:10:05 -0500 Subject: [PATCH 05/11] fix(ci): redirect script messages to stderr and support version format X.Y.Z-suffix Fixed workflow failure by ensuring only data goes to stdout, not informational messages. Also added support for version format X.Y.Z-suffix in addition to X.Y.Z+build. --- .github/scripts/attach-apk-to-release.sh | 12 ++++----- .github/scripts/extract-release-notes.sh | 14 +++++----- .github/scripts/extract-version.sh | 18 ++++++------- .github/scripts/generate-tag-name.sh | 4 +-- .github/scripts/setup-apk-signing.sh | 22 +++++++-------- .github/scripts/verify-apk-signature.sh | 34 ++++++++++++------------ 6 files changed, 52 insertions(+), 52 deletions(-) diff --git a/.github/scripts/attach-apk-to-release.sh b/.github/scripts/attach-apk-to-release.sh index 174023aa..4491178f 100755 --- a/.github/scripts/attach-apk-to-release.sh +++ b/.github/scripts/attach-apk-to-release.sh @@ -28,8 +28,8 @@ VERSION="$4" ENV="$5" if [ -z "$TAG_NAME" ] || [ -z "$APP" ] || [ -z "$APP_NAME" ] || [ -z "$VERSION" ] || [ -z "$ENV" ]; then - echo "โŒ Error: Missing required arguments" - echo "Usage: $0 " + echo "โŒ Error: Missing required arguments" >&2 + echo "Usage: $0 " >&2 exit 1 fi @@ -37,8 +37,8 @@ fi 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" - echo "Searching for APK files..." + 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 @@ -54,7 +54,7 @@ fi cp "$APK_PATH" "/tmp/$APK_NAME" # Upload to GitHub Release -echo "๐Ÿ“ค Uploading $APK_NAME to release $TAG_NAME..." +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" +echo "โœ… APK attached to release: $APK_NAME" >&2 diff --git a/.github/scripts/extract-release-notes.sh b/.github/scripts/extract-release-notes.sh index f29530fe..5d064a7b 100755 --- a/.github/scripts/extract-release-notes.sh +++ b/.github/scripts/extract-release-notes.sh @@ -11,8 +11,8 @@ 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" - echo "Usage: ./extract-release-notes.sh " + echo "โŒ Error: Missing required parameters" >&2 + echo "Usage: ./extract-release-notes.sh " >&2 exit 1 fi @@ -27,14 +27,14 @@ fi # Try to extract release notes for this version if [ -f "$CHANGELOG_PATH" ]; then - echo "๐Ÿ“ Found CHANGELOG at $CHANGELOG_PATH" + echo "๐Ÿ“ Found CHANGELOG at $CHANGELOG_PATH" >&2 # Extract section for this version # Look for ## [VERSION] and collect until next ## [ or end of file NOTES=$(awk "/## \[${VERSION}\]/,/^## \[/" "$CHANGELOG_PATH" | sed '1d;$d' | sed '/^$/d') if [ -z "$NOTES" ]; then - echo "โš ๏ธ Warning: No CHANGELOG entry found for version $VERSION" + echo "โš ๏ธ Warning: No CHANGELOG entry found for version $VERSION" >&2 NOTES="Release $VERSION for $APP_NAME โš ๏ธ No CHANGELOG entry found for this version. Please update the CHANGELOG manually. @@ -42,7 +42,7 @@ if [ -f "$CHANGELOG_PATH" ]; then **Environment:** $ENV **Tag:** $TAG_NAME" else - echo "โœ… Extracted release notes for version $VERSION" + echo "โœ… Extracted release notes for version $VERSION" >&2 NOTES="# $APP_NAME - Release $VERSION $NOTES @@ -53,7 +53,7 @@ $NOTES **Tag:** $TAG_NAME" fi else - echo "โš ๏ธ Warning: CHANGELOG not found at $CHANGELOG_PATH" + echo "โš ๏ธ Warning: CHANGELOG not found at $CHANGELOG_PATH" >&2 NOTES="Release $VERSION for $APP_NAME **Environment:** $ENV @@ -62,4 +62,4 @@ fi # Save to output file echo "$NOTES" > "$OUTPUT_FILE" -echo "โœ… Release notes saved to $OUTPUT_FILE" +echo "โœ… Release notes saved to $OUTPUT_FILE" >&2 diff --git a/.github/scripts/extract-version.sh b/.github/scripts/extract-version.sh index 88d97dd8..5f6507bd 100755 --- a/.github/scripts/extract-version.sh +++ b/.github/scripts/extract-version.sh @@ -8,7 +8,7 @@ set -e APP=$1 if [ -z "$APP" ]; then - echo "โŒ Error: App parameter required (worker-mobile-app or client-mobile-app)" + echo "โŒ Error: App parameter required (worker-mobile-app or client-mobile-app)" >&2 exit 1 fi @@ -23,26 +23,26 @@ fi # Check if pubspec exists if [ ! -f "$PUBSPEC_PATH" ]; then - echo "โŒ Error: pubspec.yaml not found at $PUBSPEC_PATH" + echo "โŒ Error: pubspec.yaml not found at $PUBSPEC_PATH" >&2 exit 1 fi -# Extract version (format: X.Y.Z+buildNumber) +# 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" + echo "โŒ Error: Could not find version in $PUBSPEC_PATH" >&2 exit 1 fi -# Extract just the semantic version (before the +) -VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//' | sed 's/+.*//' | tr -d ' ') +# Extract just the semantic version (before the + or -) +VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//' | sed 's/[+\-].*//' | tr -d ' ') # Validate version format if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "โŒ Error: Invalid version format in pubspec.yaml: $VERSION" - echo "Expected format: X.Y.Z (e.g., 0.1.0)" + echo "โŒ Error: Invalid version format in pubspec.yaml: $VERSION" >&2 + echo "Expected format: X.Y.Z (e.g., 0.1.0)" >&2 exit 1 fi -echo "โœ… Extracted version from $PUBSPEC_PATH: $VERSION" +echo "โœ… Extracted version from $PUBSPEC_PATH: $VERSION" >&2 echo "$VERSION" diff --git a/.github/scripts/generate-tag-name.sh b/.github/scripts/generate-tag-name.sh index c779b542..8376a217 100755 --- a/.github/scripts/generate-tag-name.sh +++ b/.github/scripts/generate-tag-name.sh @@ -9,8 +9,8 @@ ENV=$2 VERSION=$3 if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$VERSION" ]; then - echo "โŒ Error: Missing required parameters" - echo "Usage: ./generate-tag-name.sh " + echo "โŒ Error: Missing required parameters" >&2 + echo "Usage: ./generate-tag-name.sh " >&2 exit 1 fi diff --git a/.github/scripts/setup-apk-signing.sh b/.github/scripts/setup-apk-signing.sh index fe982f6a..197df4eb 100755 --- a/.github/scripts/setup-apk-signing.sh +++ b/.github/scripts/setup-apk-signing.sh @@ -32,12 +32,12 @@ ENV="$2" TEMP_DIR="$3" if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$TEMP_DIR" ]; then - echo "โŒ Error: Missing required arguments" - echo "Usage: $0 " + echo "โŒ Error: Missing required arguments" >&2 + echo "Usage: $0 " >&2 exit 1 fi -echo "๐Ÿ” Setting up Android signing for $APP in $ENV environment..." +echo "๐Ÿ” Setting up Android signing for $APP in $ENV environment..." >&2 # Determine which keystore to use if [ "$APP" = "worker-mobile-app" ]; then @@ -68,9 +68,9 @@ 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!" - echo "โš ๏ธ APK will be built UNSIGNED for $ENV environment." - echo "โš ๏ธ Please configure GitHub Secrets as documented in docs/RELEASE/APK_SIGNING_SETUP.md" + 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 @@ -83,12 +83,12 @@ KEYSTORE_PATH="$KEYSTORE_DIR/release.jks" echo "$KEYSTORE_BASE64" | base64 -d > "$KEYSTORE_PATH" if [ ! -f "$KEYSTORE_PATH" ]; then - echo "โŒ Failed to decode keystore!" + echo "โŒ Failed to decode keystore!" >&2 exit 1 fi -echo "โœ… Keystore decoded successfully" -echo "๐Ÿ“ฆ Keystore size: $(ls -lh "$KEYSTORE_PATH" | awk '{print $5}')" +echo "โœ… Keystore decoded successfully" >&2 +echo "๐Ÿ“ฆ Keystore size: $(ls -lh "$KEYSTORE_PATH" | awk '{print $5}')" >&2 # Export environment variables for build.gradle.kts # Using CodeMagic-compatible variable names @@ -98,5 +98,5 @@ echo "CM_KEYSTORE_PASSWORD_${APP_NAME}=$KEYSTORE_PASSWORD" >> $GITHUB_ENV echo "CM_KEY_ALIAS_${APP_NAME}=$KEY_ALIAS" >> $GITHUB_ENV echo "CM_KEY_PASSWORD_${APP_NAME}=$KEY_PASSWORD" >> $GITHUB_ENV -echo "โœ… Signing environment configured for $APP_NAME ($ENV environment)" -echo "๐Ÿ”‘ Using key alias: $KEY_ALIAS" +echo "โœ… Signing environment configured for $APP_NAME ($ENV environment)" >&2 +echo "๐Ÿ”‘ Using key alias: $KEY_ALIAS" >&2 diff --git a/.github/scripts/verify-apk-signature.sh b/.github/scripts/verify-apk-signature.sh index 16832d02..eec7088a 100755 --- a/.github/scripts/verify-apk-signature.sh +++ b/.github/scripts/verify-apk-signature.sh @@ -18,41 +18,41 @@ set -e APK_PATH="$1" if [ -z "$APK_PATH" ]; then - echo "โŒ Error: Missing APK path" - echo "Usage: $0 " + echo "โŒ Error: Missing APK path" >&2 + echo "Usage: $0 " >&2 exit 1 fi if [ ! -f "$APK_PATH" ]; then - echo "โŒ APK not found at: $APK_PATH" + echo "โŒ APK not found at: $APK_PATH" >&2 exit 1 fi -echo "๐Ÿ” Verifying APK signature..." +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!" + echo "โœ… APK is properly signed!" >&2 # Extract certificate details - echo "" - echo "๐Ÿ“œ 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 "" - echo "๐Ÿ”‘ Signer Information:" + 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!" - echo "" - echo "This may happen if:" - echo " 1. GitHub Secrets are not configured for this environment" - echo " 2. Keystore credentials are incorrect" - echo " 3. Build configuration didn't apply signing" - echo "" - echo "See: docs/RELEASE/APK_SIGNING_SETUP.md for setup instructions" + 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 From 639aeeb708acc680110fa1a87520dd39a6455f14 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 14:21:27 -0500 Subject: [PATCH 06/11] fix(ci): keep version suffix/build in tags and fix Node.js cache - Keep full version format (0.0.1-m3 or 1.2.3+456) instead of stripping suffix - Tags now include full version: krow-withus-worker-mobile/dev-v0.0.1-m3 - Remove invalid Node.js cache path that was causing resolution errors --- .github/scripts/extract-version.sh | 10 +++++----- .github/workflows/product-release.yml | 4 +--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/scripts/extract-version.sh b/.github/scripts/extract-version.sh index 5f6507bd..39cbeceb 100755 --- a/.github/scripts/extract-version.sh +++ b/.github/scripts/extract-version.sh @@ -34,13 +34,13 @@ if [ -z "$VERSION_LINE" ]; then exit 1 fi -# Extract just the semantic version (before the + or -) -VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//' | sed 's/[+\-].*//' | tr -d ' ') +# Extract full version including suffix/build number +VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//' | tr -d ' ') -# Validate version format -if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then +# Validate version format (X.Y.Z with optional +build or -suffix) +if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-+][a-zA-Z0-9]+)?$ ]]; then echo "โŒ Error: Invalid version format in pubspec.yaml: $VERSION" >&2 - echo "Expected format: X.Y.Z (e.g., 0.1.0)" >&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 diff --git a/.github/workflows/product-release.yml b/.github/workflows/product-release.yml index f3f3930c..a437cf28 100644 --- a/.github/workflows/product-release.yml +++ b/.github/workflows/product-release.yml @@ -45,7 +45,7 @@ jobs: with: fetch-depth: 0 - - name: ๏ฟฝ Make scripts executable + - name: ๐Ÿƒ๐Ÿพโ€โ™‚๏ธ Make scripts executable run: | chmod +x .github/scripts/*.sh echo "โœ… Scripts are now executable" @@ -165,8 +165,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: '20' - cache: 'npm' - cache-dependency-path: 'backend/*/package-lock.json' - name: ๐Ÿ”ฅ Install Firebase CLI run: | From 920ba40c504f36bec5339e172c2201ba1fa134a0 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 14:25:34 -0500 Subject: [PATCH 07/11] fix(ci): improve version extraction script for GitHub Actions compatibility - Replace bash [[ ]] regex test with grep -Eq for better portability - Add debug output showing pwd and directory listing on file not found - Use explicit regex groups for + and - separately for better compatibility --- .github/scripts/extract-version.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/scripts/extract-version.sh b/.github/scripts/extract-version.sh index 39cbeceb..51e5b031 100755 --- a/.github/scripts/extract-version.sh +++ b/.github/scripts/extract-version.sh @@ -24,6 +24,9 @@ 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 @@ -38,7 +41,8 @@ fi VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//' | tr -d ' ') # Validate version format (X.Y.Z with optional +build or -suffix) -if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-+][a-zA-Z0-9]+)?$ ]]; then +# 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 From 62b6dd22aa6748d5788988b9678afa2af3e921c8 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 14:31:23 -0500 Subject: [PATCH 08/11] fix: update Flutter version to 3.38.x in product release workflow --- .github/workflows/product-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/product-release.yml b/.github/workflows/product-release.yml index a437cf28..7e72e4ec 100644 --- a/.github/workflows/product-release.yml +++ b/.github/workflows/product-release.yml @@ -182,7 +182,7 @@ jobs: - name: ๐Ÿฆ Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.24.5' + flutter-version: '3.38.x' channel: 'stable' cache: true From 8378ebddea61b9f2945d5c25397f675290b3a3d1 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 14:54:18 -0500 Subject: [PATCH 09/11] ci: change all workflows to manual trigger only (workflow_dispatch) Updated workflows to use workflow_dispatch instead of pull_request/push: - backend-foundation.yml: Removed pull_request and push triggers - mobile-ci.yml: Removed pull_request and push triggers with path filters - web-quality.yml: Removed pull_request and push triggers Workflows now only run manually via Actions tab. This gives more control over when CI runs and reduces unnecessary workflow executions. --- .github/workflows/backend-foundation.yml | 9 +-------- .github/workflows/mobile-ci.yml | 11 +---------- .github/workflows/web-quality.yml | 9 +-------- 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/.github/workflows/backend-foundation.yml b/.github/workflows/backend-foundation.yml index 0e408f8f..a4a7d777 100644 --- a/.github/workflows/backend-foundation.yml +++ b/.github/workflows/backend-foundation.yml @@ -1,14 +1,7 @@ name: Backend Foundation on: - pull_request: - branches: - - dev - - main - push: - branches: - - dev - - main + workflow_dispatch: jobs: backend-foundation-makefile: diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 1a439740..910576de 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -1,16 +1,7 @@ name: Mobile CI on: - pull_request: - paths: - - 'apps/mobile/**' - - '.github/workflows/mobile-ci.yml' - push: - branches: - - main - paths: - - 'apps/mobile/**' - - '.github/workflows/mobile-ci.yml' + workflow_dispatch: jobs: detect-changes: diff --git a/.github/workflows/web-quality.yml b/.github/workflows/web-quality.yml index 7280b333..dd955c5c 100644 --- a/.github/workflows/web-quality.yml +++ b/.github/workflows/web-quality.yml @@ -1,14 +1,7 @@ name: Web Quality on: - pull_request: - branches: - - dev - - main - push: - branches: - - dev - - main + workflow_dispatch: jobs: web-quality: From 107ce1d48a95b4b197325b18285d4a0a485fe04d Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 15:09:32 -0500 Subject: [PATCH 10/11] feat(ci): update release notes format to new template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated extract-release-notes.sh to follow new format: **Environment:** {ENV} **Tag:** {TAG} ## What is new in this release {changelog content} Improvements: - Moved environment and tag info to the top - Added 'What is new in this release' heading - Improved awk pattern to properly extract changelog sections - Support both [vX.Y.Z] and [X.Y.Z] version formats in CHANGELOG - Removes unnecessary app name and separator lines Testing: โœ… worker-mobile-app: Extracts content from apps/mobile/apps/staff/CHANGELOG.md โœ… client-mobile-app: Extracts content from apps/mobile/apps/client/CHANGELOG.md โœ… Handles [v0.0.1-m3] format correctly --- .github/scripts/extract-release-notes.sh | 38 ++++++++++++++---------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/.github/scripts/extract-release-notes.sh b/.github/scripts/extract-release-notes.sh index 5d064a7b..408d969f 100755 --- a/.github/scripts/extract-release-notes.sh +++ b/.github/scripts/extract-release-notes.sh @@ -30,34 +30,40 @@ if [ -f "$CHANGELOG_PATH" ]; then echo "๐Ÿ“ Found CHANGELOG at $CHANGELOG_PATH" >&2 # Extract section for this version - # Look for ## [VERSION] and collect until next ## [ or end of file - NOTES=$(awk "/## \[${VERSION}\]/,/^## \[/" "$CHANGELOG_PATH" | sed '1d;$d' | sed '/^$/d') + # 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 [ -z "$NOTES" ]; then + # 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="Release $VERSION for $APP_NAME + NOTES="**Environment:** $ENV +**Tag:** $TAG_NAME -โš ๏ธ No CHANGELOG entry found for this version. Please update the CHANGELOG manually. +## What is new in this release -**Environment:** $ENV -**Tag:** $TAG_NAME" +โš ๏ธ No CHANGELOG entry found for this version. Please update the CHANGELOG manually." else echo "โœ… Extracted release notes for version $VERSION" >&2 - NOTES="# $APP_NAME - Release $VERSION + NOTES="**Environment:** $ENV +**Tag:** $TAG_NAME -$NOTES +## What is new in this release ---- - -**Environment:** $ENV -**Tag:** $TAG_NAME" +$CHANGELOG_CONTENT" fi else echo "โš ๏ธ Warning: CHANGELOG not found at $CHANGELOG_PATH" >&2 - NOTES="Release $VERSION for $APP_NAME + NOTES="**Environment:** $ENV +**Tag:** $TAG_NAME -**Environment:** $ENV -**Tag:** $TAG_NAME" +## What is new in this release + +โš ๏ธ CHANGELOG file not found at $CHANGELOG_PATH" fi # Save to output file From 14bb00aae442dbe9cf5ea3e6d716c6672f4c3b47 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 5 Mar 2026 15:10:28 -0500 Subject: [PATCH 11/11] Rename mobile app dirs; update changelog versions Rename mobile app directories (client_app -> client, staff_app -> staff) and normalize changelog version tags from `0.0.1-M3` to `v0.0.1-m3` in the affected CHANGELOG.md files to standardize folder naming and version formatting. --- apps/mobile/apps/{client_app => client}/CHANGELOG.md | 2 +- apps/mobile/apps/{staff_app => staff}/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename apps/mobile/apps/{client_app => client}/CHANGELOG.md (98%) rename apps/mobile/apps/{staff_app => staff}/CHANGELOG.md (98%) diff --git a/apps/mobile/apps/client_app/CHANGELOG.md b/apps/mobile/apps/client/CHANGELOG.md similarity index 98% rename from apps/mobile/apps/client_app/CHANGELOG.md rename to apps/mobile/apps/client/CHANGELOG.md index 6388273c..0c6412a6 100644 --- a/apps/mobile/apps/client_app/CHANGELOG.md +++ b/apps/mobile/apps/client/CHANGELOG.md @@ -1,6 +1,6 @@ # Client Mobile App - Change Log -## [0.0.1-M3] - Milestone 3 - 2026-02-15 +## [v0.0.1-m3] - Milestone 3 - 2026-02-15 ### Added - Authentication & Onboarding - Business email and password authentication diff --git a/apps/mobile/apps/staff_app/CHANGELOG.md b/apps/mobile/apps/staff/CHANGELOG.md similarity index 98% rename from apps/mobile/apps/staff_app/CHANGELOG.md rename to apps/mobile/apps/staff/CHANGELOG.md index 8d4c26e9..1a039638 100644 --- a/apps/mobile/apps/staff_app/CHANGELOG.md +++ b/apps/mobile/apps/staff/CHANGELOG.md @@ -1,6 +1,6 @@ # Staff Mobile App - Change Log -## [0.0.1-M3] - Milestone 3 - 2026-02-15 +## [v0.0.1-m3] - Milestone 3 - 2026-02-15 ### Added - Authentication & Onboarding - Phone number authentication with OTP verification