Automatic Rollback System
Relevant source files
The following files were used as context for generating this wiki page:
The Automatic Rollback System is a critical safety feature of the pubm CLI tool designed to revert changes made during the publishing process if a failure occurs. It ensures that the project remains in a consistent state by undoing operations such as file modifications, git commits, and local/remote tags.
The system operates using a stack-based approach where actions are registered as they are performed and executed in reverse order (LIFO) upon failure or interruption (e.g., SIGINT). This mechanism is vital for maintaining repository integrity, especially in monorepo environments where multiple packages are published simultaneously.
Sources: CLAUDE.md:5, packages/core/src/utils/rollback.ts:50-100
Architecture and Core Logic
The system is centered around the RollbackTracker class, which manages a collection of RollbackAction objects. Each action contains a function to execute, a descriptive label, and an optional confirmation flag.
Key Components
| Component | Description |
|---|---|
RollbackTracker<Ctx> | The main class managing the lifecycle of rollback actions and their execution context. |
RollbackAction<Ctx> | An interface defining a single rollback operation, including its logic (fn) and metadata. |
RollbackResult | An object summarizing the outcome of a rollback execution, including success/failure counts. |
RollbackExecuteOptions | Configuration for execution, determining interactivity and whether the rollback was triggered by a signal. |
Sources: packages/core/src/utils/rollback.ts:25-45
Execution Flow
The RollbackTracker uses a Last-In, First-Out (LIFO) execution pattern. This ensures that the most recent changes are undone first, which is critical for operations like Git where a commit must be reverted before the files changed in that commit can be restored.
The diagram shows the logic flow during the execute method, including how the system handles user prompts and process interruptions.
Sources: packages/core/src/utils/rollback.ts:60-120
Integration with Task Runner
The rollback system is deeply integrated into the pubm task runner. Actions are registered dynamically as the pipeline progresses through different phases (Prepare, Version, Publish).
Workspace and Manifest Handling
During monorepo operations, the system handles complex file restorations, such as reverting workspace: protocol dependencies in package.json files after they have been resolved for publishing.
- Workspace Backups: Original manifest contents are stored in a map.
- Registration: A rollback action is added to iterate through the map and write the original content back to disk.
ctx.runtime.rollback.add({
label: "Restore workspace protocol dependencies",
fn: async () => {
for (const [filePath, content] of allBackups) {
writeFileSync(filePath, content, "utf-8");
}
},
});
Sources: packages/core/src/tasks/runner-utils/manifest-handling.ts:71-79
Git Operations Rollback
The system frequently registers handlers for Git-specific operations. In a standard versioning flow, the following sequence is typically registered:
- Delete Local Tag: Removes the
v*tag created for the release. - Reset Git Commit: Reverts the "Version Packages" commit using
git reset --hard HEAD^. - Stash Handling: If the working tree was dirty, the system can use
git stashandgit popto preserve local changes while resetting the commit.
Sources: packages/core/tests/unit/tasks/runner-coverage.test.ts:980-1010, packages/core/tests/e2e/rollback.test.ts:210-230
Error Handling and Manual Recovery
Not all rollback actions are guaranteed to succeed. For example, a network error might prevent unpublishing a package from a registry.
Handling Failed Rollbacks
When an action fails, the RollbackTracker catches the error, logs it to the console, and adds the action label to a manualRecovery list. This list is presented to the user at the end of the process so they know which steps require manual intervention.
Interactivity and Signals
The system distinguishes between interactive prompts and signal-triggered events:
- Confirmation: Some actions (like unpublishing from a registry) default to
confirm: true. In interactive mode, the user is prompted. - SIGINT (Ctrl+C): If the rollback itself is interrupted or triggered by a SIGINT, the system skips confirmation prompts and proceeds only with automatic, non-destructive actions.
Sources: packages/core/src/utils/rollback.ts:75-95, packages/core/src/i18n/locales/en.json:20-25
Summary of Rollback Scenarios
The following table summarizes common rollback behaviors observed in the codebase:
| Scenario | Rollback Sequence (LIFO) |
|---|---|
| Failure after version bump | Delete Tags → Reset Commit → Restore Manifests |
| Failure after registry publish | Unpublish (if confirmed) → Delete Tags → Reset Commit → Restore Manifests |
| Failure after GitHub Release | Delete GitHub Release → Delete Remote Tags → Delete Local Tags → Reset Commit |
| Workspace dependency failure | Restore original package.json with workspace: protocols |
Sources: packages/core/tests/e2e/rollback.test.ts:100-350, packages/core/src/tasks/runner-utils/manifest-handling.ts:60-85
The Automatic Rollback System serves as the final line of defense in the pubm ecosystem, ensuring that transient failures or user cancellations do not leave projects in a "half-published" or corrupted state. By utilizing a simple yet robust LIFO stack of functions, it provides coverage for a wide array of file system, Git, and remote API operations.