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.
This commit is contained in:
101
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
101
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
## 📋 Description
|
||||||
|
|
||||||
|
<!-- Provide a clear and concise description of your changes -->
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Type of Change
|
||||||
|
|
||||||
|
<!-- Mark the relevant option with an "x" -->
|
||||||
|
|
||||||
|
- [ ] 🐛 **Bug fix** (non-breaking change that fixes an issue)
|
||||||
|
- [ ] ✨ **Feature** (non-breaking change that adds functionality)
|
||||||
|
- [ ] 📝 **Documentation** (changes to docs, comments, or README)
|
||||||
|
- [ ] 🔧 **Refactor** (code change that doesn't affect functionality)
|
||||||
|
- [ ] ⚡ **Performance** (improvement in performance or optimization)
|
||||||
|
- [ ] 🔐 **Security** (security fix or improvement)
|
||||||
|
- [ ] 🎨 **Style** (formatting, linting, or minor code style changes)
|
||||||
|
- [ ] 🏗️ **Architecture** (significant structural changes)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Affected Areas
|
||||||
|
|
||||||
|
<!-- Mark the relevant areas that were modified -->
|
||||||
|
|
||||||
|
- [ ] 📱 **Mobile** (Flutter - Client/Worker app)
|
||||||
|
- [ ] 🌐 **Web** (React Dashboard)
|
||||||
|
- [ ] 🔌 **Backend** (APIs, Data Connect, Cloud Functions)
|
||||||
|
- [ ] 🗄️ **Database** (Schema changes, migrations)
|
||||||
|
- [ ] 🚀 **CI/CD** (GitHub Actions, deployment configs)
|
||||||
|
- [ ] 📚 **Documentation** (Docs, onboarding guides)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 Related Issues
|
||||||
|
|
||||||
|
<!-- Link any related issues using #issue_number -->
|
||||||
|
|
||||||
|
Closes #
|
||||||
|
Related to #
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Testing
|
||||||
|
|
||||||
|
<!-- Describe how you tested these changes -->
|
||||||
|
|
||||||
|
**Test Details:**
|
||||||
|
<!-- Provide specific test cases or scenarios -->
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Breaking Changes
|
||||||
|
|
||||||
|
<!-- Are there any breaking changes? If yes, describe them -->
|
||||||
|
|
||||||
|
- [ ] No breaking changes
|
||||||
|
- [ ] Yes, breaking changes:
|
||||||
|
|
||||||
|
**Details:**
|
||||||
|
<!-- Describe migration path or deprecation period if applicable -->
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Checklist
|
||||||
|
|
||||||
|
<!-- Complete this before requesting review -->
|
||||||
|
|
||||||
|
- [ ] Code follows project style guidelines
|
||||||
|
- [ ] Self-review completed
|
||||||
|
- [ ] Comments added for complex logic
|
||||||
|
- [ ] Documentation updated (if applicable)
|
||||||
|
- [ ] No new console warnings/errors
|
||||||
|
- [ ] Tests pass locally
|
||||||
|
- [ ] Branch is up-to-date with `dev`
|
||||||
|
- [ ] Commit messages are clear and descriptive
|
||||||
|
- [ ] Sensitive data is not committed
|
||||||
|
- [ ] Environment variables documented (if added)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Additional Notes
|
||||||
|
|
||||||
|
<!-- Any additional context, decisions, or considerations -->
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Review Checklist for Maintainers
|
||||||
|
|
||||||
|
- [ ] Code quality and readability
|
||||||
|
- [ ] Design patterns follow project conventions
|
||||||
|
- [ ] Test coverage is adequate
|
||||||
|
- [ ] Performance implications reviewed
|
||||||
|
- [ ] Security concerns addressed
|
||||||
|
- [ ] Documentation is complete
|
||||||
|
- [ ] Breaking changes properly communicated
|
||||||
|
- [ ] Cross-platform compatibility (if applicable)
|
||||||
73
.github/scripts/create-release-summary.sh
vendored
Executable file
73
.github/scripts/create-release-summary.sh
vendored
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Generate release summary for GitHub Actions
|
||||||
|
# Usage: ./create-release-summary.sh <app> <environment> <version> <tag_name>
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
APP=$1
|
||||||
|
ENV=$2
|
||||||
|
VERSION=$3
|
||||||
|
TAG_NAME=$4
|
||||||
|
|
||||||
|
if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$VERSION" ] || [ -z "$TAG_NAME" ]; then
|
||||||
|
echo "❌ Error: Missing required parameters"
|
||||||
|
echo "Usage: ./create-release-summary.sh <app> <environment> <version> <tag_name>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine display names
|
||||||
|
if [ "$APP" = "worker-mobile-app" ]; then
|
||||||
|
APP_DISPLAY="Worker Product"
|
||||||
|
APP_EMOJI="👷"
|
||||||
|
else
|
||||||
|
APP_DISPLAY="Client Product"
|
||||||
|
APP_EMOJI="💼"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ENV_UPPER=$(echo "$ENV" | tr '[:lower:]' '[:upper:]')
|
||||||
|
RELEASE_NAME="Krow With Us - ${APP_DISPLAY} - ${ENV_UPPER} - v${VERSION}"
|
||||||
|
|
||||||
|
# Environment emoji
|
||||||
|
case "$ENV" in
|
||||||
|
dev)
|
||||||
|
ENV_EMOJI="🔧"
|
||||||
|
;;
|
||||||
|
stage)
|
||||||
|
ENV_EMOJI="🎭"
|
||||||
|
;;
|
||||||
|
prod)
|
||||||
|
ENV_EMOJI="🚀"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
ENV_EMOJI="📦"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Generate summary
|
||||||
|
cat << EOF >> $GITHUB_STEP_SUMMARY
|
||||||
|
## 🎉 Release Created Successfully
|
||||||
|
|
||||||
|
### ${APP_EMOJI} Application Details
|
||||||
|
- **App:** ${APP_DISPLAY}
|
||||||
|
- **Environment:** ${ENV_EMOJI} ${ENV_UPPER}
|
||||||
|
- **Version:** \`${VERSION}\`
|
||||||
|
- **Tag:** \`${TAG_NAME}\`
|
||||||
|
|
||||||
|
### 📦 Release Information
|
||||||
|
**Release Name:** ${RELEASE_NAME}
|
||||||
|
|
||||||
|
### ✅ Next Steps
|
||||||
|
|
||||||
|
1. 🔍 **Verify** the tag and release on GitHub
|
||||||
|
2. 🏗️ **Trigger** CodeMagic build (if configured)
|
||||||
|
3. 📱 **Monitor** app store deployment
|
||||||
|
4. 📚 **Update** project documentation if needed
|
||||||
|
5. 🎯 **Communicate** release to stakeholders
|
||||||
|
|
||||||
|
### 🔗 Quick Links
|
||||||
|
- [View Tag](../../releases/tag/${TAG_NAME})
|
||||||
|
- [Release Documentation](../../docs/release/MOBILE_RELEASE_PLAN.md)
|
||||||
|
- [CHANGELOG](../../apps/mobile/apps/${APP}/CHANGELOG.md)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "✅ Summary generated successfully"
|
||||||
65
.github/scripts/extract-release-notes.sh
vendored
Executable file
65
.github/scripts/extract-release-notes.sh
vendored
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Extract release notes from CHANGELOG for a specific version
|
||||||
|
# Usage: ./extract-release-notes.sh <app> <version> <environment> <tag_name> <output_file>
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
APP=$1
|
||||||
|
VERSION=$2
|
||||||
|
ENV=$3
|
||||||
|
TAG_NAME=$4
|
||||||
|
OUTPUT_FILE=$5
|
||||||
|
|
||||||
|
if [ -z "$APP" ] || [ -z "$VERSION" ] || [ -z "$ENV" ] || [ -z "$TAG_NAME" ] || [ -z "$OUTPUT_FILE" ]; then
|
||||||
|
echo "❌ Error: Missing required parameters"
|
||||||
|
echo "Usage: ./extract-release-notes.sh <app> <version> <environment> <tag_name> <output_file>"
|
||||||
|
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"
|
||||||
48
.github/scripts/extract-version.sh
vendored
Executable file
48
.github/scripts/extract-version.sh
vendored
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Extract version from version file for products
|
||||||
|
# Usage: ./extract-version.sh <app>
|
||||||
|
# app: worker-mobile-app or client-mobile-app
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
APP=$1
|
||||||
|
|
||||||
|
if [ -z "$APP" ]; then
|
||||||
|
echo "❌ Error: App parameter required (worker-mobile-app or client-mobile-app)"
|
||||||
|
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"
|
||||||
22
.github/scripts/generate-tag-name.sh
vendored
Executable file
22
.github/scripts/generate-tag-name.sh
vendored
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Generate tag name for product release
|
||||||
|
# Usage: ./generate-tag-name.sh <app> <environment> <version>
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
APP=$1
|
||||||
|
ENV=$2
|
||||||
|
VERSION=$3
|
||||||
|
|
||||||
|
if [ -z "$APP" ] || [ -z "$ENV" ] || [ -z "$VERSION" ]; then
|
||||||
|
echo "❌ Error: Missing required parameters"
|
||||||
|
echo "Usage: ./generate-tag-name.sh <app> <environment> <version>"
|
||||||
|
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"
|
||||||
64
.github/workflows/backend-foundation.yml
vendored
Normal file
64
.github/workflows/backend-foundation.yml
vendored
Normal file
@@ -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
|
||||||
331
.github/workflows/hotfix-branch-creation.yml
vendored
Normal file
331
.github/workflows/hotfix-branch-creation.yml
vendored
Normal file
@@ -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
|
||||||
|
<!-- Describe how many users are affected and severity -->
|
||||||
|
|
||||||
|
### Solution
|
||||||
|
<!-- Describe the fix (will be added as you commit fixes) -->
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
<!-- Describe local verification -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Hotfix Process
|
||||||
|
|
||||||
|
1. ✅ Hotfix branch created
|
||||||
|
2. ⏳ **NEXT:** Make your bug fix commits to this branch
|
||||||
|
3. ⏳ Test the fix locally
|
||||||
|
4. ⏳ Request expedited review (< 15 minutes)
|
||||||
|
5. ⏳ Merge to main and create production tag
|
||||||
|
|
||||||
|
### To add your fix:
|
||||||
|
\`\`\`bash
|
||||||
|
git checkout $BRANCH
|
||||||
|
# Make your changes
|
||||||
|
git commit -m \"fix: [description]\"
|
||||||
|
git push origin $BRANCH
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### After merging:
|
||||||
|
\`\`\`bash
|
||||||
|
# Tag and release
|
||||||
|
git checkout main
|
||||||
|
git pull origin main
|
||||||
|
git tag -a krow-withus-${APP_CLEAN}-mobile/prod-v${HOTFIX_VERSION} -m \"HOTFIX: ${ISSUE}\"
|
||||||
|
git push origin krow-withus-${APP_CLEAN}-mobile/prod-v${HOTFIX_VERSION}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Ref:** [Hotfix Process Documentation](../docs/release/HOTFIX_PROCESS.md)"
|
||||||
|
|
||||||
|
# Create PR
|
||||||
|
PR_URL=$(gh pr create \
|
||||||
|
--base main \
|
||||||
|
--head "$BRANCH" \
|
||||||
|
--title "$PR_TITLE" \
|
||||||
|
--body "$PR_BODY" \
|
||||||
|
--label "hotfix,urgent,production")
|
||||||
|
|
||||||
|
echo "pr_url=${PR_URL}" >> $GITHUB_OUTPUT
|
||||||
|
echo "✅ Pull Request created: $PR_URL"
|
||||||
|
|
||||||
|
- name: 📊 Hotfix Summary
|
||||||
|
run: |
|
||||||
|
# Strip -mobile-app suffix for cleaner tag names
|
||||||
|
APP_CLEAN=$(echo "${{ github.event.inputs.app }}" | sed 's/-mobile-app$//')
|
||||||
|
|
||||||
|
echo "## 🚨 Hotfix Branch Created" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**App:** ${{ github.event.inputs.app }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Issue:** ${{ github.event.inputs.issue_description }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**From Tag:** \`${{ github.event.inputs.tag }}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Current Version:** ${{ steps.validate_tag.outputs.current_version }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Hotfix Version:** ${{ steps.hotfix_version.outputs.hotfix_version }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Branch:** \`${{ steps.branch.outputs.branch_name }}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### 🔧 Next Steps" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "1. **Checkout the hotfix branch:**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " git fetch origin" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " git checkout ${{ steps.branch.outputs.branch_name }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " \`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "2. **Make your bug fix(es)** - Keep changes minimal!" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "3. **Test locally** - Verify the fix works" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "4. **Request expedited review** - Target < 15 minutes" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "5. **Merge PR and create production tag:**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " git checkout main" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " git pull origin main" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " git tag -a krow-withus-${APP_CLEAN}-mobile/prod-v${{ steps.hotfix_version.outputs.hotfix_version }} -m \"HOTFIX: ${{ github.event.inputs.issue_description }}\"" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " git push origin krow-withus-${APP_CLEAN}-mobile/prod-v${{ steps.hotfix_version.outputs.hotfix_version }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo " \`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ -n "${{ steps.create_pr.outputs.pr_url }}" ]; then
|
||||||
|
echo "**Pull Request:** ${{ steps.create_pr.outputs.pr_url }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
248
.github/workflows/mobile-ci.yml
vendored
Normal file
248
.github/workflows/mobile-ci.yml
vendored
Normal file
@@ -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<<EOF" >> $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
|
||||||
|
|
||||||
145
.github/workflows/product-release.yml
vendored
Normal file
145
.github/workflows/product-release.yml
vendored
Normal file
@@ -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: <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 }}"
|
||||||
59
.github/workflows/web-quality.yml
vendored
Normal file
59
.github/workflows/web-quality.yml
vendored
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user