Prepare production artifacts before release
This commit is contained in:
parent
d79e4e436b
commit
9aa371105f
|
|
@ -1272,6 +1272,21 @@ allows only the absent Play App Signing certificate; the stricter
|
||||||
publishing Android through Google Play. The plan neither uploads a bundle nor
|
publishing Android through Google Play. The plan neither uploads a bundle nor
|
||||||
creates a backup.
|
creates a backup.
|
||||||
|
|
||||||
|
Prepare and verify the immutable Git bundle and `linux/amd64` image archive on
|
||||||
|
the development workstation before authorising any production mutation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/production-release-clean.sh prepare whoneedhelp
|
||||||
|
```
|
||||||
|
|
||||||
|
`prepare` repeats the read-only production and environment checks, reads the
|
||||||
|
production image-build inputs into a mode-`0600` temporary file, and then
|
||||||
|
creates or verifies the commit-bound artifacts under `output/releases/`. It
|
||||||
|
does not upload an artifact, create a production backup, change the remote
|
||||||
|
checkout, load an image, run a migration, or restart a service. A later
|
||||||
|
`apply` for the same commit verifies and reuses those exact artifacts instead
|
||||||
|
of compiling them again.
|
||||||
|
|
||||||
After reviewing the exact commit printed by the plan, execution additionally
|
After reviewing the exact commit printed by the plan, execution additionally
|
||||||
requires an explicit per-commit confirmation:
|
requires an explicit per-commit confirmation:
|
||||||
|
|
||||||
|
|
@ -1361,6 +1376,8 @@ including those edits:
|
||||||
```bash
|
```bash
|
||||||
./scripts/production-release-clean.sh plan whoneedhelp
|
./scripts/production-release-clean.sh plan whoneedhelp
|
||||||
|
|
||||||
|
./scripts/production-release-clean.sh prepare whoneedhelp
|
||||||
|
|
||||||
WNH_PRODUCTION_RELEASE_CONFIRM='whoneedhelp.com:EXACT_COMMIT' \
|
WNH_PRODUCTION_RELEASE_CONFIRM='whoneedhelp.com:EXACT_COMMIT' \
|
||||||
./scripts/production-release-clean.sh apply whoneedhelp
|
./scripts/production-release-clean.sh apply whoneedhelp
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ action=${1:-plan}
|
||||||
ssh_target=${2:-whoneedhelp}
|
ssh_target=${2:-whoneedhelp}
|
||||||
|
|
||||||
case "$action" in
|
case "$action" in
|
||||||
plan | apply) ;;
|
plan | prepare | apply) ;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 [plan|apply] [SSH_TARGET]" >&2
|
echo "Usage: $0 [plan|prepare|apply] [SSH_TARGET]" >&2
|
||||||
exit 2
|
exit 2
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ remote_root=${WNH_PRODUCTION_REMOTE_ROOT:-/srv/who_need_help-production}
|
||||||
expected_domain=${WNH_PRODUCTION_DOMAIN:-whoneedhelp.com}
|
expected_domain=${WNH_PRODUCTION_DOMAIN:-whoneedhelp.com}
|
||||||
|
|
||||||
case "$action" in
|
case "$action" in
|
||||||
plan | apply) ;;
|
plan | prepare | apply) ;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 [plan|apply] [SSH_TARGET]" >&2
|
echo "Usage: $0 [plan|prepare|apply] [SSH_TARGET]" >&2
|
||||||
exit 2
|
exit 2
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
@ -106,6 +106,7 @@ if [[ -n "$(git -C "$ROOT" status --porcelain --untracked-files=no)" ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
confirmation="$expected_domain:$local_commit"
|
confirmation="$expected_domain:$local_commit"
|
||||||
|
if [[ "$action" == "apply" ]]; then
|
||||||
if [[ "${WNH_PRODUCTION_RELEASE_CONFIRM:-}" != "$confirmation" ]]; then
|
if [[ "${WNH_PRODUCTION_RELEASE_CONFIRM:-}" != "$confirmation" ]]; then
|
||||||
echo "Release execution requires explicit approval in this exact process:" >&2
|
echo "Release execution requires explicit approval in this exact process:" >&2
|
||||||
echo "WNH_PRODUCTION_RELEASE_CONFIRM=$confirmation $0 apply $ssh_target" >&2
|
echo "WNH_PRODUCTION_RELEASE_CONFIRM=$confirmation $0 apply $ssh_target" >&2
|
||||||
|
|
@ -123,6 +124,7 @@ if [[ "$migration_policy" == "forward_only" ]]; then
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
"$ROOT/scripts/prepare-production-release.sh"
|
"$ROOT/scripts/prepare-production-release.sh"
|
||||||
artifact_root=${WNH_PRODUCTION_RELEASE_ARTIFACT_ROOT:-"$ROOT/output/releases"}
|
artifact_root=${WNH_PRODUCTION_RELEASE_ARTIFACT_ROOT:-"$ROOT/output/releases"}
|
||||||
|
|
@ -151,6 +153,11 @@ chmod 600 "$production_env"
|
||||||
"$ROOT/scripts/prepare-production-images.sh" "$production_env"
|
"$ROOT/scripts/prepare-production-images.sh" "$production_env"
|
||||||
cleanup_production_env
|
cleanup_production_env
|
||||||
|
|
||||||
|
if [[ "$action" == "prepare" ]]; then
|
||||||
|
echo "Production release artifacts are prepared and verified locally; no remote state was changed."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
remote_release_dir="$remote_root/output/releases/incoming"
|
remote_release_dir="$remote_root/output/releases/incoming"
|
||||||
remote_bundle="$remote_release_dir/$(basename -- "$bundle")"
|
remote_bundle="$remote_release_dir/$(basename -- "$bundle")"
|
||||||
remote_image_archive="$remote_release_dir/$(basename -- "$image_archive")"
|
remote_image_archive="$remote_release_dir/$(basename -- "$image_archive")"
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,22 @@ class ProductionReleaseCleanTest(unittest.TestCase):
|
||||||
self.assertEqual(result.returncode, 23)
|
self.assertEqual(result.returncode, 23)
|
||||||
self.assert_release_worktree_removed()
|
self.assert_release_worktree_removed()
|
||||||
|
|
||||||
|
def test_prepare_is_forwarded_through_the_same_clean_checkout(self):
|
||||||
|
dirty = self.project / "README.md"
|
||||||
|
dirty.write_text("user-owned change\n", encoding="utf-8")
|
||||||
|
|
||||||
|
self.run_command(
|
||||||
|
[str(self.scripts / WRAPPER.name), "prepare", "production-alias"],
|
||||||
|
env=self.environment(),
|
||||||
|
)
|
||||||
|
|
||||||
|
captured = self.capture.read_text(encoding="utf-8")
|
||||||
|
self.assertIn("status=\n", captured)
|
||||||
|
self.assertIn("args=prepare production-alias", captured)
|
||||||
|
self.assertIn(f"commit={self.commit}", captured)
|
||||||
|
self.assertEqual(dirty.read_text(encoding="utf-8"), "user-owned change\n")
|
||||||
|
self.assert_release_worktree_removed()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user