Setup Script
- Before You Start
- Run It
- What It Sets Up
- Check Your Setup
- Clone Your Team’s Repositories
- See Where Your Repositories Stand
- IntelliJ IDEA
- Switching to Your Own Tokens
- Keep the Script Current
- Upgrade Your Tools
- Free Up Disk Space
- Remove Your Credentials
- Credentials File (for the Onboarding Team)
- Maintaining the Script
ngss-dev-setup.sh sets up a Mac for VA Mobile / NGSS development in one guided run, and checks it again whenever you like. It automates the Development Environment Setup, Token and Environment Configuration, Maven Configuration and Skaffold and Kustomize Setup pages, the workstation part of the New Hire Checklist, and most of the Token Verification Checklist. It can also repair what it finds wrong, clone your team’s repositories and show where each one stands, set up IntelliJ IDEA, keep your tools up to date, free up disk space, and remove your saved credentials when you hand back a laptop.
Before You Start
-
A Mac with an administrator account. Homebrew asks for your password once.
-
The onboarding credentials: Bitbucket, VA Nexus and Sandbox DTR usernames and tokens, plus Jira and Jenkins tokens if you have them. The onboarding team may give you these as a credentials file.
-
30 to 60 minutes on a new Mac. Most of that is downloading, and the questions all come at the start. An Intel Mac can take much longer, because Homebrew no longer has prebuilt packages for Intel Macs and builds the command-line tools from source. The script warns you and asks before it does.
Run It
curl -fsSL https://onboarding.apothesource.io/apothesource-onboarding/_attachments/dev-setup/ngss-dev-setup.sh -o ngss-dev-setup.sh
bash ngss-dev-setup.sh
Before any questions, it checks the Mac:
-
Rosetta. If Terminal is set to Open using Rosetta, Homebrew won’t install Apple Silicon tools and SDKMAN would pick Intel JDKs, so the script starts itself again as Apple Silicon code (
arch -arm64), and tells you how to turn Rosetta off for Terminal. If it can’t, for example when you piped it into bash, it stops instead. -
An Intel Mac. Homebrew stopped making prebuilt packages for Intel Macs in September 2026, so some tools may build from source, which can take hours; the script asks before it does that. Homebrew stops supporting Intel Macs in September 2027; see Intel Macs for what that means and how to install the tools yourself.
-
An Intel Homebrew. Migration Assistant can copy an old Intel Mac’s Homebrew into
/usr/local. On Apple Silicon the script uses, and if needed installs, Homebrew in/opt/homebrewinstead, and sets it up last in your login profile so new terminals find it first. If a line that runs later, say in~/.zshrc, puts/usr/local/binback in front,doctorpoints it out. -
Disk space. The setup needs about 30 GB. With less, it warns and asks; under 10 GB the default answer is to stop.
-
The VA network. If
coderepo.mobilehealth.va.govisn’t reachable, it tells you to connect to the VPN. Without it, cloning, the token checks and the build fail, so run the script again once you’re connected. -
A setup started by hand. If you already did part of the setup by following the docs, the script lists what it found and stops before changing anything, because working around a half-finished setup makes its output hard to follow. Signs of this include credential or Skaffold settings in your shell profile outside the script’s block, a
~/.m2/settings.xmlfor VA Nexus, the Jira or Jenkins CLI, or the git hooks. Finish the setup by hand with Development Environment Setup and the pages it links to, then rundoctorto check it, anddoctor --fixto repair what it finds (see Check Your Setup). Repositories you cloned yourself don’t count, and neither does anything from an earlier run of the script. To run the guided setup anyway, add--force.
Then it asks a few questions (container runtime, optional extras, your git name and email, where to clone repositories, and your credentials), shows its plan, and works through it. It tries each credential against its server as you enter it. When you run it again, it asks for the credentials you still don’t have, and for the others only if you want to re-enter them. If both OrbStack and Docker Desktop are installed, it keeps the one docker uses now, and points docker at the runtime it sets up, so images you build land in the Kubernetes cluster that runs them.
It remembers the folder you choose for repositories (in ~/.config/ngss/settings), so doctor, clone, repos, tidy and upgrade look there too. Pass --workspace to use another folder for one run. At the end it runs doctor, lists what’s left to do by hand, such as licenses and IntelliJ settings, and, if the setup took more than a few minutes, posts a macOS notification.
You can run it again at any time. Finished steps are skipped, so after a failure, fix the cause and re-run it to continue. Logs for the longer steps are in ~/.config/ngss/logs.
|
Add |
What It Sets Up
| Area | What it does |
|---|---|
Tools |
Xcode Command Line Tools, Homebrew, Skaffold, Kustomize, jq, wget and TruffleHog (for the secret scans in the git hooks). OrbStack (or Docker Desktop) with Kubernetes turned on. Optionally IntelliJ IDEA, Postman, Headlamp, PlantUML, the Jira CLI, iTerm2, Sublime Text, Windows App and Citrix Workspace. |
Java |
SDKMAN with Java 21.0.10 (the default) and 17.0.13, Maven 3.9.15 and Gradle. On Apple Silicon, if SDKMAN came over from an Intel Mac (it still fetches Intel JDKs), it switches SDKMAN to Apple Silicon builds and reinstalls its JDKs. It turns on |
Shell |
A marked block in |
Credentials |
|
Maven |
|
Git |
Your name and email, |
CLIs |
|
IntelliJ IDEA |
The PlantUML Integration, Google Cloud Code, Bitbucket Integration Pro and GitHub Copilot plugins, the VA code style and inspections, and the Copilot sign-in host. See IntelliJ IDEA. |
macOS |
Optionally turns off smart quotes and smart dashes, which break code pasted into a terminal, and shows hidden files in Finder. |
Repositories |
Clones location-service, starter-project, jwtgen, mobile-framework and ngss-maven-tiles, installs the JDKs they pin, and builds location-service with |
Files it rewrites are backed up first as <file>.ngss-backup-<time>. Tokens never appear on a command line or in the script’s output.
Check Your Setup
bash ngss-dev-setup.sh doctor
bash ngss-dev-setup.sh doctor --fix # then offer to repair what it found
doctor changes nothing. It checks your tools, free disk space, the VA network, what a new terminal sees, your Maven settings, and OrbStack and Kubernetes, and it tries each credential against its server. It also flags Rosetta, an Intel Homebrew or an Intel SDKMAN on Apple Silicon, leftover copies of the onboarding credentials, a damaged ngss-dev-setup block in your shell profile, older copies of the git hooks that could let secrets or conflict markers through, and hook events that aren’t linked to the dispatcher, so Git skips each repository’s own hooks for them, such as Git LFS’s post-checkout. Its output never includes secrets, so you can paste it into Slack when you ask for help.
With --fix, it then offers a fix for each problem it can repair, asking before each one, and checks again at the end. It runs only those fixes, not the whole setup. For example, it can install a missing tool or JDK, restore the shell settings, ~/.m2/settings.xml or docker login, move credential lines from your shell profile into credentials.env, start OrbStack (or install it if you have no container runtime), or ask you for credentials that are missing or were rejected. Problems it can’t fix say what to do. If the fixes uncover more, such as git settings it couldn’t check before the Command Line Tools were in, it tells you to run it again.
Fixes that would change how you work, such as switching your kubectl context or replacing an old git hooks dispatcher (which then blocks pushes to main), default to no, and --yes skips them, along with the ones that need you to type credentials. Add --dry-run to see the fixes without making them.
Clone Your Team’s Repositories
bash ngss-dev-setup.sh clone # list the Backstage systems
bash ngss-dev-setup.sh clone --system ckm # clone every repository in CKM
It looks up every component in the system in Backstage, clones the repositories you don’t have yet into your workspace (~/Projects, or the folder you chose at install; --workspace changes it for one run), and installs the JDK and Maven versions their .sdkmanrc files pin. Repositories you already have are left alone. Add --dry-run to see the list first, or pass --system to install to do this as part of the setup.
See Where Your Repositories Stand
bash ngss-dev-setup.sh repos # one line per repository
bash ngss-dev-setup.sh repos --pull # and fast-forward the ones you haven't changed
repos fetches every git repository in your workspace (~/Projects, the folder you chose at install, or --workspace), up to two folders down, and shows each one’s branch, uncommitted changes, and how far it is behind or ahead of its upstream branch. With --pull, it fast-forwards each repository that is only behind and has no changes (untracked files don’t count). It leaves the rest alone: repositories with changes or unpushed commits, a detached HEAD, or no upstream branch. Fetching never stops to ask for a password. If the first fetch takes too long, as it does off the VPN, the rest show where they stood at their last fetch. With --no-fetch (or --dry-run), it fetches nothing and answers at once from what each repository knew at its last fetch.
bash ngss-dev-setup.sh repos --clean-branches --dry-run # see which branches would go
bash ngss-dev-setup.sh repos --clean-branches
Bitbucket can delete a branch when its pull request merges, but your local copy stays. repos counts those branches, and --clean-branches lists them and asks once before deleting them. It deletes a branch only when its remote branch is gone and all its commits are in the repository’s main branch. It keeps a branch that has commits of its own, which is what a squash merge leaves behind (it prints the git branch -D command for that), and the branch you have checked out.
IntelliJ IDEA
bash ngss-dev-setup.sh intellij
Quit IntelliJ first, because it overwrites its settings when it quits. The command:
-
Installs the PlantUML Integration, Google Cloud Code, Bitbucket Integration Pro and GitHub Copilot plugins.
-
Imports the
VA_Mobile_CodeStylecode style and theVA_Mobile_Inspectionsinspections from mobile-framework (see IntelliJ Checkstyle & Inspection Profiles), makes the code style the default, and makes the inspections the default for projects you open from now on. -
Sets GitHub Copilot to sign in through
va.ghe.com(see GitHub Copilot Access and IDE Configuration (VA GHEC-US)).
If you upgraded IntelliJ and haven’t opened the new version yet, the command waits: writing its settings first would stop IntelliJ from offering to import your old ones. Open it once, let it import them, quit it, and run the command again.
install does the same when you choose IntelliJ. You still need a license, your token in the Bitbucket plugin, and the Copilot sign-in. When mobile-framework updates its IDE files, run the command again to pick up the new versions.
Switching to Your Own Tokens
Once you have your PIV and your own accounts, create your tokens and run:
bash ngss-dev-setup.sh credentials
It replaces the onboarding values in credentials.env, git’s saved login, docker login and the Jira CLI, and then checks them. Update the token saved in IntelliJ’s git settings and in the Bitbucket plugin yourself.
Keep the Script Current
bash ngss-dev-setup.sh update
doctor tells you when a newer version is published. update downloads it, checks that it’s a complete copy of the script, and replaces yours, keeping the old one as ngss-dev-setup.sh.previous. It won’t overwrite a copy that a git repository tracks, such as this site’s; use git there. If your copy is a symlink, it updates the file the symlink points to.
Upgrade Your Tools
bash ngss-dev-setup.sh upgrade --dry-run # see what's out of date
bash ngss-dev-setup.sh upgrade
update replaces the script; upgrade upgrades the tools it installed. It runs brew update, lists the Homebrew tools from the setup that have newer versions (Skaffold, Kustomize, jq, wget, PlantUML and Graphviz, the Jira CLI, TruffleHog, kubectl, Headlamp and Windows App), and asks once before upgrading them. If the copy of a tool on your PATH isn’t Homebrew’s, such as a Kustomize you installed by hand from Skaffold and Kustomize Setup, it tells you, because upgrading Homebrew’s copy won’t change the one you run. It also installs any JDK or Maven version a repository has newly pinned, updates SDKMAN itself, and refreshes the Jenkins CLI JAR from the Sandbox Jenkins. Your other outdated Homebrew packages are listed, and it asks before upgrading those too; with --yes, it leaves them alone. doctor mentions it when the setup’s tools have upgrades.
To keep your builds working, it leaves some things alone:
-
Java and Maven. Each repository’s
.sdkmanrcpins them, soupgradenever moves them to a newer version, and it doesn’t upgrade Homebrew’s JDK or Maven packages either. -
New major versions of Skaffold, Kustomize and TruffleHog. Builds, deployments and the git hooks use them, so
upgradetells you when one is out. Check with the team, then upgrade it with thebrew upgradecommand it prints. -
Apps that are running. Homebrew closes an app to upgrade it, which would end a Windows App session, for example. Quit the app and run
upgradeagain. -
Apps that update themselves: OrbStack, Docker Desktop, IntelliJ IDEA (which also updates its plugins), Postman, iTerm2, Sublime Text and Citrix Workspace. Use their own update prompts. Upgrading OrbStack or Docker Desktop through Homebrew would stop your containers.
|
Homebrew no longer has prebuilt packages for Intel Macs, so on an Intel Mac, upgrading a command-line tool means building it from source. That can take hours, because it may build LLVM first, and it can fail. |
Free Up Disk Space
bash ngss-dev-setup.sh tidy --dry-run # how much could be freed
bash ngss-dev-setup.sh tidy # choose what to remove
tidy adds up what it could remove and asks about each kind separately. The answer defaults to yes only for what comes back by itself (marked yes below); the rest defaults to no, and tidy --yes leaves it alone.
-
Caches and logs left behind by IntelliJ IDEA versions that aren’t installed and haven’t run for 30 days (yes; IntelliJ rebuilds them).
-
Settings of those IntelliJ versions, moved to the Trash rather than deleted. It keeps the settings that a newly upgraded IntelliJ will import the first time it starts, including Community Edition settings that the unified IntelliJ IDEA can import. An IntelliJ installed somewhere
tidydoesn’t look, such as a custom Toolbox folder, still counts as in use while it keeps writing logs. -
Docker images and build cache that nothing has used for 30 days, and unused anonymous volumes (yes; images are pulled or rebuilt when next needed). The size it shows is an upper bound, and leaves the volumes out, because Docker counts named volumes there too, which it doesn’t remove. With a Docker CLI older than 23, it leaves volumes alone, because its
volume pruneremoves named volumes too. -
JDK, Maven and Gradle versions that no repository’s
.sdkmanrcpins, no IntelliJ project uses as its SDK, andJAVA_HOMEor your shell profile doesn’t name. It reads the repositories in your workspace, following symlinks; pass--workspaceif some are somewhere else. It skips this when it finds no repositories, rather than guess. SDKMAN may no longer offer an old version once it’s gone. -
Maven SNAPSHOT folders in
~/.m2/repositorythat no build has used for 30 days (nothing in them has changed), except ones built only on this Mac (mvn installwithout a deploy), which Maven couldn’t download again. Others download again on the VPN, unless Nexus has removed them. -
Homebrew’s downloads and old versions (
brew cleanup -s, yes).
Remove Your Credentials
Before you hand back a laptop, or when tokens may have leaked, run:
bash ngss-dev-setup.sh forget --dry-run # see what's saved
bash ngss-dev-setup.sh forget
forget lists what it found and asks once before removing it (the answer defaults to no; --yes removes it all without asking): credentials.env, git’s saved Coderepo login, the docker login for dtr.mapsandbox.net, the Jira CLI settings, credential lines in your shell profile, and the script’s backups of your profile that still hold credentials.
It doesn’t change:
-
Your shell history. It warns you if the history sets token variables, so you can delete those lines yourself.
-
~/.m2/settings.xml, and the backups of it the script makes when it replaces that file. It lists the ones with passwords written into them, so you can replace each password with an${env.VAR}reference (see Maven Configuration) or delete the backup yourself. -
IntelliJ. Remove the token in IntelliJ’s git settings and in the Bitbucket plugin.
-
The tokens themselves. Removing local copies doesn’t stop a token from working, so
forgetends by saying where to revoke each one: Bitbucket, VA Nexus, Sandbox DTR, Jira and Jenkins each have a page for it (see Creating Token Values). For the onboarding team’s tokens, it tells you to let them know instead.
Credentials File (for the Onboarding Team)
Instead of typing credentials, a new hire can pass a file with --credentials-file. Put one KEY=VALUE on each line; any subset works, and # comments are fine:
VA_BITBT_USER=<Bitbucket username>
VA_BITBT_PWD=<Bitbucket HTTP access token>
VA_NEXUS_USER=<VA Nexus user token name>
VA_NEXUS_PWD=<VA Nexus user token passcode>
DTR_USER=<Sandbox DTR user token name>
DTR_PWD=<Sandbox DTR user token passcode>
JIRA_LOGIN=<Jira username>
JIRA_API_TOKEN=<Jira personal access token>
JENKINS_API_USER=<Sandbox Jenkins username>
JENKINS_API_TOKEN=<Jenkins API token>
bash ngss-dev-setup.sh --credentials-file ~/Downloads/onboarding.env
The script reads the file as data and never runs it. Once the values are saved, it offers to delete the file. Share the file through the new hire’s personal Google Drive folder rather than Slack or email.
Maintaining the Script
The script is in this site’s repository at antora/apothesource-onboarding/modules/ROOT/attachments/dev-setup/ngss-dev-setup.sh.
-
The versions and endpoints are at the top of the script. When the team moves to a new JDK or Maven version, change them there and on Development Environment Setup, and everyone re-runs the script to catch up.
-
It contains copies of the
settings.xmlfrom Maven Configuration and the hook scripts from Modular Git Hooks (Pick-and-Choose). After you change either page or the script, runscripts/check-dev-setup-sync.sh. It prints a diff and fails if they no longer match. -
The IntelliJ plugin IDs are in
IDEA_PLUGINSat the top of the script. The script imports the code style and inspections from mobile-framework, and falls back to this site’sVA_Mobile_CodeStyle.xmlandVA_Mobile_Inspections.xmlattachments when it can’t reach mobile-framework, so copy those over when mobile-framework’sdocs/appendices/idefiles change. -
upgradeleaves the apps inSELF_UPDATING_CASKSto their own updaters, and holds back new major versions of the tools inHOLD_MAJOR. Both lists are at the top of the script. -
Bump
VERSIONin the script whenever you change it.doctortells people when a newer version is published, andupdateinstalls it. -
Before you open a pull request that changes the script, run
scripts/test-dev-setup/run.shon a Mac. It runs the script against a throwaway home folder with stand-in commands, so nothing on your Mac changes and nothing goes over the network. Apps and Homebrew tools come only from that sandbox too, so the results don’t depend on what your Mac has installed, and the prompts are answered on a pseudo-terminal, the way a person types them. It runs several scenarios at once and takes a few minutes;scripts/test-dev-setup/run.sh hruns a single scenario (the scenarios are listed in the script), andJOBS=1runs them one at a time. Ctrl-C stops them all, and a scenario still running after ten minutes is stopped and counted as failed (SCENARIO_LIMITchanges that). The top ofrun.shalso lists settings for trying other setups, such as bash as the login shell, GNU tools first onPATH, or another locale.