feat: add replace subcommand with multi-pattern support
This commit is contained in:
29
specs/002-add-replace-command/checklists/release.md
Normal file
29
specs/002-add-replace-command/checklists/release.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Release Readiness Checklist: Replace Command with Multi-Pattern Support
|
||||
|
||||
**Purpose**: Verify readiness for release / polish phase
|
||||
**Created**: 2025-10-29
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Documentation
|
||||
|
||||
- [x] Quickstart reflects latest syntax and automation workflow
|
||||
- [x] CLI reference (`docs/cli-flags.md`) includes replace command usage and warnings
|
||||
- [x] AGENTS.md updated with replace command summary
|
||||
- [x] CHANGELOG entry drafted for replace command
|
||||
|
||||
## Quality Gates
|
||||
|
||||
- [x] `go test ./...` passing locally
|
||||
- [x] Smoke test script for replace + undo exists and runs
|
||||
- [x] Ledger metadata includes pattern counts and is asserted in tests
|
||||
- [x] Empty replacement path warns users in preview
|
||||
|
||||
## Operational Readiness
|
||||
|
||||
- [x] `--dry-run` and `--yes` are mutually exclusive and error when combined
|
||||
- [x] Undo command reverses replace operations via ledger entry
|
||||
- [x] Scope flags behave identically across list/replace commands
|
||||
|
||||
## Notes
|
||||
|
||||
- Resolve outstanding checklist items prior to tagging release.
|
||||
34
specs/002-add-replace-command/checklists/requirements.md
Normal file
34
specs/002-add-replace-command/checklists/requirements.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Specification Quality Checklist: Replace Command with Multi-Pattern Support
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2025-10-29
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
|
||||
70
specs/002-add-replace-command/contracts/replace-command.md
Normal file
70
specs/002-add-replace-command/contracts/replace-command.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# CLI Contract: `renamer replace`
|
||||
|
||||
## Command Synopsis
|
||||
|
||||
```bash
|
||||
renamer replace <pattern1> [pattern2 ...] <replacement> [flags]
|
||||
```
|
||||
|
||||
### Global Flags (inherited from root command)
|
||||
- `--path <dir>` (defaults to current working directory)
|
||||
- `-r`, `--recursive`
|
||||
- `-d`, `--include-dirs`
|
||||
- `--hidden`
|
||||
- `-e`, `--extensions <.ext|.ext2>`
|
||||
- `--yes` — apply without interactive confirmation (used by all mutating commands)
|
||||
- `--dry-run` — force preview-only run even if `--yes` is supplied
|
||||
|
||||
## Description
|
||||
Batch-replace literal substrings across filenames and directories using shared traversal and preview
|
||||
infrastructure. All arguments except the final token are treated as patterns; the last argument is
|
||||
the replacement value.
|
||||
|
||||
## Arguments & Flags
|
||||
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `<pattern...>` | Yes (≥2) | Literal substrings to be replaced. Quotes required when containing spaces. |
|
||||
| `<replacement>` | Yes | Final positional argument; literal replacement applied to each pattern. |
|
||||
|
||||
| Flag | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `--path` | string | `.` | Working directory for traversal (global flag). |
|
||||
| `-r`, `--recursive` | bool | `false` | Traverse subdirectories depth-first (global flag). |
|
||||
| `-d`, `--include-dirs` | bool | `false` | Include directory names in replacement scope (global flag). |
|
||||
| `--hidden` | bool | `false` | Include hidden files/directories (global flag). |
|
||||
| `-e`, `--extensions` | string | (none) | Restrict replacements to files matching `|`-delimited extensions (global flag). |
|
||||
| `--yes` | bool | `false` | Skip confirmation prompt and apply immediately after successful preview (global flag). |
|
||||
| `--dry-run` | bool | `false` | Force preview-only run even if `--yes` is provided (global flag). |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning | Example Trigger |
|
||||
|------|---------|-----------------|
|
||||
| `0` | Success | Preview or apply completed without conflicts. |
|
||||
| `2` | Validation error | Fewer than two arguments supplied or unreadable directory. |
|
||||
| `3` | Conflict detected | Target filename already exists; user must resolve before retry. |
|
||||
|
||||
## Preview Output
|
||||
- Lists each impacted file with columns: `PATH`, `MATCHED PATTERN`, `NEW PATH`.
|
||||
- Summary line: `Total: <files> (patterns: pattern1=#, pattern2=#, conflicts=#)`.
|
||||
|
||||
## Apply Behavior
|
||||
- Re-validates preview results before writing changes.
|
||||
- Writes ledger entry capturing old/new names, patterns, replacement string, timestamp.
|
||||
- On conflict, aborts without partial renames.
|
||||
|
||||
## Validation Rules
|
||||
- Minimum two unique patterns required (at least one pattern plus replacement).
|
||||
- Patterns and replacement treated as UTF-8 literals; no regex expansion.
|
||||
- Duplicate patterns deduplicated with warning in preview summary.
|
||||
- Replacement applied to every occurrence within file/dir name.
|
||||
- Empty replacement allowed but requires confirmation message: "Replacement string is empty; affected substrings will be removed."
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
renamer replace draft Draft DRAFT final
|
||||
renamer replace "Project X" "Project-X" ProjectX --extensions .txt|.md
|
||||
renamer replace tmp temp temp-backup stable --hidden --recursive --yes
|
||||
```
|
||||
45
specs/002-add-replace-command/data-model.md
Normal file
45
specs/002-add-replace-command/data-model.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Data Model: Replace Command with Multi-Pattern Support
|
||||
|
||||
## Entities
|
||||
|
||||
### ReplaceRequest
|
||||
- **Description**: Captures all inputs driving a replace operation.
|
||||
- **Fields**:
|
||||
- `workingDir` (string, required): Absolute path where traversal begins.
|
||||
- `patterns` ([]string, min length 2): Ordered list of literal substrings to replace.
|
||||
- `replacement` (string, required): Literal value substituting each pattern.
|
||||
- `includeDirectories` (bool): Whether directories participate in replacement.
|
||||
- `recursive` (bool): Traverse subdirectories depth-first.
|
||||
- `includeHidden` (bool): Include hidden files during traversal.
|
||||
- `extensions` ([]string): Optional extension filters inherited from scope flags.
|
||||
- `dryRun` (bool): Preview mode flag; true during preview, false when applying changes.
|
||||
- **Validations**:
|
||||
- `patterns` MUST be deduplicated case-sensitively before execution.
|
||||
- `replacement` MAY be empty, but command must warn the user during preview.
|
||||
- `workingDir` MUST exist and be readable before traversal.
|
||||
|
||||
### ReplaceSummary
|
||||
- **Description**: Aggregates preview/apply outcomes for reporting and ledger entries.
|
||||
- **Fields**:
|
||||
- `totalFiles` (int): Count of files/directories affected.
|
||||
- `patternMatches` (map[string]int): Total substitutions per pattern.
|
||||
- `conflicts` ([]ConflictDetail): Detected filename collisions with rationale.
|
||||
- `ledgerEntryID` (string, optional): Identifier once committed to `.renamer` ledger.
|
||||
|
||||
### ConflictDetail
|
||||
- **Description**: Describes a file that could not be renamed due to collision or validation failure.
|
||||
- **Fields**:
|
||||
- `originalPath` (string)
|
||||
- `proposedPath` (string)
|
||||
- `reason` (string): Human-readable description (e.g., "target already exists").
|
||||
|
||||
## Relationships
|
||||
- `ReplaceRequest` produces a stream of candidate rename operations via traversal utilities.
|
||||
- `ReplaceSummary` aggregates results from executing the request and is persisted inside ledger entries.
|
||||
- `ConflictDetail` records subset of `ReplaceSummary` when collisions block application.
|
||||
|
||||
## State Transitions
|
||||
1. **Parsing**: CLI args parsed into `ReplaceRequest`; validations run immediately.
|
||||
2. **Preview**: Traversal + replacement simulation produce `ReplaceSummary` with proposed paths.
|
||||
3. **Confirm**: Upon user confirmation (or `--yes`), operations apply atomically; ledger entry written.
|
||||
4. **Undo**: Ledger reverse operation reads `ReplaceSummary` data to restore originals.
|
||||
90
specs/002-add-replace-command/plan.md
Normal file
90
specs/002-add-replace-command/plan.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Implementation Plan: Replace Command with Multi-Pattern Support
|
||||
|
||||
**Branch**: `002-add-replace-command` | **Date**: 2025-10-29 | **Spec**: [spec.md](./spec.md)
|
||||
**Input**: Feature specification from `/specs/002-add-replace-command/spec.md`
|
||||
|
||||
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
|
||||
|
||||
## Summary
|
||||
|
||||
Introduce a `renamer replace` subcommand that accepts multiple literal patterns and replaces them
|
||||
with a single target string while honoring existing preview → confirm → ledger → undo guarantees.
|
||||
The feature will extend shared scope flags, reuse traversal/filtering pipelines, and add
|
||||
automation-friendly validation and help documentation.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Go 1.24
|
||||
**Primary Dependencies**: `spf13/cobra`, `spf13/pflag`
|
||||
**Storage**: Local filesystem (no persistent database)
|
||||
**Testing**: Go `testing` package with CLI integration/contract tests
|
||||
**Target Platform**: Cross-platform CLI (Linux, macOS, Windows)
|
||||
**Project Type**: Single CLI project
|
||||
**Performance Goals**: Complete preview + apply for 100 files within 2 minutes
|
||||
**Constraints**: Deterministic previews, reversible ledger entries, conflict detection before apply
|
||||
**Scale/Scope**: Handles hundreds of files per invocation; patterns limited to user-provided literals
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- Preview flow MUST show deterministic rename mappings and require explicit confirmation (Preview-First Safety).
|
||||
- Undo strategy MUST describe how the `.renamer` ledger entry is written and reversed (Persistent Undo Ledger).
|
||||
- Planned rename rules MUST document their inputs, validations, and composing order (Composable Rule Engine).
|
||||
- Scope handling MUST cover files vs directories (`-d`), recursion (`-r`), and extension filtering via `-e` without escaping the requested path (Scope-Aware Traversal).
|
||||
- CLI UX plan MUST confirm Cobra usage, flag naming, help text, and automated tests for preview/undo flows (Ergonomic CLI Stewardship).
|
||||
|
||||
**Gate Alignment**:
|
||||
- Replace command will reuse preview + confirmation pipeline; no direct rename without preview.
|
||||
- Ledger entries will include replacement mappings to maintain undo guarantees.
|
||||
- Replacement logic will be implemented as composable rule(s) integrating with existing rename engine.
|
||||
- Command will rely on shared scope flags (`--path`, `-r`, `-d`, `--hidden`, `-e`) to avoid divergence.
|
||||
- Cobra command structure and automated tests will cover help/validation/undo parity.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/002-add-replace-command/
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
├── contracts/
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
cmd/
|
||||
├── root.go
|
||||
└── list.go (existing CLI commands; replace command will be added here or alongside)
|
||||
|
||||
internal/
|
||||
├── listing/
|
||||
├── output/
|
||||
├── traversal/
|
||||
└── (new replace-specific packages under internal/replace/)
|
||||
|
||||
scripts/
|
||||
└── smoke-test-list.sh
|
||||
|
||||
tests/
|
||||
├── contract/
|
||||
├── integration/
|
||||
└── fixtures/
|
||||
|
||||
docs/
|
||||
└── cli-flags.md
|
||||
```
|
||||
|
||||
**Structure Decision**: Single CLI repository with commands under `cmd/` and reusable logic under
|
||||
`internal/`. Replace-specific logic will live in `internal/replace/` (request parsing, rule engine,
|
||||
summary). CLI command wiring will reside in `cmd/replace.go`. Tests will follow existing
|
||||
contract/integration directories.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
No constitution gate violations identified; additional complexity justification not required.
|
||||
63
specs/002-add-replace-command/quickstart.md
Normal file
63
specs/002-add-replace-command/quickstart.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Quickstart: Replace Command with Multi-Pattern Support
|
||||
|
||||
## Goal
|
||||
Demonstrate how to consolidate multiple filename patterns into a single replacement while using the
|
||||
preview → apply → undo workflow safely.
|
||||
|
||||
## Prerequisites
|
||||
- Go toolchain (>= 1.24) installed for building the CLI locally.
|
||||
- Sample directory with files containing inconsistent substrings (e.g., `draft`, `Draft`, `DRAFT`).
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Build the CLI**
|
||||
```bash
|
||||
go build -o renamer ./...
|
||||
```
|
||||
|
||||
2. **Inspect replace help**
|
||||
```bash
|
||||
./renamer replace --help
|
||||
```
|
||||
Review syntax, especially the "final argument is replacement" guidance and quoting rules.
|
||||
|
||||
3. **Run a preview with multiple patterns**
|
||||
```bash
|
||||
./renamer replace draft Draft DRAFT final --dry-run
|
||||
```
|
||||
Confirm the table shows each occurrence mapped to `final` and the summary lists per-pattern counts.
|
||||
|
||||
4. **Apply replacements after review**
|
||||
```bash
|
||||
./renamer replace draft Draft DRAFT final --yes
|
||||
```
|
||||
Observe the confirmation summary, then verify file names have been updated.
|
||||
|
||||
5. **Undo if necessary**
|
||||
```bash
|
||||
./renamer undo
|
||||
```
|
||||
Ensure the ledger entry created by step 4 is reversed and filenames restored.
|
||||
|
||||
6. **Handle patterns with spaces**
|
||||
```bash
|
||||
./renamer replace "Project X" "Project-X" ProjectX --dry-run
|
||||
```
|
||||
Verify that quoting preserves whitespace and the preview reflects the intended substitution.
|
||||
|
||||
7. **Combine with scope filters**
|
||||
```bash
|
||||
./renamer replace tmp temp stable --path ./examples --extensions .log|.txt --recursive
|
||||
```
|
||||
Confirm only matching files under `./examples` are listed.
|
||||
|
||||
8. **Integrate into automation**
|
||||
```bash
|
||||
./renamer replace draft Draft final --dry-run && \
|
||||
./renamer replace draft Draft final --yes
|
||||
```
|
||||
The first command previews changes; the second applies them with exit code `0` when successful.
|
||||
|
||||
## Next Steps
|
||||
- Add contract/integration tests covering edge cases (empty replacement, conflicts).
|
||||
- Update documentation (`docs/cli-flags.md`, README) with replace command examples.
|
||||
32
specs/002-add-replace-command/research.md
Normal file
32
specs/002-add-replace-command/research.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Phase 0 Research: Replace Command with Multi-Pattern Support
|
||||
|
||||
## Decision: Literal substring replacement with ordered evaluation
|
||||
- **Rationale**: Aligns with current rename semantics and keeps user expectations simple for first
|
||||
iteration; avoids complexity of regex/glob interactions. Ordered application ensures predictable
|
||||
handling of overlapping patterns.
|
||||
- **Alternatives considered**:
|
||||
- *Regex support*: powerful but significantly increases validation surface and user errors.
|
||||
- *Simultaneous substitution without order*: risk of ambiguous conflicts when one pattern is subset
|
||||
of another.
|
||||
|
||||
## Decision: Dedicated replace service under `internal/replace`
|
||||
- **Rationale**: Keeps responsibilities separated from existing listing module, enabling reusable
|
||||
preview + apply logic while encapsulating pattern parsing, summary, and reporting.
|
||||
- **Alternatives considered**:
|
||||
- *Extending existing listing package*: would blur responsibilities between read-only listing and
|
||||
mutation workflows.
|
||||
- *Embedding in command file*: hinders testability and violates composable rule principle.
|
||||
|
||||
## Decision: Pattern delimiter syntax `with`
|
||||
- **Rationale**: Matches user description and provides a clear boundary between patterns and
|
||||
replacement string. Works well with Cobra argument parsing and allows quoting for whitespace.
|
||||
- **Alternatives considered**:
|
||||
- *Using flags for replacement string*: more verbose and inconsistent with provided example.
|
||||
- *Special separators like `--`*: less descriptive and increases documentation burden.
|
||||
|
||||
## Decision: Conflict detection before apply
|
||||
- **Rationale**: Maintains Preview-First Safety by ensuring duplicates or invalid filesystem names are
|
||||
reported before commit. Reuses existing validation helpers from rename pipeline.
|
||||
- **Alternatives considered**:
|
||||
- *Best-effort renames with partial success*: violates atomic undo expectations.
|
||||
- *Skipping conflicting files silently*: unsafe and would erode trust.
|
||||
115
specs/002-add-replace-command/spec.md
Normal file
115
specs/002-add-replace-command/spec.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Feature Specification: Replace Command with Multi-Pattern Support
|
||||
|
||||
**Feature Branch**: `002-add-replace-command`
|
||||
**Created**: 2025-10-29
|
||||
**Status**: Draft
|
||||
**Input**: User description: "添加 替换(replace)命令,用于替换指定的字符串,支持同时对多个字符串进行替换为一个 示例: renamer replace pattern1 pattern2 with space pattern3 <replacement>"
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2025-10-29
|
||||
|
||||
- Q: What syntax separates patterns from the replacement value? → A: The final positional argument is the replacement; no delimiter keyword is used.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Normalize Naming with One Command (Priority: P1)
|
||||
|
||||
As a CLI user cleaning messy filenames, I want to run `renamer replace` with multiple source
|
||||
patterns so I can normalize all variants to a single replacement in one pass.
|
||||
|
||||
**Why this priority**: Unlocks the main value proposition—batch consolidation of inconsistent
|
||||
substrings without writing custom scripts.
|
||||
|
||||
**Independent Test**: Execute `renamer list` to confirm scope, then `renamer replace foo bar Baz`
|
||||
and verify preview shows every `foo` and `bar` occurrence replaced with `Baz` before confirming.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** files containing `draft`, `Draft`, and `DRAFT`, **When** the user runs `renamer replace draft Draft DRAFT final`, **Then** the preview lists every filename replaced with `final`, and execution applies the same mapping.
|
||||
2. **Given** filenames where patterns appear multiple times, **When** the user runs `renamer replace beta gamma release`, **Then** each occurrence within a single filename is substituted, and the summary highlights total replacements per file.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Script-Friendly Replacement Workflows (Priority: P2)
|
||||
|
||||
As an operator embedding renamer in automation, I want deterministic exit codes and reusable
|
||||
profiles for replace operations so scripts can preview, apply, and undo safely.
|
||||
|
||||
**Why this priority**: Ensures pipelines can rely on the command without interactive ambiguity.
|
||||
|
||||
**Independent Test**: In a CI script, run `renamer replace ... --dry-run` (preview), assert exit code
|
||||
0, then run with `--yes` and check ledger entry plus `renamer undo` restores originals.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a non-interactive environment, **When** the user passes `--yes` to apply replacements after a successful preview, **Then** the command exits 0 on success and writes a ledger entry capturing all mappings.
|
||||
2. **Given** an invalid argument (e.g., only one token supplied), **When** the command executes, **Then** it exits with a non-zero code and explains that the final positional argument becomes the replacement value.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Validate Complex Pattern Input (Priority: P3)
|
||||
|
||||
As a power user handling patterns with spaces or special characters, I want clear syntax guidance
|
||||
and validation feedback so I can craft replacements confidently.
|
||||
|
||||
**Why this priority**: Prevents user frustration when patterns require quoting or escaping.
|
||||
|
||||
**Independent Test**: Run `renamer replace "Project X" "Project-X" ProjectX` and confirm preview
|
||||
resolves both variants, while invalid quoting produces actionable guidance.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a pattern containing whitespace, **When** it is provided in quotes, **Then** the preview reflects the intended substring and documentation shows identical syntax describing the final argument as replacement.
|
||||
2. **Given** duplicate patterns in the same command, **When** the command runs, **Then** duplicates are deduplicated with a warning so replacements remain idempotent.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Replacement produces duplicate target filenames; command must surface conflicts before confirmation.
|
||||
- Patterns overlap within the same filename (e.g., `aaa` replaced via `aa`); order of application must be deterministic and documented.
|
||||
- Case-sensitivity opt-in: default literal matching is case-sensitive, but a future `--ignore-case` option is deferred; command must warn that matches are case-sensitive.
|
||||
- Replacement string empty (aka deletion); preview must show empty substitution clearly and require explicit confirmation.
|
||||
- No files match any pattern; command exits 0 with "No entries matched" messaging and no ledger entry.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The CLI MUST expose `renamer replace <pattern...> <replacement>` and treat all but the final token as literal patterns (quotes support whitespace).
|
||||
- **FR-002**: Replace operations MUST integrate with the existing preview → confirm workflow; previews list old and new names with highlighted substrings.
|
||||
- **FR-003**: Executions MUST append detailed entries to `.renamer` including original names, replacements performed, patterns supplied, and timestamps so undo remains possible.
|
||||
- **FR-004**: Users MUST be able to undo the most recent replace batch via existing undo mechanics without orphaned files.
|
||||
- **FR-005**: Command MUST respect global scope flags (`--recursive`, `--include-dirs`, `--hidden`, `--extensions`, `--path`) identical to `list` / `preview` behavior.
|
||||
- **FR-006**: Command MUST accept two or more patterns and collapse them into a single replacement string applied to every filename in scope.
|
||||
- **FR-007**: Command MUST preserve idempotence by deduplicating patterns and reporting the number of substitutions per pattern in summary output.
|
||||
- **FR-008**: Invalid invocations (fewer than two arguments, empty pattern list after deduplication, missing replacement) MUST fail with exit code ≠0 and actionable usage guidance.
|
||||
- **FR-009**: CLI help MUST document quoting rules for patterns containing spaces or shell special characters.
|
||||
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **ReplaceRequest**: Captures working directory, scope flags, ordered pattern list, replacement string, and preview/apply options.
|
||||
- **ReplaceSummary**: Aggregates per-pattern match counts, per-file changes, and conflict warnings for preview and ledger output.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Users complete a multi-pattern replacement across 100 files with preview + apply in under 2 minutes end-to-end.
|
||||
- **SC-002**: 95% of usability test participants interpret the final positional replacement argument correctly after reading `renamer replace --help`.
|
||||
- **SC-003**: Automated regression tests confirm replace + undo leave the filesystem unchanged in 100% of scripted scenarios.
|
||||
- **SC-004**: Support tickets related to manual string normalization drop by 40% within the first release cycle after launch.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- Patterns are treated as literal substrings; regex support is out of scope for this increment.
|
||||
- Case-sensitive matching aligns with current rename semantics; advanced matching can be added later.
|
||||
- Replacement applies to filenames (and directories when `-d`/`--include-dirs` is set), not file contents.
|
||||
- Existing infrastructure for preview, ledger, and undo can be extended without architectural changes.
|
||||
|
||||
## Dependencies & Risks
|
||||
|
||||
- Requires updates to shared traversal/filter utilities so replace respects global scope flags.
|
||||
- Help/quickstart documentation must be updated alongside the command to prevent misuse.
|
||||
- Potential filename conflicts must be detected pre-apply to avoid data loss; conflict handling relies on existing validation pipeline.
|
||||
169
specs/002-add-replace-command/tasks.md
Normal file
169
specs/002-add-replace-command/tasks.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# Tasks: Replace Command with Multi-Pattern Support
|
||||
|
||||
**Input**: Design documents from `/specs/002-add-replace-command/`
|
||||
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
|
||||
|
||||
**Tests**: Tests are optional; include them only where they support the user story’s independent validation.
|
||||
|
||||
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no dependencies)
|
||||
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
||||
- Include exact file paths in descriptions
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
**Purpose**: Prepare project for replace command implementation
|
||||
|
||||
- [X] T001 Audit root command for shared flags; document expected additions in `cmd/root.go`
|
||||
- [X] T002 Create replace package scaffold in `internal/replace/README.md` with intended module layout
|
||||
- [X] T003 Add sample fixtures directory for replacement tests at `tests/fixtures/replace-samples/README.md`
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Core utilities required by every user story
|
||||
|
||||
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
|
||||
|
||||
- [X] T004 Implement `ReplaceRequest` struct and validators in `internal/replace/request.go`
|
||||
- [X] T005 [P] Implement pattern parser handling quoting/deduplication in `internal/replace/parser.go`
|
||||
- [X] T006 [P] Extend traversal utilities to emit replace candidates in `internal/replace/traversal.go`
|
||||
- [X] T007 [P] Implement replacement engine with overlap handling in `internal/replace/engine.go`
|
||||
- [X] T008 Define summary metrics and conflict structs in `internal/replace/summary.go`
|
||||
- [X] T009 Document replace syntax and flags draft in `docs/cli-flags.md`
|
||||
|
||||
**Checkpoint**: Foundation ready—user story implementation can begin
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 - Normalize Naming with One Command (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: Deliver multi-pattern replacement with preview + apply guarantees
|
||||
|
||||
**Independent Test**: `renamer replace foo bar Baz --dry-run` followed by `--yes`; verify preview shows replacements, apply updates files, and `renamer undo` restores originals.
|
||||
|
||||
### Tests for User Story 1 (OPTIONAL - included for confidence)
|
||||
|
||||
- [X] T010 [P] [US1] Contract test for preview summary counts in `tests/contract/replace_command_test.go`
|
||||
- [X] T011 [P] [US1] Integration test covering multi-pattern apply + undo in `tests/integration/replace_flow_test.go`
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [X] T012 [US1] Implement CLI command wiring in `cmd/replace.go` using shared scope flags
|
||||
- [X] T013 [US1] Implement preview rendering and summary output in `internal/replace/preview.go`
|
||||
- [X] T014 [US1] Hook replace engine into ledger/undo pipeline in `internal/replace/apply.go`
|
||||
- [X] T015 [US1] Add documentation examples to `docs/cli-flags.md` and quickstart
|
||||
|
||||
**Checkpoint**: User Story 1 delivers functional `renamer replace` with preview/apply/undo
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 - Script-Friendly Replacement Workflows (Priority: P2)
|
||||
|
||||
**Goal**: Ensure automation-friendly behaviors (exit codes, non-interactive usage)
|
||||
|
||||
**Independent Test**: Scripted run invoking `renamer replace ... --dry-run` then `--yes`; expect consistent exit codes and ledger entry
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [X] T016 [US2] Implement non-interactive flag validation (`--yes` + positional args) in `cmd/replace.go`
|
||||
- [X] T017 [US2] Add ledger metadata (pattern counts) for automation in `internal/replace/summary.go`
|
||||
- [X] T018 [US2] Expand integration test to assert exit codes for invalid input in `tests/integration/replace_flow_test.go`
|
||||
- [X] T019 [US2] Update quickstart section with automation guidance in `specs/002-add-replace-command/quickstart.md`
|
||||
|
||||
**Checkpoint**: Scripts can rely on deterministic exit codes and ledger data
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 - Validate Complex Pattern Input (Priority: P3)
|
||||
|
||||
**Goal**: Provide resilient handling for whitespace/special-character patterns and user guidance
|
||||
|
||||
**Independent Test**: `renamer replace "Project X" "Project-X" ProjectX --dry-run` plus invalid quoting to verify errors
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [X] T020 [P] [US3] Implement quoting guidance and warnings in `cmd/replace.go`
|
||||
- [X] T021 [P] [US3] Add parser coverage for whitespace patterns in `tests/unit/replace_parser_test.go`
|
||||
- [X] T022 [US3] Surface duplicate pattern warnings in preview summary in `internal/replace/preview.go`
|
||||
- [X] T023 [US3] Document advanced pattern examples in `docs/cli-flags.md`
|
||||
|
||||
**Checkpoint**: Power users receive clear guidance and validation feedback
|
||||
|
||||
---
|
||||
|
||||
## Phase N: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: Final validation, documentation, and release readiness
|
||||
|
||||
- [X] T024 Update agent guidance with replace command details in `AGENTS.md`
|
||||
- [X] T025 Add changelog entry describing new replace command in `docs/CHANGELOG.md`
|
||||
- [X] T026 Create smoke test script covering replace + undo in `scripts/smoke-test-replace.sh`
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Setup (Phase 1)**: No prerequisites
|
||||
- **Foundational (Phase 2)**: Depends on setup completion; blocks all user stories
|
||||
- **User Story 1 (Phase 3)**: Depends on foundational phase; MVP delivery
|
||||
- **User Story 2 (Phase 4)**: Depends on User Story 1 (automation builds on base command)
|
||||
- **User Story 3 (Phase 5)**: Depends on User Story 1 (parser/extensions) and shares foundation
|
||||
- **Polish (Phase N)**: Runs after user stories complete
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- **US1**: Requires foundational tasks
|
||||
- **US2**: Requires US1 implementation + ledger integration
|
||||
- **US3**: Requires US1 parser and preview infrastructure
|
||||
|
||||
### Within Each User Story
|
||||
|
||||
- Tests (if included) should be authored before implementation tasks
|
||||
- Parser/engine updates precede CLI wiring
|
||||
- Documentation updates finalize after behavior stabilizes
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
- Foundational parser/engine/summary tasks (T005–T008) can progress in parallel after T004
|
||||
- US1 tests (T010–T011) can run alongside command wiring (T012–T014)
|
||||
- US3 parser coverage (T021) can proceed independently while warnings (T022) integrate with preview
|
||||
|
||||
---
|
||||
|
||||
## Parallel Example: User Story 1
|
||||
|
||||
```bash
|
||||
# Terminal 1: Write contract test and run in watch mode
|
||||
go test ./tests/contract -run TestReplaceCommandPreview
|
||||
|
||||
# Terminal 2: Implement preview renderer
|
||||
$EDITOR internal/replace/preview.go
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Story 1)
|
||||
1. Complete Setup and Foundational phases
|
||||
2. Implement US1 tasks (T010–T015)
|
||||
3. Ensure preview/apply/undo works end-to-end
|
||||
|
||||
### Incremental Delivery
|
||||
1. Ship US1 (core replace command)
|
||||
2. Layer US2 (automation-friendly exit codes and ledger metadata)
|
||||
3. Add US3 (advanced pattern validation)
|
||||
4. Execute polish tasks for documentation and smoke tests
|
||||
|
||||
### Parallel Team Strategy
|
||||
- Engineer A: Parser/engine/summary foundational work
|
||||
- Engineer B: CLI command wiring + tests (US1)
|
||||
- Engineer C: Automation behaviors and documentation (US2/Polish)
|
||||
- After US1, shift Engineers to handle US3 enhancements and polish concurrently
|
||||
Reference in New Issue
Block a user