generateDeployScript method

Future<void> generateDeployScript()

Generate deployment script

Implementation

Future<void> generateDeployScript() async {
  if (!config.createServer) return;
  if (config.firebaseProjectId == null) {
    warn('Firebase project ID not set, skipping deploy script');
    return;
  }

  info('Generating deploy script...');

  final String content =
      '''
#!/bin/bash
# Deployment script for ${config.serverPackageName}
#
# Generated by Oracular. Idempotent: every gcloud step gracefully handles
# already-existing resources. Cleanup steps at the end keep Artifact
# Registry storage and Cloud Run revision counts bounded.

set -e

PROJECT_ID="${config.firebaseProjectId}"
REGION="us-central1"
SERVICE_NAME="${config.serverPackageName.replaceAll('_', '-')}"
REPOSITORY="oracular"
IMAGE_NAME="\$REGION-docker.pkg.dev/\$PROJECT_ID/\$REPOSITORY/\$SERVICE_NAME"

# Cleanup tunables — keep in sync with oracular/lib/models/setup_config.dart
ARTIFACT_KEEP_RECENT="${config.artifactKeepRecent}"
ARTIFACT_DELETE_OLDER_DAYS="${config.artifactDeleteOlderDays}"
CLOUD_RUN_KEEP_REVISIONS="${config.cloudRunKeepRevisions}"

echo "==> Ensuring Artifact Registry repository exists..."
gcloud artifacts repositories create \$REPOSITORY \\
  --repository-format=docker \\
  --location \$REGION \\
  --project \$PROJECT_ID || true

echo "==> Configuring Docker auth for Artifact Registry..."
gcloud auth configure-docker "\$REGION-docker.pkg.dev" --quiet

echo "==> Building Docker image..."
docker build --platform linux/amd64 -t \$IMAGE_NAME .

echo "==> Pushing to Artifact Registry..."
docker push \$IMAGE_NAME

echo "==> Deploying to Cloud Run..."
gcloud run deploy \$SERVICE_NAME \\
  --image \$IMAGE_NAME \\
  --platform managed \\
  --region \$REGION \\
  --project \$PROJECT_ID \\
  --allow-unauthenticated \\
  --port 8080 \\
  --memory 512Mi \\
  --cpu 1 \\
  --min-instances 0 \\
  --max-instances 10

# ─── Cleanup: Artifact Registry image versions ──────────────────────────────
# Apply the cleanup-policy.json shipped alongside this script. Keeps the
# N most-recent versions and deletes anything older than D days.
if [ -f "\$(dirname "\$0")/cleanup-policy.json" ]; then
echo "==> Applying Artifact Registry cleanup policy..."
gcloud artifacts repositories set-cleanup-policies \$REPOSITORY \\
    --location \$REGION \\
    --project \$PROJECT_ID \\
    --policy "\$(dirname "\$0")/cleanup-policy.json" || \\
  echo "WARNING: cleanup policy not applied (gcloud >= 444.0.0 required)"
else
echo "WARNING: cleanup-policy.json not found alongside script — skipping AR cleanup"
fi

# ─── Cleanup: Cloud Run revisions ───────────────────────────────────────────
# Keep the latest \$CLOUD_RUN_KEEP_REVISIONS revisions and delete anything
# older that is not currently routing traffic.
echo "==> Pruning old Cloud Run revisions for \$SERVICE_NAME (keep latest \$CLOUD_RUN_KEEP_REVISIONS)..."
ALL_REVS=\$(gcloud run revisions list \\
  --service=\$SERVICE_NAME \\
  --region=\$REGION \\
  --project=\$PROJECT_ID \\
  --sort-by="~creationTimestamp" \\
  --format="value(metadata.name)" 2>/dev/null || true)

if [ -n "\$ALL_REVS" ]; then
TRAFFIC_REVS=\$(gcloud run services describe \$SERVICE_NAME \\
    --region=\$REGION \\
    --project=\$PROJECT_ID \\
    --format="value(status.traffic.revisionName)" 2>/dev/null || true)

COUNT=0
for REV in \$ALL_REVS; do
  COUNT=\$((COUNT+1))
  if [ "\$COUNT" -le "\$CLOUD_RUN_KEEP_REVISIONS" ]; then
    continue
  fi
  if echo "\$TRAFFIC_REVS" | grep -q "\$REV"; then
    echo "  Skipping \$REV (serving traffic)"
    continue
  fi
  echo "  Deleting old revision: \$REV"
  gcloud run revisions delete \$REV \\
      --region=\$REGION \\
      --project=\$PROJECT_ID \\
      --quiet || echo "  WARNING: could not delete \$REV"
done
else
echo "WARNING: could not list Cloud Run revisions — skipping prune"
fi

echo ""
echo "Deployment complete!"
echo "Service URL: https://\$SERVICE_NAME-\$PROJECT_ID.\$REGION.run.app"
''';

  final File file3 = File(p.join(serverPath, 'script_deploy.sh'));
  await file3.writeAsString(content);

  // Make executable
  await _runner.run('chmod', <String>['+x', file3.path]);

  success('Generated: ${config.serverPackageName}/script_deploy.sh');

  // Also drop the cleanup-policy.json next to the script so the script
  // can find it without depending on the templates directory at runtime.
  await _ensureCleanupPolicyFile();
}