Chapter 20Lesson 03~100 minutes

Deployment, Versioning, and Backward Compatibility

A Bash script used by CI or other automation becomes a software product with consumers. Flags, defaults, exit statuses, outputs, and paths must evolve intentionally.

AdvancedProduction design & capstoneHands-on lab

Learning objectives

By the end of this lesson

  • Version production Bash tools.
  • Preserve stable flags and defaults.
  • Deprecate before removing interfaces.
  • Version structured output when needed.
  • Stage and validate before promotion.

1. A mature Bash CLI has consumers

Once a shell tool is used by CI, cron, operators, or other scripts, its flags, defaults, exit statuses, output fields, paths, and environment variables become interfaces.

Backward compatibility
flowchart LR
  V1["version 1"] --> C["consumers"]
  V2["version 2"] --> C
  C --> Q{"compatible?"}
  Q -->|"yes"| U["safe upgrade"]
  Q -->|"no"| M["migration required"]

2. Give the tool a version

TOOL_VERSION=2.1.0

case ${1:-} in
  --version)
    printf '%s\n' "$TOOL_VERSION"
    exit 0
    ;;
esac

3. Defaults are compatibility too

Changing a default environment, timeout, output format, or destructive behavior can break callers even if every flag name remains unchanged.

4. Deprecate before removing

if [[ -n ${OLD_ENV_VAR:-} ]]; then
  printf 'warning: OLD_ENV_VAR is deprecated; use NEW_ENV_VAR\n' >&2
  NEW_ENV_VAR=${NEW_ENV_VAR:-$OLD_ENV_VAR}
fi

5. Version structured output when it evolves

jq -n               --arg release_id "$release_id"               '{schema_version:1, release_id:$release_id}'

6. Stage and validate before promotion

install -m 0755 release.sh /usr/local/lib/mytool/release.sh.new
bash -n /usr/local/lib/mytool/release.sh.new
mv /usr/local/lib/mytool/release.sh.new                /usr/local/lib/mytool/release.sh

Consumers should never observe a partially written tool.

7. Test old calling conventions

Backward-compatibility tests should run representative older flags, environment variables, and output consumers against the new version.

8. Hands-on lab: versioned CLI with deprecated input

mkdir -p "$HOME/devops-academy/bash/chapter20/lesson03"
cd "$HOME/devops-academy/bash/chapter20/lesson03"

cat > tool.sh <<'EOF'
#!/usr/bin/env bash
set -u

TOOL_VERSION=2.0.0

case ${1:-} in
  --version)
    printf '%s\n' "$TOOL_VERSION"
    exit 0
    ;;
esac

if [[ -n ${OLD_ENV:-} ]]; then
  printf 'warning: OLD_ENV is deprecated; use NEW_ENV\n' >&2
  NEW_ENV=${NEW_ENV:-$OLD_ENV}
fi

value=${NEW_ENV:-default}
printf '{"schema_version":1,"value":"%s"}\n' "$value"
EOF

chmod u+x tool.sh
./tool.sh --version
OLD_ENV=legacy ./tool.sh
NEW_ENV=current ./tool.sh

Verification checklist

9. Knowledge check

Question 1. What becomes a compatibility interface?

Question 2. Why deprecate first?

Question 3. Why version structured output?

Question 4. What should happen before promotion?

10. Summary

Treat production Bash tools as released software: version them, preserve stable contracts, deprecate before removal, test compatibility, and deploy staged known-good versions.

11. Further reading

  • Semantic Versioning specification.
  • Command Line Interface Guidelines.
  • GNU Coreutils documentation — install and mv.
  • Release-engineering guidance on deprecation and compatibility.
Next

Operational Runbooks, Rollback, and Incident-Friendly Automation

Continue the final chapter by combining production Bash patterns into a complete operational design.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.