Generalize Backup command - #14
Merged
Merged
Conversation
Lets a caller place the finished archive outside the project, name it, and keep the restorable directory form in place. Together these are what the Epartment build server currently needs its own backup command override for. Volumes are still staged in the project's .roll/backups/ and retention cleanup still only ever runs against that directory, so pointing --output-dir at a shared delivery directory cannot delete another environment's archives. The "latest" symlink is likewise only maintained when the archive stays in .roll/backups/, since a shared directory would have every environment fighting over one symlink. The destination is created and checked for writability before `env down` and before any volume is tarred, so an unusable path fails in seconds rather than after a multi-hour backup. --keep-dir suppresses the post-archive `rm -rf` of the backup directory. `roll restore` reads the directory form, so a workflow that archives the whole workspace after a backup only captures a restorable copy while that directory still exists. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
backup is on ROLL_CMD_ANYARGS, so roll's parser stops at --help and hands it to backup.cmd unchanged. The handler called `roll backup --help`, which re-entered the same branch and never terminated. Render the usage directly instead. The same pattern is present in restore.cmd, restore-full.cmd, duplicate.cmd, env.cmd, db.cmd and svc.cmd and is left untouched here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
marcepartment
requested review from
HeRovaZy,
mlaurense and
sbudejis-epartment
and
a lite review from Copilot
August 26, 2026 12:13
There was a problem hiding this comment.
Pull request overview
This PR generalizes the roll backup command by adding CLI options to control where the final backup archive is written and how it is named, while keeping staging/retention behavior anchored to the project’s .roll/backups directory.
Changes:
- Add
--output-dir,--archive-name, and--keep-diroptions tobackupand document them in help text. - Validate/create the output directory up front and route archive creation to the resolved destination (with conditional
latestsymlink behavior). - Bump the project version to
0.7.1.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
version |
Version bump to reflect the new backup CLI behavior. |
commands/backup.help |
Documents new output-related flags and clarifies behavior/notes. |
commands/backup.cmd |
Implements output directory resolution, archive naming, and directory retention controls. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| ## Volumes are always staged inside the project: that is where the disk space is budgeted, and | ||
| ## retention cleanup must never be pointed at a shared drop directory holding other projects' | ||
| ## archives. --output-dir only moves the finished archive. | ||
| BACKUP_BASE_DIR="$(pwd)/.roll/backups" |
Comment on lines
+870
to
+872
| if [[ "${BACKUP_OUTPUT_DIR}" == "${BACKUP_BASE_DIR}" ]]; then | ||
| (cd "${BACKUP_BASE_DIR}" && ln -sf "$archive_name" "latest$(getCompressionExtension)") | ||
| fi |
Comment on lines
+43
to
+47
| ## Do NOT re-invoke `roll backup --help` here. `backup` is on roll's ROLL_CMD_ANYARGS | ||
| ## list, so roll's own parser stops at --help and passes it straight through to this | ||
| ## script — re-invoking roll lands right back on this branch and recurses forever. | ||
| ## usage.cmd renders ROLL_CMD_HELP (backup.help) and exits on its own. | ||
| source "${ROLL_DIR}/commands/usage.cmd" |
Comment on lines
852
to
855
| # Create compressed archive for the entire backup | ||
| local archive_name="backup_${ROLL_ENV_NAME}_${timestamp}$(getCompressionExtension)" | ||
| local archive_name="${BACKUP_ARCHIVE_NAME:-backup_${ROLL_ENV_NAME}_${timestamp}}$(getCompressionExtension)" | ||
| local archive_path="${BACKUP_OUTPUT_DIR}/${archive_name}" | ||
| logMessage INFO "Creating final backup archive: $archive_name" |
Comment on lines
860
to
864
| if [[ $BACKUP_OUTPUT_ID -eq 1 ]]; then | ||
| (cd "$(pwd)/.roll/backups" && tar -cf - "$timestamp" 2>/dev/null | $(getCompressionCommand) > "$archive_name") | ||
| (cd "${BACKUP_BASE_DIR}" && tar -cf - "$timestamp" 2>/dev/null | $(getCompressionCommand) > "$archive_path") || archive_status=$? | ||
| else | ||
| (cd "$(pwd)/.roll/backups" && tar -cf - "$timestamp" | $(getCompressionCommand) > "$archive_name") | ||
| (cd "${BACKUP_BASE_DIR}" && tar -cf - "$timestamp" | $(getCompressionCommand) > "$archive_path") || archive_status=$? | ||
| fi |
- Set pipefail around the final tar|compress pipeline. roll sets `set -e` but never pipefail, so the pipeline reported the compressor's status: gzip exits 0 on a truncated stream, so a tar that ran out of disk was recorded as a successful backup and the uncompressed copy was then deleted. Verified: `(false | cat)` returns 0, with pipefail returns 1. - Reject a path separator in --archive-name. It names a file inside the output directory, so `--archive-name=../x` wrote outside it and past the writability checks. - Decide the "latest" symlink from whether --output-dir was given rather than by comparing it to the staging path. The same directory compares unequal as a string once a relative argument or a symlinked path is involved, which skipped the symlink for a backup that never left the project. - Document why BACKUP_BASE_DIR stays keyed on the working directory: it is pre-existing behaviour that restore.cmd shares, and changing it only here would make backups land where restore does not look. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
commands/backup.help:52
- The
--keep-dirhelp text says backups are only restorable when the uncompressed directory is kept, butroll restoresupports restoring from the archive as well (it extracts internally). This is misleading documentation;--keep-diris optional and mainly useful for inspection or leaving extracted contents in place.
--keep-dir Keep the uncompressed backup directory in .roll/backups/ as well as
the archive (removed by default). 'roll restore' reads the directory
form, so this is what leaves a restorable backup in the project.
Comment on lines
+120
to
+124
| --output-dir=*) | ||
| BACKUP_OUTPUT_DIR="${1#*=}" | ||
| BACKUP_OUTPUT_REDIRECTED=1 | ||
| shift | ||
| ;; |
Comment on lines
+906
to
+909
| ## Clean up the directory version, which the archive already contains. --keep-dir | ||
| ## retains it for a caller that needs a restorable backup left in place — restore | ||
| ## reads the directory form, so archiving the workspace after a backup only yields a | ||
| ## restorable copy while the directory is still there. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add argument options for an output path.