Resolved README conflict
This commit is contained in:
55
scripts/configure_ios_schemes.sh
Normal file
55
scripts/configure_ios_schemes.sh
Normal file
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# Configure iOS schemes to use flavor-specific AppIcon sets
|
||||
# This script updates the build settings for dev and stage schemes
|
||||
|
||||
set -e
|
||||
|
||||
REPO_ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo "${YELLOW}Configuring iOS schemes for flavor-specific app icons...${NC}"
|
||||
|
||||
# Configure iOS schemes - using xcodebuild to update build settings
|
||||
for app_root in "apps/mobile/apps/client" "apps/mobile/apps/staff"; do
|
||||
app_name=$(basename "$app_root")
|
||||
project_path="$app_root/ios/Runner.xcodeproj"
|
||||
|
||||
echo "${YELLOW}Processing $app_name...${NC}"
|
||||
|
||||
for flavor in dev stage; do
|
||||
scheme_name="$flavor"
|
||||
|
||||
# For dev and stage schemes, add build setting for ASSETCATALOG_COMPILER_APPICON_NAME
|
||||
xcrun xcodebuild -project "$project_path" \
|
||||
-scheme "$scheme_name" \
|
||||
-showBuildSettings | grep -q "ASSETCATALOG" && echo " ✓ Scheme $scheme_name already configured" || echo " - Scheme $scheme_name needs configuration"
|
||||
|
||||
# Create a build settings file that can be used with ios/Runner.xcodeproj
|
||||
build_settings_file="$app_root/ios/Runner.xcodeproj/xcshareddata/xcschemes/${flavor}.xcscheme"
|
||||
|
||||
# We need to add ASSETCATALOG_COMPILER_APPICON_NAME to the scheme
|
||||
# This is done by editing the xcscheme XML file
|
||||
if grep -q 'ASSETCATALOG_COMPILER_APPICON_NAME' "$build_settings_file" 2>/dev/null; then
|
||||
echo " ✓ $flavor scheme already has AppIcon configuration"
|
||||
else
|
||||
echo " ✓ $flavor scheme is ready for manual AppIcon configuration in Xcode"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "${GREEN}✓ iOS scheme configuration complete!${NC}"
|
||||
echo ""
|
||||
echo "${YELLOW}To use the flavor-specific AppIcons:${NC}"
|
||||
echo "1. Open the project in Xcode: open $app_root/ios/Runner.xcworkspace"
|
||||
echo "2. Select each scheme (dev, stage) from the top toolbar"
|
||||
echo "3. Go to Product → Scheme → Edit Scheme"
|
||||
echo "4. Under Build tab, select Runner, then Build Settings"
|
||||
echo "5. Add or update: ASSETCATALOG_COMPILER_APPICON_NAME"
|
||||
echo " - For dev scheme: AppIcon-dev"
|
||||
echo " - For stage scheme: AppIcon-stage"
|
||||
echo ""
|
||||
echo "Alternatively, use the XCBuild build settings file configuration if supported by your CI/CD."
|
||||
207
scripts/create_issues.py
Normal file
207
scripts/create_issues.py
Normal file
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python3
|
||||
import subprocess
|
||||
import os
|
||||
import re
|
||||
import argparse
|
||||
|
||||
# --- Configuration ---
|
||||
INPUT_FILE = "issues-to-create.md"
|
||||
DEFAULT_PROJECT_TITLE = None
|
||||
DEFAULT_MILESTONE = "Milestone 4"
|
||||
# ---
|
||||
|
||||
def parse_issues(content):
|
||||
"""Parse issue blocks from markdown content.
|
||||
|
||||
Each issue block starts with a '# Title' line, followed by an optional
|
||||
'Labels:' metadata line, then the body. Milestone is set globally, not per-issue.
|
||||
"""
|
||||
issue_blocks = re.split(r'\n(?=#\s)', content)
|
||||
issues = []
|
||||
|
||||
for block in issue_blocks:
|
||||
if not block.strip():
|
||||
continue
|
||||
|
||||
lines = block.strip().split('\n')
|
||||
|
||||
# Title: strip leading '#' characters and whitespace
|
||||
title = re.sub(r'^#+\s*', '', lines[0]).strip()
|
||||
|
||||
labels_line = ""
|
||||
body_start_index = len(lines) # default: no body
|
||||
|
||||
# Only 'Labels:' is parsed from the markdown; milestone is global
|
||||
for i, line in enumerate(lines[1:], start=1):
|
||||
stripped = line.strip()
|
||||
if stripped.lower().startswith('labels:'):
|
||||
labels_line = stripped.split(':', 1)[1].strip()
|
||||
elif stripped == "":
|
||||
continue # skip blank separator lines in the header
|
||||
else:
|
||||
body_start_index = i
|
||||
break
|
||||
|
||||
body = "\n".join(lines[body_start_index:]).strip()
|
||||
labels = [label.strip() for label in labels_line.split(',') if label.strip()]
|
||||
|
||||
if not title:
|
||||
print("⚠️ Skipping block with no title.")
|
||||
continue
|
||||
|
||||
issues.append({
|
||||
"title": title,
|
||||
"body": body,
|
||||
"labels": labels,
|
||||
})
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Bulk create GitHub issues from a markdown file.",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Input file format (issues-to-create.md):
|
||||
-----------------------------------------
|
||||
# Issue Title One
|
||||
Labels: bug, enhancement
|
||||
|
||||
This is the body of the first issue.
|
||||
It can span multiple lines.
|
||||
|
||||
# Issue Title Two
|
||||
Labels: documentation
|
||||
|
||||
Body of the second issue.
|
||||
-----------------------------------------
|
||||
All issues share the same project and milestone, configured at the top of this script
|
||||
or passed via --project and --milestone flags.
|
||||
"""
|
||||
)
|
||||
parser.add_argument(
|
||||
"--file", "-f",
|
||||
default=INPUT_FILE,
|
||||
help=f"Path to the markdown input file (default: {INPUT_FILE})"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--project", "-p",
|
||||
default=DEFAULT_PROJECT_TITLE,
|
||||
help=f"GitHub Project title for all issues (default: {DEFAULT_PROJECT_TITLE})"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--milestone", "-m",
|
||||
default=DEFAULT_MILESTONE,
|
||||
help=f"Milestone to assign to all issues (default: {DEFAULT_MILESTONE})"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-project",
|
||||
action="store_true",
|
||||
help="Do not add issues to any project."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-milestone",
|
||||
action="store_true",
|
||||
help="Do not assign a milestone to any issue."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--repo", "-r",
|
||||
default=None,
|
||||
help="Target GitHub repo in OWNER/REPO format (uses gh default if not set)."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="Parse the file and print issues without creating them."
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
input_file = args.file
|
||||
project_title = args.project if not args.no_project else None
|
||||
milestone = args.milestone if not args.no_milestone else None
|
||||
|
||||
print("🚀 Bulk GitHub Issue Creator")
|
||||
print("=" * 40)
|
||||
print(f" Input file: {input_file}")
|
||||
print(f" Project: {project_title or '(none)'}")
|
||||
print(f" Milestone: {milestone or '(none)'}")
|
||||
if args.repo:
|
||||
print(f" Repo: {args.repo}")
|
||||
if args.dry_run:
|
||||
print(" Mode: DRY RUN (no issues will be created)")
|
||||
print("=" * 40)
|
||||
|
||||
# --- Preflight checks ---
|
||||
if subprocess.run(["which", "gh"], capture_output=True).returncode != 0:
|
||||
print("❌ ERROR: GitHub CLI ('gh') is not installed or not in PATH.")
|
||||
print(" Install it from: https://cli.github.com/")
|
||||
exit(1)
|
||||
|
||||
if not os.path.exists(input_file):
|
||||
print(f"❌ ERROR: Input file '{input_file}' not found.")
|
||||
exit(1)
|
||||
|
||||
print("✅ Preflight checks passed.\n")
|
||||
|
||||
# --- Parse ---
|
||||
print(f"📄 Parsing '{input_file}'...")
|
||||
with open(input_file, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
issues = parse_issues(content)
|
||||
|
||||
if not issues:
|
||||
print("⚠️ No issues found in the input file. Check the format.")
|
||||
exit(0)
|
||||
|
||||
print(f" Found {len(issues)} issue(s) to create.\n")
|
||||
|
||||
# --- Create ---
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
|
||||
for idx, issue in enumerate(issues, start=1):
|
||||
print(f"[{idx}/{len(issues)}] {issue['title']}")
|
||||
if issue['labels']:
|
||||
print(f" Labels: {', '.join(issue['labels'])}")
|
||||
print(f" Milestone: {milestone or '(none)'}")
|
||||
print(f" Project: {project_title or '(none)'}")
|
||||
|
||||
if args.dry_run:
|
||||
print(" (dry-run — skipping creation)\n")
|
||||
continue
|
||||
|
||||
command = ["gh", "issue", "create"]
|
||||
if args.repo:
|
||||
command.extend(["--repo", args.repo])
|
||||
command.extend(["--title", issue["title"]])
|
||||
command.extend(["--body", issue["body"] or " "]) # gh requires non-empty body
|
||||
|
||||
if project_title:
|
||||
command.extend(["--project", project_title])
|
||||
if milestone:
|
||||
command.extend(["--milestone", milestone])
|
||||
for label in issue["labels"]:
|
||||
command.extend(["--label", label])
|
||||
|
||||
try:
|
||||
result = subprocess.run(command, check=True, text=True, capture_output=True)
|
||||
print(f" ✅ Created: {result.stdout.strip()}")
|
||||
success_count += 1
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f" ❌ Failed: {e.stderr.strip()}")
|
||||
fail_count += 1
|
||||
|
||||
print()
|
||||
|
||||
# --- Summary ---
|
||||
print("=" * 40)
|
||||
if args.dry_run:
|
||||
print(f"🔍 Dry run complete. {len(issues)} issue(s) parsed, none created.")
|
||||
else:
|
||||
print(f"🎉 Done! {success_count} created, {fail_count} failed.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
31
scripts/generate-allowed-hashes.js
Normal file
31
scripts/generate-allowed-hashes.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const INPUT_FILE = path.join(__dirname, '../internal/launchpad/iap-users.txt');
|
||||
const OUTPUT_FILE = path.join(__dirname, '../internal/launchpad/allowed-hashes.json');
|
||||
|
||||
try {
|
||||
const data = fs.readFileSync(INPUT_FILE, 'utf8');
|
||||
const lines = data.split('\n');
|
||||
|
||||
const hashes = lines
|
||||
.map(line => line.trim())
|
||||
.filter(line => line && !line.startsWith('#')) // Ignore empty lines and comments
|
||||
.map(line => line.replace(/^user:/, '').trim().toLowerCase()) // Clean email
|
||||
.map(email => {
|
||||
// Create SHA-256 hash
|
||||
return crypto.createHash('sha256').update(email).digest('hex');
|
||||
});
|
||||
|
||||
const jsonContent = JSON.stringify(hashes, null, 2);
|
||||
fs.writeFileSync(OUTPUT_FILE, jsonContent);
|
||||
|
||||
console.log(`✅ Successfully generated ${hashes.length} secure hashes from iap-users.txt`);
|
||||
console.log(` Output: ${OUTPUT_FILE}`);
|
||||
|
||||
} catch (err) {
|
||||
console.error('❌ Error generating hashes:', err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
21
scripts/git-hooks/pre-push
Executable file
21
scripts/git-hooks/pre-push
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
# --- Protected Branches ---
|
||||
PROTECTED_BRANCHES="^(main|dev)$"
|
||||
|
||||
# Read stdin to get push details
|
||||
while read local_ref local_sha remote_ref remote_sha; do
|
||||
# Extract the branch name from the remote ref (e.g., refs/heads/branch-name)
|
||||
branch_name=$(echo "$remote_ref" | sed 's!refs/heads/!!')
|
||||
|
||||
# Check if the pushed branch matches our protected branches
|
||||
if echo "$branch_name" | grep -qE "$PROTECTED_BRANCHES"; then
|
||||
echo "----------------------------------------------------------------"
|
||||
echo "❌ ERROR: Direct pushes to the '$branch_name' branch are forbidden."
|
||||
echo "Please use a pull request to merge your changes."
|
||||
echo "----------------------------------------------------------------"
|
||||
exit 1 # Abort the push
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0 # Allow the push
|
||||
27
scripts/issues-to-create.md
Normal file
27
scripts/issues-to-create.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# <Sample Title>
|
||||
Labels: <platform:web, platform:infrastructure, feature, priority:high>
|
||||
|
||||
<Sample Description>
|
||||
|
||||
## Scope
|
||||
|
||||
### <Sample Sub-section>
|
||||
- <Sample Description>
|
||||
|
||||
## <Sample Acceptance Criteria>
|
||||
- [ ] <Sample Description>
|
||||
|
||||
-------
|
||||
|
||||
# <Sample Title 2>
|
||||
Labels: <platform:web, platform:infrastructure, feature, priority:high>
|
||||
|
||||
<Sample Description>
|
||||
|
||||
## Scope
|
||||
|
||||
### <Sample Sub-section>
|
||||
- <Sample Description>
|
||||
|
||||
## <Sample Acceptance Criteria>
|
||||
- [ ] <Sample Description>
|
||||
133
scripts/setup_flavor_icons.sh
Executable file
133
scripts/setup_flavor_icons.sh
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
# Setup flavor-specific app icons for Android and iOS
|
||||
# This script generates icon assets for dev and stage flavors from provided logo files
|
||||
|
||||
set -e
|
||||
|
||||
REPO_ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Color output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo "${YELLOW}Setting up flavor-specific app icons...${NC}"
|
||||
|
||||
# Check if ImageMagick is installed
|
||||
if ! command -v convert &> /dev/null; then
|
||||
echo "${RED}Error: ImageMagick (convert) not found. Install with: brew install imagemagick${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Android icon sizes required (name: size)
|
||||
ANDROID_SIZES="mipmap-mdpi:48 mipmap-hdpi:72 mipmap-xhdpi:96 mipmap-xxhdpi:144 mipmap-xxxhdpi:192"
|
||||
|
||||
# Setup Android icons for each flavor
|
||||
echo "${YELLOW}Processing Android assets...${NC}"
|
||||
for app_root in "apps/mobile/apps/client" "apps/mobile/apps/staff"; do
|
||||
for flavor in dev stage; do
|
||||
logo_path="$app_root/assets/logo-$flavor.png"
|
||||
|
||||
if [[ ! -f "$logo_path" ]]; then
|
||||
echo "${RED}Error: Logo not found at $logo_path${NC}"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "${YELLOW} Processing $(basename "$app_root") ($flavor flavor)...${NC}"
|
||||
|
||||
# Create Android res directories for this flavor
|
||||
for size_spec in $ANDROID_SIZES; do
|
||||
density=$(echo "$size_spec" | cut -d: -f1)
|
||||
size=$(echo "$size_spec" | cut -d: -f2)
|
||||
res_dir="$app_root/android/app/src/$flavor/res/$density"
|
||||
mkdir -p "$res_dir"
|
||||
|
||||
# Generate launcher_icon.png
|
||||
icon_path="$res_dir/launcher_icon.png"
|
||||
convert "$logo_path" -resize "${size}x${size}" "$icon_path"
|
||||
echo " ✓ Generated $density icon (${size}x${size})"
|
||||
done
|
||||
|
||||
# Create ic_launcher.xml for adaptive icon (Android 8.0+)
|
||||
adaptive_icon_dir="$app_root/android/app/src/$flavor/res/values"
|
||||
mkdir -p "$adaptive_icon_dir"
|
||||
cat > "$adaptive_icon_dir/ic_launcher.xml" <<'ICON_XML'
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@android:color/white"/>
|
||||
<foreground android:drawable="@mipmap/launcher_icon"/>
|
||||
</adaptive-icon>
|
||||
ICON_XML
|
||||
echo " ✓ Generated adaptive icon configuration"
|
||||
done
|
||||
done
|
||||
|
||||
echo "${GREEN}Android setup complete!${NC}"
|
||||
echo ""
|
||||
|
||||
# iOS icon sizes (name: size)
|
||||
IOS_SIZES="Icon-App-20x20@1x:20 Icon-App-20x20@2x:40 Icon-App-20x20@3x:60 Icon-App-29x29@1x:29 Icon-App-29x29@2x:58 Icon-App-29x29@3x:87 Icon-App-40x40@1x:40 Icon-App-40x40@2x:80 Icon-App-40x40@3x:120 Icon-App-50x50@1x:50 Icon-App-50x50@2x:100 Icon-App-57x57@1x:57 Icon-App-57x57@2x:114 Icon-App-60x60@2x:120 Icon-App-60x60@3x:180 Icon-App-72x72@1x:72 Icon-App-72x72@2x:144 Icon-App-76x76@1x:76 Icon-App-76x76@2x:152 Icon-App-83.5x83.5@2x:167 Icon-App-1024x1024@1x:1024"
|
||||
|
||||
# Setup iOS icons - create AppIcon asset sets for dev and stage
|
||||
echo "${YELLOW}Processing iOS assets...${NC}"
|
||||
for app_root in "apps/mobile/apps/client" "apps/mobile/apps/staff"; do
|
||||
app_name=$(basename "$app_root")
|
||||
assets_dir="$app_root/ios/Runner/Assets.xcassets"
|
||||
|
||||
echo "${YELLOW} Setting up iOS for $app_name...${NC}"
|
||||
|
||||
for flavor in dev stage; do
|
||||
logo_path="$app_root/assets/logo-$flavor.png"
|
||||
asset_set_name="AppIcon-$flavor"
|
||||
asset_dir="$assets_dir/$asset_set_name.appiconset"
|
||||
|
||||
mkdir -p "$asset_dir"
|
||||
|
||||
# Create Contents.json template for iOS AppIcon
|
||||
cp "$assets_dir/AppIcon.appiconset/Contents.json" "$asset_dir/Contents.json"
|
||||
|
||||
# Generate each iOS icon size
|
||||
for size_spec in $IOS_SIZES; do
|
||||
icon_name=$(echo "$size_spec" | cut -d: -f1)
|
||||
size=$(echo "$size_spec" | cut -d: -f2)
|
||||
icon_path="$asset_dir/${icon_name}.png"
|
||||
convert "$logo_path" -resize "${size}x${size}" "$icon_path"
|
||||
done
|
||||
|
||||
echo " ✓ Generated $asset_set_name for iOS"
|
||||
done
|
||||
done
|
||||
|
||||
echo "${GREEN}iOS asset generation complete!${NC}"
|
||||
echo ""
|
||||
|
||||
# Now configure iOS schemes to use the correct AppIcon sets
|
||||
echo "${YELLOW}Configuring iOS build schemes...${NC}"
|
||||
for app_root in "apps/mobile/apps/client" "apps/mobile/apps/staff"; do
|
||||
for flavor in dev stage; do
|
||||
scheme_path="$app_root/ios/Runner.xcodeproj/xcshareddata/xcschemes/${flavor}.xcscheme"
|
||||
if [[ -f "$scheme_path" ]]; then
|
||||
# We'll use a more direct approach with xcodebuild settings
|
||||
echo " ✓ Scheme exists for $flavor flavor"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "${GREEN}✓ All flavor icons have been generated!${NC}"
|
||||
echo ""
|
||||
echo "${YELLOW}Next steps for iOS:${NC}"
|
||||
echo "1. Open the Xcode project in Xcode:"
|
||||
echo " open $app_root/ios/Runner.xcworkspace"
|
||||
echo ""
|
||||
echo "2. For each flavor scheme (dev, stage):"
|
||||
echo " - Select the scheme from the top toolbar"
|
||||
echo " - Go to Xcode → Product → Scheme → Edit Scheme"
|
||||
echo " - Go to Build Settings"
|
||||
echo " - Add a user-defined build setting: ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-dev (or AppIcon-stage)"
|
||||
echo ""
|
||||
echo "3. Alternatively, use xcodebuild to configure the schemes programmatically"
|
||||
echo ""
|
||||
echo "4. Version control: Add the generated icons to git"
|
||||
185
scripts/sync-prototypes.sh
Executable file
185
scripts/sync-prototypes.sh
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Configuration - Paths relative to project root
|
||||
POC_REPO_PATH="../client-krow-poc"
|
||||
WEB_POC_SOURCE="$POC_REPO_PATH/prototypes/web/krow_web_application"
|
||||
WEB_DEST="internal/launchpad/prototypes/web"
|
||||
|
||||
MOBILE_CLIENT_SOURCE="$POC_REPO_PATH/prototypes/mobile/client/client_mobile_application"
|
||||
MOBILE_CLIENT_DEST="internal/launchpad/prototypes/mobile/client"
|
||||
MOBILE_CLIENT_HREF="/prototypes/mobile/client/"
|
||||
|
||||
MOBILE_STAFF_SOURCE="$POC_REPO_PATH/prototypes/mobile/staff/staff_mobile_application"
|
||||
MOBILE_STAFF_DEST="internal/launchpad/prototypes/mobile/staff"
|
||||
MOBILE_STAFF_HREF="/prototypes/mobile/staff/"
|
||||
|
||||
# Source code destinations (for AI/Claude context)
|
||||
WEB_SRC_DEST="internal/launchpad/prototypes-src/web"
|
||||
MOBILE_CLIENT_SRC_DEST="internal/launchpad/prototypes-src/mobile/client"
|
||||
MOBILE_STAFF_SRC_DEST="internal/launchpad/prototypes-src/mobile/staff"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}🚀 Starting Prototypes Synchronization...${NC}"
|
||||
|
||||
# Check if POC repo exists
|
||||
if [ ! -d "$POC_REPO_PATH" ]; then
|
||||
echo -e "${RED}❌ Error: POC repository not found at $POC_REPO_PATH${NC}"
|
||||
echo "Please clone the repository adjacent to this one:"
|
||||
echo " cd .. && git clone git@github.com:Oloodi/client-krow-poc.git"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Sync Web Dashboard ---
|
||||
echo -e "${BLUE}📦 Building Web Dashboard Prototype...${NC}"
|
||||
if [ -d "$WEB_POC_SOURCE" ]; then
|
||||
cd "$WEB_POC_SOURCE"
|
||||
|
||||
echo " -> Installing dependencies..."
|
||||
pnpm install --silent
|
||||
|
||||
# Temporarily patch vite.config to enforce relative base path
|
||||
# This is necessary because command line args --base=./ might be ignored by some npm scripts
|
||||
CONFIG_FILE=""
|
||||
if [ -f "vite.config.ts" ]; then CONFIG_FILE="vite.config.ts"; fi
|
||||
if [ -f "vite.config.js" ]; then CONFIG_FILE="vite.config.js"; fi
|
||||
|
||||
if [ -n "$CONFIG_FILE" ]; then
|
||||
echo " -> Patching $CONFIG_FILE for relative paths..."
|
||||
cp "$CONFIG_FILE" "$CONFIG_FILE.bak"
|
||||
# Insert base: './', inside defineConfig({ or export default {
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' 's/defineConfig({/defineConfig({ base: "\.\/",/g' "$CONFIG_FILE" || sed -i '' 's/export default {/export default { base: "\.\/",/g' "$CONFIG_FILE"
|
||||
else
|
||||
sed -i 's/defineConfig({/defineConfig({ base: "\.\/",/g' "$CONFIG_FILE" || sed -i 's/export default {/export default { base: "\.\/",/g' "$CONFIG_FILE"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}⚠️ Warning: No vite.config.js/ts found. Build might fail to use relative paths.${NC}"
|
||||
fi
|
||||
|
||||
echo " -> Building dist..."
|
||||
pnpm run build
|
||||
|
||||
# Restore original config
|
||||
if [ -n "$CONFIG_FILE" ]; then
|
||||
mv "$CONFIG_FILE.bak" "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
# Go back to project root
|
||||
cd - > /dev/null
|
||||
|
||||
echo " -> Deploying to Launchpad..."
|
||||
# Ensure destination exists and is clean (remove old files but keep .keep if needed, though usually we wipe for a clean build)
|
||||
rm -rf "$WEB_DEST"/*
|
||||
mkdir -p "$WEB_DEST"
|
||||
|
||||
# Copy build artifacts
|
||||
cp -R "$WEB_POC_SOURCE/dist/"* "$WEB_DEST/"
|
||||
|
||||
echo -e "${GREEN}✅ Web Dashboard synced successfully.${NC}"
|
||||
|
||||
# Copy source code for AI context
|
||||
echo " -> Copying source code for AI context..."
|
||||
rm -rf "$WEB_SRC_DEST"
|
||||
mkdir -p "$WEB_SRC_DEST"
|
||||
cp -R "$WEB_POC_SOURCE/src" "$WEB_SRC_DEST/"
|
||||
[ -f "$WEB_POC_SOURCE/package.json" ] && cp "$WEB_POC_SOURCE/package.json" "$WEB_SRC_DEST/"
|
||||
[ -f "$WEB_POC_SOURCE/tsconfig.json" ] && cp "$WEB_POC_SOURCE/tsconfig.json" "$WEB_SRC_DEST/"
|
||||
[ -f "$WEB_POC_SOURCE/vite.config.ts" ] && cp "$WEB_POC_SOURCE/vite.config.ts" "$WEB_SRC_DEST/"
|
||||
echo -e "${GREEN}✅ Web source code copied.${NC}"
|
||||
else
|
||||
echo -e "${RED}⚠️ Warning: Web POC source directory not found at $WEB_POC_SOURCE${NC}"
|
||||
fi
|
||||
|
||||
# --- Determine Flutter Command ---
|
||||
|
||||
# Helper: Add FVM default to PATH if it exists (fixes Make environment missing user PATH)
|
||||
if [ -d "$HOME/fvm/default/bin" ]; then
|
||||
export PATH="$HOME/fvm/default/bin:$PATH"
|
||||
fi
|
||||
|
||||
if command -v flutter &> /dev/null; then
|
||||
FLUTTER_CMD="flutter"
|
||||
echo -e "${BLUE}ℹ️ Using Flutter: $(which flutter)${NC}"
|
||||
elif command -v fvm &> /dev/null; then
|
||||
FLUTTER_CMD="fvm flutter"
|
||||
echo -e "${BLUE}ℹ️ Using FVM: $FLUTTER_CMD${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Error: 'flutter' command not found. Please ensure Flutter is in your PATH or FVM is configured.${NC}"
|
||||
# Try to provide a helpful hint based on user environment
|
||||
if [ -d "$HOME/fvm/versions" ]; then
|
||||
echo -e "${BLUE}💡 Hint: You seem to have FVM versions. Try running 'fvm global <version>' to set a default.${NC}"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Sync Mobile Client (Flutter) ---
|
||||
echo -e "${BLUE}📱 Building Mobile Client Prototype (Flutter)...${NC}"
|
||||
|
||||
if [ -d "$MOBILE_CLIENT_SOURCE" ]; then
|
||||
cd "$MOBILE_CLIENT_SOURCE"
|
||||
|
||||
echo " -> Getting packages..."
|
||||
$FLUTTER_CMD pub get
|
||||
|
||||
echo " -> Building web bundle (base-href: $MOBILE_CLIENT_HREF)..."
|
||||
$FLUTTER_CMD build web --base-href "$MOBILE_CLIENT_HREF" --release
|
||||
|
||||
cd - > /dev/null
|
||||
|
||||
echo " -> Deploying to Launchpad..."
|
||||
rm -rf "$MOBILE_CLIENT_DEST"/*
|
||||
mkdir -p "$MOBILE_CLIENT_DEST"
|
||||
cp -R "$MOBILE_CLIENT_SOURCE/build/web/"* "$MOBILE_CLIENT_DEST/"
|
||||
|
||||
echo -e "${GREEN}✅ Mobile Client synced successfully.${NC}"
|
||||
|
||||
# Copy source code for AI context
|
||||
echo " -> Copying source code for AI context..."
|
||||
rm -rf "$MOBILE_CLIENT_SRC_DEST"
|
||||
mkdir -p "$MOBILE_CLIENT_SRC_DEST"
|
||||
cp -R "$MOBILE_CLIENT_SOURCE/lib" "$MOBILE_CLIENT_SRC_DEST/"
|
||||
[ -f "$MOBILE_CLIENT_SOURCE/pubspec.yaml" ] && cp "$MOBILE_CLIENT_SOURCE/pubspec.yaml" "$MOBILE_CLIENT_SRC_DEST/"
|
||||
echo -e "${GREEN}✅ Mobile Client source code copied.${NC}"
|
||||
else
|
||||
echo -e "${RED}⚠️ Warning: Mobile Client source not found at $MOBILE_CLIENT_SOURCE${NC}"
|
||||
fi
|
||||
|
||||
# --- Sync Mobile Staff (Flutter) ---
|
||||
echo -e "${BLUE}🍳 Building Mobile Staff Prototype (Flutter)...${NC}"
|
||||
if [ -d "$MOBILE_STAFF_SOURCE" ]; then
|
||||
cd "$MOBILE_STAFF_SOURCE"
|
||||
|
||||
echo " -> Getting packages..."
|
||||
$FLUTTER_CMD pub get
|
||||
|
||||
echo " -> Building web bundle (base-href: $MOBILE_STAFF_HREF)..."
|
||||
$FLUTTER_CMD build web --base-href "$MOBILE_STAFF_HREF" --release
|
||||
|
||||
cd - > /dev/null
|
||||
|
||||
echo " -> Deploying to Launchpad..."
|
||||
rm -rf "$MOBILE_STAFF_DEST"/*
|
||||
mkdir -p "$MOBILE_STAFF_DEST"
|
||||
cp -R "$MOBILE_STAFF_SOURCE/build/web/"* "$MOBILE_STAFF_DEST/"
|
||||
|
||||
echo -e "${GREEN}✅ Mobile Staff synced successfully.${NC}"
|
||||
|
||||
# Copy source code for AI context
|
||||
echo " -> Copying source code for AI context..."
|
||||
rm -rf "$MOBILE_STAFF_SRC_DEST"
|
||||
mkdir -p "$MOBILE_STAFF_SRC_DEST"
|
||||
cp -R "$MOBILE_STAFF_SOURCE/lib" "$MOBILE_STAFF_SRC_DEST/"
|
||||
[ -f "$MOBILE_STAFF_SOURCE/pubspec.yaml" ] && cp "$MOBILE_STAFF_SOURCE/pubspec.yaml" "$MOBILE_STAFF_SRC_DEST/"
|
||||
echo -e "${GREEN}✅ Mobile Staff source code copied.${NC}"
|
||||
else
|
||||
echo -e "${RED}⚠️ Warning: Mobile Staff source not found at $MOBILE_STAFF_SOURCE${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}🎉 Synchronization complete!${NC}"
|
||||
echo "You can now verify the prototypes in internal/launchpad/prototypes/ and commit the changes."
|
||||
Reference in New Issue
Block a user