Building & Testing the Git Init Shell Script
Add features, scaffolding, and tests to git_init.sh so it is safe and testable in both interactive and headless modes.
The Challenge: Safe automation without surprises
You have a repository initializer — scripts/git_init.sh — that supports interactive prompts and programmatic --headless invocations. This quest will guide you through validating the script’s behavior, adding tests, and ensuring it behaves well in CI.
Why this matters:
- Scripts are often used in automation and CI; they must behave predictably and be testable.
- Headless behavior must be non-destructive and reliable; interactive commands can’t be used in CI loops.
- Creating files via programmatic scaffolding must be done with a clear contract and test coverage.
🎯 Quest Objectives
By the end of this quest, you will be able to:
- Verify script syntax with
bash -nand lint withshellcheck. - Add Bats tests to confirm
--headlessoperations do not push. - Ensure it is easy to run
--no-pushfor local tests. - Add CI step instructions for running tests.
The Script
Save the following as scripts/git_init.sh in a fresh local project directory (not inside a clone of the IT-Journey repo) before you do anything else — every step below assumes this file already exists and is executable.
#!/usr/bin/env bash
# git_init.sh — interactive and headless repository initializer.
#
# Interactive: ./git_init.sh
# Headless: ./git_init.sh --headless -n <name> [--no-push] \
# [--gitignore <lang1,lang2,...>] [--scaffold <lang>] [--dry-run]
set -euo pipefail
HEADLESS=false
NO_PUSH=false
DRY_RUN=false
NAME=""
GITIGNORE_LANGS=""
SCAFFOLD_LANG=""
BASE_DIR="${GIT_INIT_BASE_DIR:-$HOME/github}"
usage() {
cat <<'USAGE'
Usage: git_init.sh [--headless] -n <name> [--no-push] [--gitignore <langs>] [--scaffold <lang>] [--dry-run]
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--headless) HEADLESS=true; shift ;;
-n|--name) NAME="$2"; shift 2 ;;
--no-push) NO_PUSH=true; shift ;;
--gitignore) GITIGNORE_LANGS="$2"; shift 2 ;;
--scaffold) SCAFFOLD_LANG="$2"; shift 2 ;;
--dry-run) DRY_RUN=true; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown argument: $1" >&2; usage; exit 1 ;;
esac
done
if [[ -z "$NAME" ]]; then
if [[ "$HEADLESS" == true ]]; then
echo "error: --headless requires -n <name>" >&2
exit 1
fi
read -rp "Repository name: " NAME
fi
REPO_DIR="$BASE_DIR/$NAME"
echo "Initializing repository '$NAME' at $REPO_DIR"
if [[ "$DRY_RUN" == true ]]; then
echo "[dry-run] mkdir -p $REPO_DIR"
echo "[dry-run] git -C $REPO_DIR init"
else
mkdir -p "$REPO_DIR"
git -C "$REPO_DIR" init -q
fi
if [[ -n "$GITIGNORE_LANGS" ]]; then
if [[ "$DRY_RUN" == true ]]; then
echo "[dry-run] write .gitignore for: $GITIGNORE_LANGS"
else
IFS=',' read -ra LANGS <<< "$GITIGNORE_LANGS"
: > "$REPO_DIR/.gitignore"
for lang in "${LANGS[@]}"; do
echo "# --- $lang ---" >> "$REPO_DIR/.gitignore"
done
fi
fi
if [[ -n "$SCAFFOLD_LANG" ]]; then
if [[ "$DRY_RUN" == true ]]; then
echo "[dry-run] mkdir -p $REPO_DIR/src $REPO_DIR/tests"
else
mkdir -p "$REPO_DIR/src" "$REPO_DIR/tests"
fi
fi
if [[ "$DRY_RUN" == true ]]; then
echo "[dry-run] git -C $REPO_DIR add -A && git -C $REPO_DIR commit -m 'chore: initial commit'"
else
git -C "$REPO_DIR" add -A
git -C "$REPO_DIR" -c user.email="quest@it-journey.dev" -c user.name="IT-Journey Quest" \
commit -q -m "chore: initial commit" --allow-empty
fi
if [[ "$NO_PUSH" == true || "$DRY_RUN" == true ]]; then
echo "Skipping push (--no-push or --dry-run)."
else
echo "Push step intentionally left for you to wire up to your own remote."
fi
echo "Done."
Make it executable once before running anything below:
chmod +x scripts/git_init.sh
Tests and Tools
We suggest two layers of tests:
- Unit-ish validations using local filesystem checks via
bats. - Linting static validation with
shellcheck.
Example Bats Test (save in tests/bats/test_headless.bats)
#!/usr/bin/env bats
setup() {
TMPDIR=$(mktemp -d)
cd "$TMPDIR"
}
teardown() {
rm -rf "$TMPDIR"
}
@test "headless mode creates a repo and does not push" {
run bash "$BATS_TEST_DIRNAME/../../scripts/git_init.sh" --headless -n sample-test --no-push
[ "$status" -eq 0 ]
[ -d "$HOME/github/sample-test/.git" ]
}
ShellCheck linting
Install with brew install shellcheck on macOS, or sudo apt-get install -y shellcheck on Linux (Ubuntu / GitHub Actions runners), then run shellcheck scripts/git_init.sh.
Syntax check
Use bash -n scripts/git_init.sh to detect syntax issues early.
Try it locally
Get the script first. Every command below expects
scripts/git_init.shto exist in your working directory and be executable. Create the project directory, save the script from The Script above into it, and make it executable:mkdir -p ~/quest-git-init && cd ~/quest-git-init # save the script above as scripts/git_init.sh here, then: mkdir -p scripts && chmod +x scripts/git_init.sh
- Syntax check
bash -n scripts/git_init.sh
- Run headless mode locally without pushing
bash scripts/git_init.sh --headless -n test-quest-sample --no-push --gitignore python,macos --scaffold python
- Run Bats tests
# install bats-core (macOS)
brew install bats-core
# install bats-core (Linux / Ubuntu, e.g. GitHub Actions runners)
sudo apt-get update && sudo apt-get install -y bats
bats tests/bats
- Run ShellCheck
# macOS
brew install shellcheck
# Linux / Ubuntu (e.g. GitHub Actions runners)
sudo apt-get install -y shellcheck
shellcheck scripts/git_init.sh
Acceptance Criteria
bash -nreturns no errorshellcheckreturns no major errorsbats tests/bats/test_headless.batsreturns pass for headless creation--gitignorecreates a.gitignorefile when requested--scaffold pythoncreatessrcandtests--dry-runprints operations and does not create files or push
Next Steps (Optional)
- Try
--dry-runto preview changes without applying them. - Create a GitHub Actions job that installs bats and shellcheck and runs tests on PRs.
Complete this quest to prove you can safely add features to a script and make it testable in automation.
Good luck! 🛠️
🕸️ Knowledge Graph
Structured wiki-links connect this quest to the IT-Journey knowledge graph. Open the Obsidian Graph View to explore connections.
Level hub: [[Level 001 - Journeyman Challenges]] Overworld: [[🏰 Overworld - Master Quest Map]] Obsidian docs: [[Obsidian Knowledge Graph and Wiki Links]]
🎁 Rewards
🕸️ Quest Network
Click a node to open the quest · ⌘/Ctrl-click for a new tab · drag to reposition · scroll to zoom.
Referenced by
- Loading…