Skip to content

Deployment Guide

This document covers the complete build and deployment pipeline for Foundation/Lens, including environment management and recovery procedures.

RequirementVersionNotes
Node.js22.xForge runtime target (nodejs22.x in manifest)
Forge CLILatestnpm install -g @forge/cli
Atlassian developer accountMust have access to the app at ari:cloud:ecosystem::app/650bca70-387f-4693-96fc-d85cd80a344f
npm8+Bundled with Node.js

Verify your Forge CLI is authenticated:

Terminal window
cd foundation && forge whoami

If not authenticated, log in:

Terminal window
forge login

The project has four npm packages, each with their own node_modules:

foundation/ # Backend (Forge resolvers, services, actions)
package.json
.npmrc # legacy-peer-deps=true
static/main/ # Main UI (AG Grid, toolbar, panels)
package.json
.npmrc # legacy-peer-deps=true
static/issue-context/ # Issue Context panel UI
package.json
.npmrc # legacy-peer-deps=true
static/admin/ # Admin page UI
package.json
.npmrc # legacy-peer-deps=true

All four .npmrc files set legacy-peer-deps=true. Never pass --legacy-peer-deps manually.

The deploy script builds all three frontend packages automatically when builds are stale. To build manually:

Terminal window
# Build all three frontend packages
bash foundation/scripts/build-static-resources.sh --deploy-target development
# Or build just the main UI
cd foundation/static/main && npm run build

The build script sets REACT_APP_FOUNDATION_DEPLOY_TARGET as an environment variable and writes a .foundation-deploy-target marker file into each build/ directory. The deploy script uses this marker to detect stale builds.

A deploy hash is auto-generated before each deploy (scripts/generate-deploy-hash.js). This embeds a short git SHA into the build for version identification.

Before deploying, the manifest guardrails script validates:

  • Manifest YAML is valid
  • Raw byte size is under the 23,500-byte CaaS budget (ECO-1310)
  • Function count is under the 50-function limit
  • All action references point to defined functions
  • All module references point to defined resources
  • All Rovo agent action references point to defined actions
Terminal window
cd foundation && npm run check:manifest
Terminal window
# Deploy to the working development environment
cd foundation && npm run deploy:dev
# Deploy to production (requires --confirm)
cd foundation && npm run deploy:production
# Deploy using the wrapper script directly
bash foundation/scripts/deploy.sh --environment dev-recovery
bash foundation/scripts/deploy.sh --environment production --confirm

The deploy wrapper script (scripts/deploy.sh) performs these safety checks before deploying:

  1. Worktree detection — Blocks deployment if running from a git worktree
  2. Branch check — Production deploys must be from main
  3. Uncommitted changes warning — Warns if working tree is dirty
  4. Manifest guardrails — Runs check-manifest-limits.js
  5. Build freshness — Rebuilds frontend if builds are stale or missing
  6. Production confirmation — Requires --confirm flag for production
EnvironmentStatusDefaultNotes
dev-recoveryWorkingYesCreated after original development env became corrupted
developmentCorruptedNoCaaS manifest release fails with INTERNAL_SERVER_ERROR 500
stagingCorruptedNoDeploy failures
productionWorkingNoLive Marketplace app

When an environment becomes corrupted (persistent 500 errors during CaaS manifest release), create a new one:

Terminal window
cd foundation && forge environments create --environment dev-new --non-interactive
cd foundation && forge deploy --environment dev-new
cd foundation && forge settings set default-environment dev-new

After switching the default environment, run a plain deploy to confirm:

Terminal window
cd foundation && forge deploy

Use the setup script to configure required Forge environment variables:

Terminal window
# Interactive guide for all environments
bash foundation/scripts/setup-env.sh
# Commands for a specific environment
bash foundation/scripts/setup-env.sh --environment dev-recovery

Required variables:

VariableSensitivePurpose
SENTRY_DSNYes (encrypted)Error tracking DSN

Set variables before the first deploy:

Terminal window
cd foundation && forge variables set SENTRY_DSN <value> --environment dev-recovery --encrypt

After deploying to an environment, install the app on your Jira Cloud site:

Terminal window
cd foundation && forge install --environment dev-recovery --site humanr.atlassian.net --product Jira --confirm-scopes --non-interactive

To upgrade an existing installation after a new deploy:

Terminal window
cd foundation && forge install --environment dev-recovery --site humanr.atlassian.net --product Jira --upgrade --confirm-scopes --non-interactive

The full production release script handles verification, deployment, installation, and post-deploy validation:

Terminal window
cd foundation && npm run release:production:local
# or directly:
bash foundation/scripts/release-production.sh --confirm

This script:

  1. Runs verify:quick (manifest + TypeScript + frontend builds)
  2. Configures Forge CLI for non-interactive use
  3. Verifies Forge authentication
  4. Deploys to production via deploy.sh --environment production --confirm
  5. Installs or upgrades the Jira production site
  6. Verifies the deployment and installation are successful

Every code change must follow this pipeline before being committed:

Terminal window
# Backend tests
cd foundation && npm test
# Frontend tests
cd foundation/static/main && npm test
Terminal window
cd foundation && npm run verify:quick

This runs:

  • Forge consumption guardrails (check-consumption.js)
  • Manifest + TypeScript release readiness (predeploy:check: manifest check + tsc --noEmit)
  • Frontend production builds (all three packages)
Terminal window
cd foundation && npm run verify:local

Adds to the quick pipeline:

  • Backend Jest suite
  • Main UI Jest suite
Terminal window
cd foundation && npm run deploy:dev

After deploying, refresh the Foundation tab in Jira Cloud and take a screenshot to verify:

  • No crashes or blank screens
  • Expected UI elements are visible
  • Data renders correctly

The Foundation app runs in a Forge Custom UI cross-origin iframe. Browser-level screenshots can see inside the iframe.

Interactive testing (clicking buttons, opening menus, filling forms) must be done manually by the user. The Forge iframe prevents automated click interactions from external tools.

Only commit after all verification steps pass.

Symptom: Repeated 500 Errors During CaaS Manifest Release

Section titled “Symptom: Repeated 500 Errors During CaaS Manifest Release”

If forge deploy repeatedly fails only in one environment during the “Release CaaS manifest” step with INTERNAL_SERVER_ERROR 500:

  1. Do not assume the code is broken. The environment itself may be corrupted on Atlassian’s side.
  2. Test in another environment. Deploy to staging or a fresh environment to confirm.
  3. Create a fresh environment if the corruption is confirmed:
Terminal window
cd foundation && forge environments create --environment dev-fresh --non-interactive
cd foundation && forge deploy --environment dev-fresh
cd foundation && forge settings set default-environment dev-fresh
  1. Do not delete the corrupted environment immediately. Keep it until the replacement is verified.

The app broke at 45/45 action modules during fresh Jira installations. The fix was reducing to 44/44 actions. Current manifest has 35 actions with ~650 bytes of headroom.

If install fails:

  1. Check the manifest action count: cd foundation && npm run check:manifest
  2. Check if the manifest byte size exceeds the CaaS limit
  3. Try uninstalling from the Jira admin panel and reinstalling

These warnings appear during lint/build but do not prevent deployment:

  • manifest.yml: deprecated app.name
  • manifest.yml: deprecated permissions.external.fetch.backend entries
  • src/resolvers/inline-edit.ts: deprecated storage export from @forge/api
  • CRA/Atlaskit source-map warnings in static/issue-context and static/admin
  • CRA/CssMinimizer postcss-calc warnings from @atlaskit/lozenge in static/main
  • Never deploy from a worktree. The deploy script blocks this automatically.
  • Never run forge tunnel from a worktree.
  • Worktrees are for isolated development. Merge or PR back to main first, then deploy from the main working tree.
  • After merging a PR, always git pull origin main in the main working tree to keep local main in sync.