Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions .github/workflows/l10n-gettext-extract.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ jobs:
run: |
sudo apt update
sudo apt install gettext -y
- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: '24'
- name: Install global npm packages
run: |
yarn global add grunt-cli
- name: Clone l10n repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
Expand All @@ -30,6 +23,14 @@ jobs:
fetch-depth: 2
path: 'fxa-code'
persist-credentials: false
- name: Set up Node
# .nvmrc ships in the FxA repo, checked out into fxa-code/ just above
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was failing for me in CI and reordering fixed it. Seems like we should use the nvmrc in FxA reitehr way.

with:
node-version-file: 'fxa-code/.nvmrc'
- name: Install global npm packages
run: |
yarn global add grunt-cli
- name: Install npm packages
run: |
cd fxa-l10n
Expand Down
48 changes: 42 additions & 6 deletions _dev/pm2/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,52 @@
DIR=$(dirname "$0")
cd "$DIR/../.."

# Make sure there is a common docker network fxa, so containers can
# communicate with one another if needed
_dev/pm2/create-docker-net.sh fxa
pm2 start _dev/pm2/infrastructure.config.js
# Fail fast with an actionable message if Docker isn't running. Without this a
# down daemon surfaces as a cryptic 'docker network' error here, or worse, as a
# 240s readiness timeout further downstream.
if ! docker info >/dev/null 2>&1; then
echo "❌ Docker is not running. Start Docker Desktop (or your Docker daemon) and retry." >&2
exit 1
fi

# On an interactive TTY (the same gate the start dashboard uses), replace pm2's

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't have to add this, but watching all the pm2 and nx builds go by just seemed excessive. Now there is a simple live dashboard as the services come up. You can still see logs with FXA_START_PLAIN=1

# verbose daemon/launch output and status table with a compact summary. CI,
# piped runs, and FXA_START_PLAIN=1 keep the full output, byte-identical.
QUIET=false
if [ -t 1 ] && [ -z "${FXA_START_PLAIN:-}" ]; then
QUIET=true
fi

mkdir -p artifacts

if [ "$QUIET" = true ]; then
echo "Starting infrastructure…"
if _dev/pm2/create-docker-net.sh fxa >/dev/null 2>&1; then
echo " ✅ docker network fxa"
else
echo " ❌ docker network setup failed (re-run with FXA_START_PLAIN=1 to see why)." >&2
exit 1
fi
if ! pm2 start _dev/pm2/infrastructure.config.js >artifacts/pm2-infra.log 2>&1; then
echo " ❌ infrastructure failed to start. Last lines of artifacts/pm2-infra.log:" >&2
tail -40 artifacts/pm2-infra.log >&2
exit 1
fi
infra_names=$(grep -oE "name: '[^']+'" _dev/pm2/infrastructure.config.js | cut -d"'" -f2 | tr '\n' ' ')
echo " ✅ infrastructure started: ${infra_names}"
else
# Make sure there is a common docker network fxa, so containers can
# communicate with one another if needed
_dev/pm2/create-docker-net.sh fxa
pm2 start _dev/pm2/infrastructure.config.js
fi

echo "waiting for containers to start"

_scripts/check-url.sh localhost:4100/health
_scripts/check-url.sh localhost:9299/api/config
_scripts/check-url.sh localhost:4100/health 200 "goaws (SNS)"
_scripts/check-url.sh localhost:9299/api/config 200 "firebase emulator"
_scripts/check-mysql.sh
_scripts/check-redis.sh

echo "waiting for DB patches"
_scripts/check-db-patcher.sh
13 changes: 10 additions & 3 deletions _scripts/check-db-patcher.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#!/bin/bash
RETRY=60

# Derive the number of databases to patch from the migrations layout rather
# than hardcoding it, so adding a database doesn't let the gate pass early.
EXPECTED=$(ls -d packages/db-migrations/databases/*/ 2>/dev/null | wc -l | tr -d ' ')
if [ -z "$EXPECTED" ] || [ "$EXPECTED" -lt 1 ]; then
EXPECTED=4
fi

echo -e "\nChecking for DB patches..."

# Strategy: poll PM2 logs for the patcher outcome. This avoids the race
Expand Down Expand Up @@ -32,9 +39,9 @@ for i in $(seq 1 $RETRY); do
exit 1
fi

# Check for success — need all 4 databases
SUCCESS_COUNT=$(echo "$LOG_OUTPUT" | grep -c "Successfully patched" 2>/dev/null || echo "0")
if [[ "$SUCCESS_COUNT" -ge 4 ]]; then
# Check for success — need every database patched
SUCCESS_COUNT=$(echo "$LOG_OUTPUT" | grep -c "Successfully patched")
if [[ "$SUCCESS_COUNT" -ge "$EXPECTED" ]]; then
echo "📋 Patch Summary:"
echo "$LOG_OUTPUT" | \
grep -E "Successfully patched" | \
Expand Down
8 changes: 7 additions & 1 deletion _scripts/check-pre-launch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ if [ -d ".nx/cache" ]; then

if (( $NX_CACHE_SIZE_GB > 50 )); then
echo "❌ NX cache size is about $NX_CACHE_SIZE_GB GB! That's pretty big!"
read -p "Do you want to delete it now? (Y/N): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] && rm -rf .nx/cache && echo "Cache deleted!" || echo "Cache kept!"
# Only prompt interactively; under a non-TTY invocation (CI, nested shells)
# a blocking read would hang startup indefinitely, so just warn and continue.
if [ -t 0 ]; then
read -p "Do you want to delete it now? (Y/N): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] && rm -rf .nx/cache && echo "Cache deleted!" || echo "Cache kept!"
else
echo " Non-interactive shell; leaving it. Run 'rm -rf .nx/cache' to clear it manually."
fi
fi
fi
28 changes: 28 additions & 0 deletions _scripts/check-redis.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash

# Wait for the redis container to accept connections before app services boot,
# so a cold start doesn't produce a burst of ioredis connection errors.
# Non-fatal: ioredis reconnects on its own, so a slow redis only delays steady
# state rather than failing the stack.

# Authenticate when REDIS_PASSWORD is set (redis.sh starts redis with
# --requirepass); otherwise an authed redis replies NOAUTH and we'd wait the
# full timeout and warn falsely.
AUTH_ARGS=()
if [ -n "${REDIS_PASSWORD:-}" ]; then
AUTH_ARGS=(--no-auth-warning -a "$REDIS_PASSWORD")
fi

RETRY=30
echo -e "\nChecking for redis..."
for i in $(seq 1 "$RETRY"); do
REPLY=$(docker exec redis-server redis-cli "${AUTH_ARGS[@]}" ping 2>/dev/null)
if echo "$REPLY" | grep -q PONG; then
echo "✅ redis responded in ${i}s"
exit 0
fi
sleep 1
done

echo "⚠️ redis did not respond after ${RETRY}s; continuing (services will retry)."
exit 0
31 changes: 22 additions & 9 deletions _scripts/check-url.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
#!/bin/bash -e

echo "Checking for response from: $1"
# Poll an HTTP endpoint until it responds, used to gate startup on service
# readiness. Args: $1=host/path (no scheme), $2=expected status (default 200),
# $3=human label (default $1). Emits a periodic heartbeat so a slow service is
# never mistaken for a hung one, and prints an actionable hint on timeout.

TARGET="$1"
EXPECTED="${2:-200}"
LABEL="${3:-$1}"

RETRY=240
for i in $(eval echo "{1..$RETRY}"); do
if [ "$(curl -s -o /dev/null --silent -w "%{http_code}" http://$1)" == "${2:-200}" ]; then
echo "$1 responded in $SECONDS seconds"
echo "⏳ Waiting for ${LABEL} (http://${TARGET}, expect HTTP ${EXPECTED})..."

for i in $(seq 1 "$RETRY"); do
if [ "$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "http://$TARGET")" == "$EXPECTED" ]; then
echo "✅ ${LABEL} responded in ${SECONDS}s"
exit 0
else
if [ "$i" -lt $RETRY ]; then
sleep 1
fi
fi
# Heartbeat every 15s so the developer sees progress during long boots.
if [ $((i % 15)) -eq 0 ]; then
echo " …still waiting on ${LABEL} (${SECONDS}s, attempt ${i}/${RETRY})"
fi
if [ "$i" -lt "$RETRY" ]; then
sleep 1
fi
done
echo "Giving up after $SECONDS seconds. Failed to get response from: $1"

echo "❌ Gave up on ${LABEL} after ${SECONDS}s (http://${TARGET})."
echo " Hint: inspect 'pm2 status' and 'pm2 logs' for the service on this port."
exit 1
111 changes: 97 additions & 14 deletions _scripts/pm2-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,117 @@ echo -e "\nChecking Node version compatibility..."

mkdir -p artifacts

# Resolve the nx project selector once: the whole repo, or a tag/name scope.
# fxa-dev-launcher is always excluded — it's a launcher, not a stack service.
if [ -z "$PROJECTS" ]; then
SCOPE=(--all --exclude=fxa-dev-launcher)
else
SCOPE=(--projects="$PROJECTS" --exclude=fxa-dev-launcher)
fi

# Build before (re)starting. The start/restart Nx targets no longer depend on
# build, so the build target is selected here via FXA_BUILD_TARGET (default: the
# full build). `yarn start mza` sets FXA_BUILD_TARGET=build-fast to skip tsc.
#
# build-fast is opt-in per project: Nx's `^build-fast` edge only builds a
# dependency that itself defines a build-fast target, and never falls back to
# build. App services define a build-fast that skips their own tsc (dev servers
# compile from source). Dist-consumed projects (the fxa-* workspace packages
# imported by name, plus crypto-relier/l10n) define build-fast too — usually an
# alias for build — so they stay in the fast graph. The ~60 @fxa/* libs resolved
# from source via tsconfig paths intentionally have no build-fast and are skipped.
if [ "$COMMAND" = "start" ] || [ "$COMMAND" = "restart" ]; then
BUILD_TARGET="${FXA_BUILD_TARGET:-build}"
echo "▶️ Building ($BUILD_TARGET)..."
npx nx run-many -t "$BUILD_TARGET" "${SCOPE[@]}" --verbose
fi

# Stream nx output live (via tee) instead of capturing it into a variable, so
# per-service build/start progress is visible as it happens. The log copy is
# only used afterwards to detect the "no projects matched" case.
NX_LOG=artifacts/nx-${COMMAND}.log
if [ -z "$PROJECTS" ]; then
echo "▶️ Starting full stack..."
npx nx run-many -t $COMMAND --all --exclude=fxa-dev-launcher --verbose
else
# Start only provided projects and dependencies
# Note dependencies are automatically determined by Nx
echo "▶️ Starting selected projects: $PROJECTS"
OUTPUT=$(npx nx run-many -t $COMMAND --projects=$PROJECTS --exclude=fxa-dev-launcher --verbose)
fi

echo "$OUTPUT"
set +e
npx nx run-many -t "$COMMAND" "${SCOPE[@]}" --verbose 2>&1 | tee "$NX_LOG"
NX_STATUS=${PIPESTATUS[0]}
if [ -n "$PROJECTS" ] && grep -qiE "No (projects|tasks) were run" "$NX_LOG"; then
echo -e "\n❌ Nx did not find any matching projects for: $PROJECTS" >&2
exit 1
fi
set -e

if echo "$OUTPUT" | grep -q "No projects were run"; then
echo -e "\n❌ Nx did not find any matching projects for: $PROJECTS" >&2
exit 1
fi
if [ "${NX_STATUS:-0}" -ne 0 ]; then
echo -e "\n❌ '$COMMAND' failed (nx exit ${NX_STATUS}). See the output above, or run 'pm2 status' and 'pm2 logs'." >&2
exit "$NX_STATUS"
fi

# Only the start command gets the readiness banner; stop/restart/delete don't.
if [ "$COMMAND" != "start" ]; then
exit 0
fi

end=`date +%s`
runtime=$((end-start))

# Map a started project to the URL that proves it is serving. Projects without
# an HTTP endpoint (libs, workers) return nothing and are skipped. Using a
# function + case keeps this compatible with the macOS system bash (3.2, no
# associative arrays).
service_url() {
case "$1" in
fxa-content-server) echo "http://localhost:3030" ;;
fxa-settings) echo "http://localhost:3000/settings/static/js/bundle.js" ;;
fxa-auth-server) echo "http://localhost:9000/__heartbeat__" ;;
fxa-profile-server) echo "http://localhost:1111/__heartbeat__" ;;
fxa-admin-server) echo "http://localhost:8090/__heartbeat__" ;;
fxa-admin-panel) echo "http://localhost:8091" ;;
123done) echo "http://localhost:8080" ;;
*) echo "" ;;
esac
}

# Resolve the projects nx actually ran so we only advertise services for this
# scope (e.g. 'mza' never starts the admin panel).
if [ -z "$PROJECTS" ]; then
STARTED=$(npx nx show projects --exclude=fxa-dev-launcher 2>/dev/null)
else
STARTED=$(npx nx show projects --projects="$PROJECTS" --exclude=fxa-dev-launcher 2>/dev/null)
fi

echo -e "\n###########################################################"
echo -e "# ✅ Stack Started Successfully in ${runtime}s"
echo -e "# ✅ Services ready in ${runtime}s (infrastructure was started earlier)"
echo -e "###########################################################"
echo -e ""
echo -e " 📍 Services:"
echo -e " Content Server http://localhost:3030"
echo -e " Admin Panel http://localhost:8091"
echo -e " 123done (RP) http://localhost:8080"
echo -e " 📍 Verifying started services:"

# Reachability is best-effort: never let a non-numeric curl code or a slow
# service abort the banner under `set -e`.
set +e
all_ok=true
for project in $STARTED; do
url=$(service_url "$project")
[ -z "$url" ] && continue
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 2 "$url" 2>/dev/null)
[[ "$code" =~ ^[0-9]+$ ]] || code="000"
if [ "$code" -ge 200 ] && [ "$code" -lt 400 ]; then
printf " %-20s %s OK\n" "$project" "$url"
else
printf " %-20s %s NOT READY (HTTP %s)\n" "$project" "$url" "$code"
all_ok=false
fi
done
set -e

echo -e ""
if [ "$all_ok" = true ]; then
echo -e " All started services responded."
else
echo -e " ⚠️ Some services aren't responding yet — give them a moment, then check 'pm2 logs'."
fi
echo -e " 💡 Run 'yarn ports' to see all service ports"
echo -e "###########################################################\n"
24 changes: 24 additions & 0 deletions _scripts/start-mza.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash -e

# `yarn start mza`: pre-launch checks, infrastructure, the fast-build services
# (build-fast skips tsc), then a sync restart, and finally the total stack
# startup time. Kept as a script (rather than an inline nps chain) so the timing
# is readable. set -e stops before the "ready" line if any step fails, so the
# time is only reported on a clean startup.

start=$(date +%s)
DIR=$(dirname "$0")
cd "$DIR/.."

PROJECTS="$1"

_scripts/check-pre-launch.sh
_dev/pm2/start.sh
FXA_BUILD_TARGET=build-fast _scripts/pm2-all.sh start "$PROJECTS"

# sync depends on the services; restart it now that they are up.
pm2 restart sync

total=$(($(date +%s) - start))
echo ""
echo "✅ Stack ready in ${total}s. Run 'yarn stop' to stop all the servers."
7 changes: 7 additions & 0 deletions libs/shared/l10n/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
"command": "echo Build complete"
}
},
"build-fast": {
"dependsOn": ["build-ts"],
"executor": "nx:run-commands",
"options": {
"command": "echo Build complete"
}
},
"build-ts": {
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
Expand Down
7 changes: 7 additions & 0 deletions libs/vendored/crypto-relier/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
"command": "echo Build complete"
}
},
"build-fast": {
"dependsOn": ["build-ts"],
"executor": "nx:run-commands",
"options": {
"command": "echo Build complete"
}
},
"build-ts": {
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
Expand Down
Loading
Loading