Add configurable sequence numbering command
This commit is contained in:
34
specs/001-sequence-numbering/checklists/requirements.md
Normal file
34
specs/001-sequence-numbering/checklists/requirements.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Specification Quality Checklist: Sequence Numbering Command
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2025-10-31
|
||||
**Feature**: [Sequence Numbering Command](../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`
|
||||
241
specs/001-sequence-numbering/contracts/sequence.openapi.yaml
Normal file
241
specs/001-sequence-numbering/contracts/sequence.openapi.yaml
Normal file
@@ -0,0 +1,241 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Renamer Sequence Command Contract
|
||||
version: 0.1.0
|
||||
description: >
|
||||
Conceptual REST contract for the `renamer sequence` CLI behavior, used to
|
||||
formalize preview/apply expectations for testing and documentation.
|
||||
servers:
|
||||
- url: cli://local
|
||||
paths:
|
||||
/sequence/preview:
|
||||
post:
|
||||
summary: Generate a deterministic sequence numbering preview.
|
||||
operationId: previewSequence
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SequenceRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Preview generated successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SequencePlan'
|
||||
'400':
|
||||
description: Invalid configuration (e.g., width <= 0, invalid separator).
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/sequence/apply:
|
||||
post:
|
||||
summary: Apply sequence numbering to previously previewed candidates.
|
||||
operationId: applySequence
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/SequenceRequest'
|
||||
- type: object
|
||||
properties:
|
||||
confirm:
|
||||
type: boolean
|
||||
const: true
|
||||
responses:
|
||||
'200':
|
||||
description: Sequence numbering applied.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SequenceApplyResult'
|
||||
'207':
|
||||
description: Applied with skipped conflicts.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SequenceApplyResult'
|
||||
'400':
|
||||
description: Invalid configuration or missing confirmation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'409':
|
||||
description: Scope filters yielded zero candidates.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
components:
|
||||
schemas:
|
||||
SequenceRequest:
|
||||
type: object
|
||||
required:
|
||||
- start
|
||||
- placement
|
||||
- separator
|
||||
properties:
|
||||
path:
|
||||
type: string
|
||||
description: Root directory for traversal.
|
||||
recursive:
|
||||
type: boolean
|
||||
includeDirs:
|
||||
type: boolean
|
||||
description: Directories remain untouched even when included.
|
||||
hidden:
|
||||
type: boolean
|
||||
extensions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
pattern: '^\\.[^./]+$'
|
||||
dryRun:
|
||||
type: boolean
|
||||
yes:
|
||||
type: boolean
|
||||
start:
|
||||
type: integer
|
||||
minimum: 1
|
||||
width:
|
||||
type: integer
|
||||
minimum: 1
|
||||
placement:
|
||||
type: string
|
||||
enum: [prefix, suffix]
|
||||
separator:
|
||||
type: string
|
||||
minLength: 1
|
||||
pattern: '^[^/\\\\]+$'
|
||||
SequencePlan:
|
||||
type: object
|
||||
required:
|
||||
- candidates
|
||||
- config
|
||||
- summary
|
||||
properties:
|
||||
candidates:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SequenceCandidate'
|
||||
skippedConflicts:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SequenceConflict'
|
||||
summary:
|
||||
$ref: '#/components/schemas/SequenceSummary'
|
||||
config:
|
||||
$ref: '#/components/schemas/SequenceConfig'
|
||||
SequenceCandidate:
|
||||
type: object
|
||||
required:
|
||||
- originalPath
|
||||
- proposedPath
|
||||
- index
|
||||
properties:
|
||||
originalPath:
|
||||
type: string
|
||||
proposedPath:
|
||||
type: string
|
||||
index:
|
||||
type: integer
|
||||
minimum: 0
|
||||
SequenceConflict:
|
||||
type: object
|
||||
required:
|
||||
- originalPath
|
||||
- conflictingPath
|
||||
- reason
|
||||
properties:
|
||||
originalPath:
|
||||
type: string
|
||||
conflictingPath:
|
||||
type: string
|
||||
reason:
|
||||
type: string
|
||||
enum: [existing_target, invalid_separator, width_overflow]
|
||||
SequenceSummary:
|
||||
type: object
|
||||
required:
|
||||
- totalCandidates
|
||||
- renamedCount
|
||||
- skippedCount
|
||||
properties:
|
||||
totalCandidates:
|
||||
type: integer
|
||||
renamedCount:
|
||||
type: integer
|
||||
skippedCount:
|
||||
type: integer
|
||||
warnings:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
SequenceConfig:
|
||||
type: object
|
||||
required:
|
||||
- start
|
||||
- placement
|
||||
- separator
|
||||
properties:
|
||||
start:
|
||||
type: integer
|
||||
width:
|
||||
type: integer
|
||||
placement:
|
||||
type: string
|
||||
enum: [prefix, suffix]
|
||||
separator:
|
||||
type: string
|
||||
SequenceApplyResult:
|
||||
type: object
|
||||
required:
|
||||
- plan
|
||||
- ledgerEntry
|
||||
properties:
|
||||
plan:
|
||||
$ref: '#/components/schemas/SequencePlan'
|
||||
ledgerEntry:
|
||||
$ref: '#/components/schemas/SequenceLedgerEntry'
|
||||
SequenceLedgerEntry:
|
||||
type: object
|
||||
required:
|
||||
- rule
|
||||
- config
|
||||
- operations
|
||||
properties:
|
||||
timestamp:
|
||||
type: string
|
||||
format: date-time
|
||||
rule:
|
||||
type: string
|
||||
const: sequence
|
||||
config:
|
||||
$ref: '#/components/schemas/SequenceConfig'
|
||||
operations:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SequenceOperation'
|
||||
SequenceOperation:
|
||||
type: object
|
||||
required:
|
||||
- from
|
||||
- to
|
||||
properties:
|
||||
from:
|
||||
type: string
|
||||
to:
|
||||
type: string
|
||||
ErrorResponse:
|
||||
type: object
|
||||
required:
|
||||
- message
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
68
specs/001-sequence-numbering/data-model.md
Normal file
68
specs/001-sequence-numbering/data-model.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Data Model: Sequence Numbering Command
|
||||
|
||||
## SequenceRequest
|
||||
- **Fields**
|
||||
- `Path` (string): Root path for traversal (defaults to current directory); must exist and be accessible.
|
||||
- `Recursive` (bool): Includes subdirectories when true.
|
||||
- `IncludeDirs` (bool): Includes directories in traversal results without numbering.
|
||||
- `Hidden` (bool): Includes hidden files when true.
|
||||
- `Extensions` ([]string): Optional `.`-prefixed extension filter; deduplicated and validated.
|
||||
- `DryRun` (bool): Indicates preview-only execution.
|
||||
- `Yes` (bool): Confirmation flag for apply mode.
|
||||
- `Start` (int): First sequence value; must be ≥1.
|
||||
- `Width` (int): Minimum digits for zero padding; must be ≥1 when provided.
|
||||
- `Placement` (enum: `prefix` | `suffix`): Determines where the sequence number is inserted; default `suffix`.
|
||||
- `Separator` (string): Separator between number and filename; defaults to `_`; must comply with filesystem rules (no path separators, non-empty).
|
||||
- **Relationships**: Consumed by traversal service to produce candidates and by sequence rule to generate `SequencePlan`.
|
||||
- **Validations**: Numeric fields validated before preview; separator sanitized; conflicting flags (dry-run vs yes) rejected.
|
||||
|
||||
## SequencePlan
|
||||
- **Fields**
|
||||
- `Candidates` ([]SequenceCandidate): Ordered list of files considered for numbering.
|
||||
- `SkippedConflicts` ([]SequenceConflict): Files skipped due to target path collisions.
|
||||
- `Summary` (SequenceSummary): Counts for total candidates, renamed files, and skipped items.
|
||||
- `Config` (SequenceConfig): Snapshot of sequence settings (start, width, placement, separator).
|
||||
- **Relationships**: Passed to output package for preview rendering and to history package for ledger persistence.
|
||||
- **Validations**: Candidate ordering must match traversal ordering; conflicts identified before apply.
|
||||
|
||||
### SequenceCandidate
|
||||
- **Fields**
|
||||
- `OriginalPath` (string)
|
||||
- `ProposedPath` (string)
|
||||
- `Index` (int): Zero-based position used to derive padded number.
|
||||
- **Constraints**: Proposed path must differ from original to be considered a rename; duplicates flagged as conflicts.
|
||||
|
||||
### SequenceConflict
|
||||
- **Fields**
|
||||
- `OriginalPath` (string)
|
||||
- `ConflictingPath` (string)
|
||||
- `Reason` (string enum: `existing_target`, `invalid_separator`, `width_overflow`)
|
||||
|
||||
### SequenceSummary
|
||||
- **Fields**
|
||||
- `TotalCandidates` (int)
|
||||
- `RenamedCount` (int)
|
||||
- `SkippedCount` (int)
|
||||
- `Warnings` ([]string)
|
||||
|
||||
## SequenceLedgerEntry
|
||||
- **Fields**
|
||||
- `Timestamp` (time.Time)
|
||||
- `Rule` (string): Fixed value `sequence`.
|
||||
- `Config` (SequenceConfig): Stored to support undo.
|
||||
- `Operations` ([]SequenceOperation): Each captures `From` and `To` paths actually renamed.
|
||||
- **Relationships**: Append-only entry written by history package; consumed by undo command.
|
||||
- **Validations**: Only include successful renames (skipped conflicts omitted). Undo must verify files still exist before attempting reversal.
|
||||
|
||||
### SequenceOperation
|
||||
- **Fields**
|
||||
- `From` (string)
|
||||
- `To` (string)
|
||||
|
||||
## SequenceConfig
|
||||
- **Fields**
|
||||
- `Start` (int)
|
||||
- `Width` (int)
|
||||
- `Placement` (string)
|
||||
- `Separator` (string)
|
||||
- **Usage**: Embedded in plan summaries, ledger entries, and undo operations to ensure consistent behavior across preview and apply.
|
||||
87
specs/001-sequence-numbering/plan.md
Normal file
87
specs/001-sequence-numbering/plan.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Implementation Plan: Sequence Numbering Command
|
||||
|
||||
**Branch**: `001-sequence-numbering` | **Date**: 2025-11-03 | **Spec**: `specs/001-sequence-numbering/spec.md`
|
||||
**Input**: Feature specification from `/specs/001-sequence-numbering/spec.md`
|
||||
|
||||
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
|
||||
|
||||
## Summary
|
||||
|
||||
Deliver a new `renamer sequence` command that appends deterministic sequence numbers to file candidates following the preview-first workflow. The command respects existing scope flags, supports configuration for start value, width, placement, and separator, records batches in the `.renamer` ledger for undo, and skips conflicting filesystem entries while warning the user.
|
||||
|
||||
## Technical Context
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the content in this section with the technical details
|
||||
for the project. The structure here is presented in advisory capacity to guide
|
||||
the iteration process.
|
||||
-->
|
||||
|
||||
**Language/Version**: Go 1.24
|
||||
**Primary Dependencies**: `spf13/cobra`, `spf13/pflag`, internal traversal/history/output packages
|
||||
**Storage**: Local filesystem + `.renamer` ledger files
|
||||
**Testing**: `go test ./...`, contract + integration suites under `tests/`
|
||||
**Target Platform**: Cross-platform CLI (Linux/macOS/Windows shells)
|
||||
**Project Type**: CLI application (single Go project)
|
||||
**Performance Goals**: Preview + apply 500 files in ≤120s; preview/apply parity ≥95%
|
||||
**Constraints**: Deterministic ordering, atomic ledger writes, skip conflicts while warning
|
||||
**Scale/Scope**: Operates on batches up to hundreds of files per invocation
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- Preview flow will extend existing preview pipeline to list original → numbered name mappings and highlight skipped conflicts before requiring `--yes`.
|
||||
- Undo strategy leverages ledger entries capturing sequence parameters (start, width, placement) and per-file mappings, ensuring reversal mirrors numbering order.
|
||||
- Sequence rule will be implemented as a composable transformation module declaring inputs (scope candidates + sequence config), validations, and outputs, reusable across preview/apply.
|
||||
- Scope handling continues to consume existing traversal services, honoring `-d`, `-r`, `--extensions`, and leaving directories untouched per clarified requirement while preventing scope escape.
|
||||
- CLI UX will wire flags via Cobra, update help text, and add tests covering flag validation, preview output, warning messaging, and undo flow consistency.
|
||||
|
||||
**Post-Design Review:** Research and design artifacts confirm all principles remain satisfied; no constitution waivers required.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/[###-feature]/
|
||||
├── plan.md # This file (/speckit.plan command output)
|
||||
├── research.md # Phase 0 output (/speckit.plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
|
||||
for this feature. Delete unused options and expand the chosen structure with
|
||||
real paths (e.g., apps/admin, packages/something). The delivered plan must
|
||||
not include Option labels.
|
||||
-->
|
||||
|
||||
```text
|
||||
cmd/
|
||||
├── renamer/ # Cobra CLI entrypoints and command wiring
|
||||
internal/
|
||||
├── traversal/ # Scope resolution and ordering services
|
||||
├── history/ # Ledger and undo utilities
|
||||
├── output/ # Preview/summary formatting
|
||||
└── sequence/ # [to be added] sequence rule implementation
|
||||
tests/
|
||||
├── contract/ # CLI contract tests
|
||||
├── integration/ # Multi-command flow tests
|
||||
└── smoke/ # Smoke scripts under scripts/
|
||||
```
|
||||
|
||||
**Structure Decision**: Extend existing single Go CLI project; new logic lives under `internal/sequence`, with command wiring in `cmd/renamer`.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> **Fill ONLY if Constitution Check has violations that must be justified**
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
|
||||
| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
|
||||
55
specs/001-sequence-numbering/quickstart.md
Normal file
55
specs/001-sequence-numbering/quickstart.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Quickstart: Sequence Numbering Command
|
||||
|
||||
## Prerequisites
|
||||
- Go 1.24 toolchain installed.
|
||||
- `renamer` repository cloned and bootstrapped (`go mod tidy` already satisfied in repo).
|
||||
- Test fixtures available under `tests/` for validation runs.
|
||||
|
||||
## Build & Install
|
||||
```bash
|
||||
go build -o bin/renamer ./cmd/renamer
|
||||
```
|
||||
|
||||
## Preview Sequence Numbering
|
||||
```bash
|
||||
bin/renamer sequence \
|
||||
--path ./fixtures/sample-batch \
|
||||
--dry-run
|
||||
```
|
||||
Outputs a preview table showing `001_`, `002_`, … prefixes based on alphabetical order.
|
||||
|
||||
## Customize Formatting
|
||||
```bash
|
||||
bin/renamer sequence \
|
||||
--path ./fixtures/sample-batch \
|
||||
--start 10 \
|
||||
--width 4 \
|
||||
--number-prefix seq \
|
||||
--separator "" \
|
||||
--dry-run
|
||||
```
|
||||
Produces names such as `seq0010file.ext`. Errors if width/start are invalid.
|
||||
|
||||
## Apply Changes
|
||||
```bash
|
||||
bin/renamer sequence \
|
||||
--path ./fixtures/sample-batch \
|
||||
--yes
|
||||
```
|
||||
Writes rename results to the `.renamer` ledger while skipping conflicting targets and warning the user.
|
||||
|
||||
## Undo Sequence Batch
|
||||
```bash
|
||||
bin/renamer undo --path ./fixtures/sample-batch
|
||||
```
|
||||
Restores filenames using the most recent ledger entry.
|
||||
|
||||
## Run Automated Tests
|
||||
```bash
|
||||
go test ./...
|
||||
tests/integration/remove_flow_test.go # existing suites ensure regressions are caught
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- Conflict warnings indicate existing files with the same numbered name; resolve manually or adjust flags.
|
||||
- Zero candidates cause a 409-style error; adjust scope flags to include desired files.
|
||||
26
specs/001-sequence-numbering/research.md
Normal file
26
specs/001-sequence-numbering/research.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Research Log
|
||||
|
||||
## Cobra Flag Validation For Sequence Command
|
||||
- **Decision**: Validate `--start`, `--width`, `--placement`, and `--separator` flags using Cobra command `PreRunE` with shared helpers, returning errors for invalid inputs before preview executes.
|
||||
- **Rationale**: Cobra documentation and community guides recommend using `RunE`/`PreRunE` to surface validation errors with non-zero exit codes, ensuring CLI consistency and enabling tests to cover messaging.
|
||||
- **Alternatives considered**: Inline validation inside business logic (rejected—mixes CLI parsing with domain rules and complicates contract tests); custom flag types (rejected—adds complexity without additional value).
|
||||
|
||||
## Sequence Ordering And Determinism
|
||||
- **Decision**: Reuse the existing traversal service to produce a stable, path-sorted candidate list and derive sequence numbers from index positions in the preview plan.
|
||||
- **Rationale**: Internal traversal package already guarantees deterministic ordering and filtering; leveraging it avoids duplicating scope logic and satisfies Preview-First and Scope-Aware principles.
|
||||
- **Alternatives considered**: Implement ad-hoc sorting inside sequence rule (rejected—risk of diverging from other commands); rely on filesystem iteration order (rejected—non-deterministic across platforms).
|
||||
|
||||
## Ledger Metadata Capture
|
||||
- **Decision**: Extend history ledger entries with a new sequence record type storing sequence parameters and per-file mappings, ensuring undo can skip missing files but restore others.
|
||||
- **Rationale**: Existing ledger pattern (as used by replace/remove commands) stores rule metadata for undo; following same structure keeps undo consistent and auditable.
|
||||
- **Alternatives considered**: Store only file rename pairs without parameters (rejected—undo would lack context if future migrations require differentiation); create a separate ledger file (rejected—breaks append-only guarantee).
|
||||
|
||||
## Conflict Handling Strategy
|
||||
- **Decision**: During apply, skip conflicting file targets, log a warning via output package, and continue numbering remaining candidates; conflicts remain in preview so users can resolve them beforehand.
|
||||
- **Rationale**: Aligns with clarified requirements and minimizes partial ledger entries while informing users; consistent with existing warning infrastructure used by other commands.
|
||||
- **Alternatives considered**: Abort entire batch on conflict (rejected—user explicitly requested skip behavior); auto-adjust numbers (rejected—violates preview/apply parity).
|
||||
|
||||
## Directory Inclusion Policy
|
||||
- **Decision**: Filter traversal results so directories included via `--include-dirs` are reported but not renamed; numbering applies only to file candidates.
|
||||
- **Rationale**: Keeps command behavior predictable, avoids confusing two numbering schemes, and respects clarified requirement without altering traversal contract tests.
|
||||
- **Alternatives considered**: Separate numbering sequences for files vs directories (rejected—adds complexity with little user need); rename directories by default (rejected—breaks clarified guidance).
|
||||
109
specs/001-sequence-numbering/spec.md
Normal file
109
specs/001-sequence-numbering/spec.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Feature Specification: Sequence Numbering Command
|
||||
|
||||
**Feature Branch**: `001-sequence-numbering`
|
||||
**Created**: 2025-10-31
|
||||
**Status**: Draft
|
||||
**Input**: User description: "添加 sequence 功能,为重命名文件添加序号,可以定义序列号长度 使用0左填充,可以指定序列号开始序号"
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2025-11-03
|
||||
|
||||
- Q: How should the command behave when the generated filename already exists outside the current batch (e.g., `file_001.txt`)? → A: Skip conflicting files, continue, and warn.
|
||||
- Q: How are sequence numbers applied when new files appear between preview and apply, potentially altering traversal order? → A: Ignore new files and rename only the previewed set.
|
||||
- Q: What validation and messaging occur when the starting number, width, or separator arguments are invalid (negative numbers, zero width, multi-character separator conflicting with filesystem rules)? → A: Hard error with non-zero exit and no preview output.
|
||||
- Q: How is numbering handled for directories when `--include-dirs` is used alongside files within the same traversal scope? → A: Do not rename directories; sequence applies to files only.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Add Sequential Indices to Batch (Priority: P1)
|
||||
|
||||
As a content manager preparing assets for delivery, I want to append an auto-incrementing number to each filename within my selected scope so that downstream systems receive files in a predictable order.
|
||||
|
||||
**Why this priority**: Sequencing multiple files is the primary value of the feature and removes the need for external renaming tools for common workflows such as media preparation or document packaging.
|
||||
|
||||
**Independent Test**: Place three files in a working directory, run `renamer sequence --path <dir> --dry-run`, and verify the preview shows `001_`, `002_`, `003_` prefixes in deterministic order. Re-run with `--yes` and confirm the ledger captures the batch.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a directory containing `draft.txt`, `notes.txt`, and `plan.txt`, **When** the user runs `renamer sequence --dry-run --path <dir>`, **Then** the preview lists each file renamed with a `001_` prefix in alphabetical order and reports the candidate totals.
|
||||
2. **Given** the same directory and preview, **When** the user re-executes the command with `--yes`, **Then** the CLI reports three files updated and the `.renamer` ledger stores the sequence configuration.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Control Number Formatting (Priority: P2)
|
||||
|
||||
As an archivist following strict naming standards, I want to define the sequence width and zero padding so the filenames meet fixed-length requirements without additional scripts.
|
||||
|
||||
**Why this priority**: Formatting options broaden adoption by matching industry conventions (e.g., four-digit reels) and avoid manual corrections after renaming.
|
||||
|
||||
**Independent Test**: Run `renamer sequence --width 4 --path <dir> --dry-run` and confirm every previewed filename contains a four-digit, zero-padded sequence value.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** files `cutA.mov` and `cutB.mov`, **When** the user runs `renamer sequence --width 4 --dry-run`, **Then** the preview shows `0001_` and `0002_` prefixes despite having only two files.
|
||||
2. **Given** the same files, **When** the user omits an explicit width, **Then** the preview pads only as needed to accommodate the highest sequence number (e.g., `1_`, `2_`, `10_`).
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Configure Starting Number and Placement (Priority: P3)
|
||||
|
||||
As a production coordinator resuming interrupted work, I want to choose the starting sequence value and whether the number appears as a prefix or suffix so I can continue existing numbering schemes without renaming older assets.
|
||||
|
||||
**Why this priority**: Starting offsets and placement control reduce rework when numbering must align with partner systems or previously delivered batches.
|
||||
|
||||
**Independent Test**: Run `renamer sequence --start 10 --dry-run` and confirm the preview begins at `010_` and inserts the number before the filename stem with the configured separator.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** files `shotA.exr` and `shotB.exr`, **When** the user runs `renamer sequence --start 10 --dry-run`, **Then** the preview numbers the files starting at `010_` and `011_`.
|
||||
2. **Given** files `cover.png` and `index.png`, **When** the user runs `renamer sequence --placement prefix --separator "-" --dry-run`, **Then** the preview shows names such as `001-cover.png` and `002-index.png` with the separator preserved.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Generated filename conflicts with an existing filesystem entry outside the batch: skip the conflicting candidate, continue with the rest, and warn with conflict details.
|
||||
- Requested width smaller than digits required is automatically expanded with a warning so numbering completes without truncation.
|
||||
- New files encountered between preview and apply are ignored; only the previewed candidates are renamed.
|
||||
- Invalid starting number, width, or separator arguments produce a hard error with non-zero exit status; no preview or apply runs until corrected.
|
||||
- Directories included via `--include-dirs` are left unchanged; numbering applies exclusively to files.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The CLI MUST expose a `sequence` command that applies an ordered numbering rule to all candidates within the current scope while preserving the preview-first workflow used by other renamer commands.
|
||||
- **FR-002**: The command MUST use a deterministic ordering strategy (default: path-sorted traversal after scope filters) so preview and apply yield identical sequences.
|
||||
- **FR-003**: Users MUST be able to configure the sequence starting value via a `--start` flag (default `1`) accepting positive integers only, with validation errors for invalid input.
|
||||
- **FR-004**: Users MUST be able to configure the minimum digit width via a `--width` flag (default determined by total candidates) and the tool MUST zero-pad numbers to match the requested width.
|
||||
- **FR-005**: Users MUST be able to choose number placement (`prefix` or `suffix`, default prefix) and optionally set a separator string plus static number prefix/suffix tokens while preserving file extensions and directory structure.
|
||||
- **FR-006**: Preview output MUST display original and proposed names, total candidates, total changed, and warnings when numbering would exceed the requested width or create conflicts.
|
||||
- **FR-007**: Apply MUST record the numbering rule (start, width, placement, separator, ordering) in the `.renamer` ledger, alongside per-file operations, so that undo can faithfully restore original names.
|
||||
- **FR-008**: Undo MUST revert sequence-based renames in reverse order even if additional files have been added since the apply step, skipping only those already removed.
|
||||
- **FR-009**: The `sequence` command MUST respect existing scope flags (`--path`, `--recursive`, `--include-dirs`, `--hidden`, `--extensions`, `--dry-run`, `--yes`) with identical semantics to other commands.
|
||||
- **FR-010**: When numbering would collide with an existing filesystem entry, the CLI MUST skip the conflicting candidate, continue numbering the remaining files, and emit a warning that lists the skipped items; apply MUST still abort if scope filters yield zero candidates.
|
||||
- **FR-011**: Invalid formatting arguments (negative start, zero/negative width, unsupported separator) MUST trigger a human-readable error, exit with non-zero status, and prevent preview/apply execution.
|
||||
- **FR-012**: Directories included in scope via `--include-dirs` MUST be preserved without numbering; only files receive sequence numbers while directories remain untouched.
|
||||
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **SequenceRequest**: Captures user-supplied configuration (start value, width, placement, separator, scope flags, execution mode).
|
||||
- **SequencePlan**: Represents the ordered list of candidate files with assigned sequence numbers, proposed names, conflicts, and summary counts.
|
||||
- **SequenceLedgerEntry**: Stores metadata required for undo, including request parameters, execution timestamp, and file rename mappings.
|
||||
|
||||
### Assumptions
|
||||
|
||||
- Ordering follows the preview list sorted by relative path unless future features introduce additional ordering controls.
|
||||
- If numbering exceeds the requested width, the command extends the width automatically, surfaces a warning, and continues rather than failing the batch.
|
||||
- Default placement is prefix with an underscore separator (e.g., `001_name.ext`) unless overridden by flags.
|
||||
- Scope and ledger behavior mirror existing rename commands; no new traversal modes are introduced.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Users can number 500 files (preview + apply) in under 120 seconds on a representative workstation without manual intervention.
|
||||
- **SC-002**: At least 95% of sampled previews match their subsequent apply results exactly during beta testing (no ordering drift or mismatched numbering).
|
||||
- **SC-003**: 90% of beta participants report that numbering settings (start value, width, placement) meet their formatting needs without external tools.
|
||||
- **SC-004**: Support requests related to manual numbering workflows decrease by 40% within one release cycle after launch.
|
||||
115
specs/001-sequence-numbering/tasks.md
Normal file
115
specs/001-sequence-numbering/tasks.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Tasks: Sequence Numbering Command
|
||||
|
||||
**Input**: Design documents from `/specs/001-sequence-numbering/`
|
||||
**Prerequisites**: `plan.md`, `spec.md`, `research.md`, `data-model.md`, `contracts/`, `quickstart.md`
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
**Purpose**: Establish scaffolding required by all user stories.
|
||||
|
||||
- [X] T001 Create sequence package documentation stub in `internal/sequence/doc.go`
|
||||
- [X] T002 Seed sample fixtures for numbering scenarios in `testdata/sequence/basic/`
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Shared components that every sequence story depends on.
|
||||
|
||||
- [X] T003 Define sequence options struct with default values in `internal/sequence/options.go`
|
||||
- [X] T004 Implement zero-padding formatter helper in `internal/sequence/format.go`
|
||||
- [X] T005 Introduce plan and summary data structures in `internal/sequence/plan.go`
|
||||
|
||||
**Checkpoint**: Base package compiles with shared types ready for story work.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 - Add Sequential Indices to Batch (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: Append auto-incremented suffixes (e.g., `_001`) to scoped files with deterministic ordering and ledger persistence.
|
||||
|
||||
**Independent Test**: `renamer sequence --dry-run --path <dir>` on three files shows `_001`, `_002`, `_003`; rerun with `--yes` updates ledger.
|
||||
|
||||
### Tests for User Story 1
|
||||
|
||||
- [X] T006 [P] [US1] Add preview contract test covering default numbering in `tests/contract/sequence_preview_test.go`
|
||||
- [X] T007 [P] [US1] Add integration flow test verifying preview/apply parity in `tests/integration/sequence_flow_test.go`
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [X] T008 [US1] Implement candidate traversal adapter using listing scope in `internal/sequence/traversal.go`
|
||||
- [X] T009 [US1] Generate preview plan with conflict detection in `internal/sequence/preview.go`
|
||||
- [X] T010 [US1] Apply renames and record sequence metadata in `internal/sequence/apply.go`
|
||||
- [X] T011 [US1] Wire Cobra sequence command execution in `cmd/sequence.go`
|
||||
- [X] T012 [US1] Register sequence command on the root command in `cmd/root.go`
|
||||
|
||||
**Checkpoint**: Sequence preview/apply for default suffix behavior is fully testable and undoable.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 - Control Number Formatting (Priority: P2)
|
||||
|
||||
**Goal**: Allow explicit width flag with zero padding and warning when auto-expanding.
|
||||
|
||||
**Independent Test**: `renamer sequence --width 4 --dry-run` shows `_0001` suffixes; omitting width auto-expands on demand.
|
||||
|
||||
### Tests for User Story 2
|
||||
|
||||
- [X] T013 [P] [US2] Add contract test for explicit width padding in `tests/contract/sequence_width_test.go`
|
||||
- [X] T014 [P] [US2] Add integration test validating width flag and warnings in `tests/integration/sequence_width_test.go`
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [X] T015 [US2] Extend options validation to handle width flag rules in `internal/sequence/options.go`
|
||||
- [X] T016 [US2] Update preview planner to enforce configured width and warnings in `internal/sequence/preview.go`
|
||||
- [X] T017 [US2] Parse and bind `--width` flag within Cobra command in `cmd/sequence.go`
|
||||
|
||||
**Checkpoint**: Users can control sequence width with deterministic zero-padding.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 - Configure Starting Number and Placement (Priority: P3)
|
||||
|
||||
**Goal**: Support custom start offsets plus prefix/suffix placement with configurable separator.
|
||||
|
||||
**Independent Test**: `renamer sequence --start 10 --placement prefix --separator "-" --dry-run` produces `0010-file.ext` entries.
|
||||
|
||||
### Tests for User Story 3
|
||||
|
||||
- [X] T018 [P] [US3] Add contract test for start and placement variants in `tests/contract/sequence_placement_test.go`
|
||||
- [X] T019 [P] [US3] Add integration test for start offset with undo coverage in `tests/integration/sequence_start_test.go`
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [X] T020 [US3] Validate start, placement, and separator flags in `internal/sequence/options.go`
|
||||
- [X] T021 [US3] Update preview generation to honor prefix/suffix placement and separators in `internal/sequence/preview.go`
|
||||
- [X] T022 [US3] Persist placement and separator metadata during apply in `internal/sequence/apply.go`
|
||||
- [X] T023 [US3] Wire `--start`, `--placement`, and `--separator` flags in `cmd/sequence.go`
|
||||
|
||||
**Checkpoint**: Placement and numbering customization scenarios fully supported with ledger fidelity.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Cross-Cutting Concerns
|
||||
|
||||
- [X] T024 [P] Document sequence command flags in `docs/cli-flags.md`
|
||||
- [X] T025 [P] Log sequence feature addition in `docs/CHANGELOG.md`
|
||||
- [X] T026 [P] Update command overview with sequence entry in `README.md`
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Setup (Phase 1) → Foundational (Phase 2) → US1 (Phase 3) → US2 (Phase 4) → US3 (Phase 5) → Polish (Phase 6)
|
||||
- User Story dependencies: `US1` completion unlocks `US2`; `US2` completion unlocks `US3`.
|
||||
|
||||
## Parallel Execution Opportunities
|
||||
|
||||
- Contract and integration test authoring tasks (T006, T007, T013, T014, T018, T019) can run concurrently with implementation once shared scaffolding is ready.
|
||||
- Documentation polish tasks (T024–T026) can be executed in parallel after all story implementations stabilize.
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
1. Deliver MVP by completing Phase 1–3 (US1), enabling default sequence numbering with undo.
|
||||
2. Iterate with formatting controls (Phase 4) to broaden usability while maintaining preview/apply parity.
|
||||
3. Finish with placement customization (Phase 5) and polish tasks (Phase 6) before release.
|
||||
Reference in New Issue
Block a user