Skip to content

feat: add ringctl patch revert command structure

What does this MR do?

Implements ringctl patch revert command to automate patch reversion during incident response.

Implementation

Command: ringctl patch revert <patch-id> -e <environment> [--dry-run] [--priority N]

Complete revert flow:

  1. Validates patch contains only supported operations (replace) more operations to be implemented later
  2. Finds the commit that applied the patch using GitLab Search API
  3. Extracts old attribute values by reading cell files at parent commit
  4. Creates new revert patch with extracted old values
  5. Deletes the failed patch
  6. Both operations in a single MR with descriptive context

Components added:

  • cmd/patch_revert.go - Command implementation with operation validation
  • lib/tissue/client.go - Added FindPatchApplicationCommit(), Instance(), Project(), Git()
  • lib/gitlab/client_wrapper.go - Added SearchCommits() and Compare() wrappers
  • lib/patch/revert.go - Added ExtractOldValues(), extractValuesFromCellFile(), CreateRevertOperations()
  • lib/tissue/templates/patch_mr.md - Enhanced with revert-specific description
  • lib/tissue/gitlab_cells_storage.go - Improved URL parsing with regex
  • Tests: lib/patch/revert_test.go, lib/tissue/client_test.go - 9 test cases total

Key Design Decisions

Robust value extraction:

  • Uses GitLab Search API (single call vs pagination)
  • Reads actual cell files at parent commit
  • Parses JSON directly (not regex on diff text)
  • Handles complex JSON values correctly

Revert patch behavior:

  • Starts from failed ring (editable in generated MR)
  • Sets completed_after_ring to failed ring
  • Priority default: 1 (executes before other patches)
  • Origin: "revert" for tracking
  • Creates new unique patch ID

Error handling:

  • Validates only replace operations supported
  • Cleanup revert patch if delete fails
  • Comprehensive error messages with context

Testing

Unit tests (9 test cases):

go test ./lib/patch ./lib/tissue -v
# All tests pass ✓

Coverage:

  • CreateRevertOperations - Operation creation logic
  • extractValuesFromCellFile - JSON parsing and extraction
  • ExtractOldValues - Complete extraction flow with mocked API
  • FindPatchApplicationCommit - Commit search with mocked Search API

Verified with cellsdev:

ringctl patch revert 01K61PZHDYKD6WBKX7NHQPKH9V -e cellsdev --priority 2

Results:

Dry-run support:

ringctl patch revert 01K61PZHDYKD6WBKX7NHQPKH9V -e cellsdev --dry-run

Shows complete revert preview without making changes.

Reviewer Feedback Addressed

Robustness improvements:

  • JSON parsing instead of regex for old value extraction
  • GitLab Search API instead of commit pagination
  • Proper parent commit handling via ParentIDs
  • Transaction cleanup if delete fails

Code quality:

  • Reduced cognitive complexity by extracting helper functions
  • Configurable constants (maxPages, commit message format)
  • Robust URL parsing with regex pattern
  • Comprehensive error handling

Metadata correctness:

  • Starts from failed ring (reviewers can adjust in MR if needed)
  • Sets completed_after_ring to failed ring
  • Dynamic URL construction using client methods
  • Enhanced MR template for revert context

Current Scope

Supported operations: Replace operations only (covers 90%+ of patches)

Validation: Fails fast with clear error for unsupported operation types

Future enhancements (separate MRs):

  • Support add/remove/move/copy operations
  • Additional edge case handling

Why

Automates the manual reversion process documented in the patching runbook:

  1. Manual deletion via ringctl patch delete
  2. Manual git history inspection for old values
  3. Manual revert patch creation
  4. Manual priority calculation

Related: https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/21502

Edited by Maina Ng'ang'a

Merge request reports

Loading