From 73c4534495ba8a049574864cad8f52dd491e7c28 Mon Sep 17 00:00:00 2001 From: winjer Date: Fri, 25 Sep 2026 15:51:35 +0100 Subject: [PATCH] archive: fix-repo-tag-worktree (merge tags spec + archive change) --- .../design.md | 0 .../implementation.md | 0 .../specs/tags/spec.md | 0 .../2026-09-25-fix-repo-tag-worktree}/work.md | 0 planflow/specs/tags/spec.md | 95 +++++++++++++++++++ 5 files changed, 95 insertions(+) rename planflow/{changes/fix-repo-tag-worktree => archive/2026-09-25-fix-repo-tag-worktree}/design.md (100%) rename planflow/{changes/fix-repo-tag-worktree => archive/2026-09-25-fix-repo-tag-worktree}/implementation.md (100%) rename planflow/{changes/fix-repo-tag-worktree => archive/2026-09-25-fix-repo-tag-worktree}/specs/tags/spec.md (100%) rename planflow/{changes/fix-repo-tag-worktree => archive/2026-09-25-fix-repo-tag-worktree}/work.md (100%) create mode 100644 planflow/specs/tags/spec.md diff --git a/planflow/changes/fix-repo-tag-worktree/design.md b/planflow/archive/2026-09-25-fix-repo-tag-worktree/design.md similarity index 100% rename from planflow/changes/fix-repo-tag-worktree/design.md rename to planflow/archive/2026-09-25-fix-repo-tag-worktree/design.md diff --git a/planflow/changes/fix-repo-tag-worktree/implementation.md b/planflow/archive/2026-09-25-fix-repo-tag-worktree/implementation.md similarity index 100% rename from planflow/changes/fix-repo-tag-worktree/implementation.md rename to planflow/archive/2026-09-25-fix-repo-tag-worktree/implementation.md diff --git a/planflow/changes/fix-repo-tag-worktree/specs/tags/spec.md b/planflow/archive/2026-09-25-fix-repo-tag-worktree/specs/tags/spec.md similarity index 100% rename from planflow/changes/fix-repo-tag-worktree/specs/tags/spec.md rename to planflow/archive/2026-09-25-fix-repo-tag-worktree/specs/tags/spec.md diff --git a/planflow/changes/fix-repo-tag-worktree/work.md b/planflow/archive/2026-09-25-fix-repo-tag-worktree/work.md similarity index 100% rename from planflow/changes/fix-repo-tag-worktree/work.md rename to planflow/archive/2026-09-25-fix-repo-tag-worktree/work.md diff --git a/planflow/specs/tags/spec.md b/planflow/specs/tags/spec.md new file mode 100644 index 0000000..3ad474d --- /dev/null +++ b/planflow/specs/tags/spec.md @@ -0,0 +1,95 @@ +# tags Specification + +## Purpose + +Defines how `gather_env_tags` derives the git-related environment tags (`repo:`, `org:`) from the working directory's git context. + +### Requirement: Repo tag derived from origin remote URL +The system SHALL derive the `repo:` tag from the last path segment of the origin remote URL (with trailing `.git` stripped), not from the working-tree directory basename. + +#### Scenario: Clone in a worktree-named directory with SSH remote +- GIVEN a git repository whose origin remote is `git@github.com:org/hbf.git` +- AND the working tree directory is named `wt579b` (a linked worktree) +- WHEN `gather_env_tags` collects tags +- THEN the tag `repo:hbf` SHALL be emitted, not `repo:wt579b` + +#### Scenario: Clone in a ticket-named directory with HTTPS remote +- GIVEN a git repository whose origin remote is `https://github.com/org/hbf.git` +- AND the working tree directory is named `hbf-578-idfix` +- WHEN `gather_env_tags` collects tags +- THEN the tag `repo:hbf` SHALL be emitted, not `repo:hbf-578-idfix` + +#### Scenario: ssh:// protocol URL form +- GIVEN a git repository whose origin remote is `ssh://git@github.com/org/hbf.git` +- WHEN `gather_env_tags` collects tags +- THEN the tag `repo:hbf` SHALL be emitted regardless of the working-tree directory name + +#### Scenario: GitLab subgroup URL +- GIVEN a git repository whose origin remote is `git@gitlab.com:acme/platform/widgets.git` +- WHEN `gather_env_tags` collects tags +- THEN the tag `repo:widgets` SHALL be emitted (last path segment, ignoring subgroups) + +#### Scenario: HTTPS URL without .git suffix +- GIVEN a git repository whose origin remote is `https://github.com/acme/widgets` (no trailing `.git`) +- WHEN `gather_env_tags` collects tags +- THEN the tag `repo:widgets` SHALL be emitted + +### Requirement: Repo tag fallback to show-toplevel basename +The system SHALL fall back to the `git rev-parse --show-toplevel` basename for the `repo:` tag when no origin remote exists, or when the origin remote URL is unparseable (e.g. a local filesystem path). + +#### Scenario: No origin remote +- GIVEN a git repository with no origin remote configured +- WHEN `gather_env_tags` collects tags +- THEN the tag `repo:` SHALL be emitted, where toplevel-basename is the directory name from `git rev-parse --show-toplevel` +- AND no `org:` tag SHALL be emitted + +#### Scenario: Origin remote is a local path +- GIVEN a git repository whose origin remote is `/home/doug/projects/widgets` (a local filesystem path, no scheme and no SCP-style colon) +- WHEN `gather_env_tags` collects tags +- THEN `repo_from_remote_url` SHALL return `None` for the local path +- AND the tag `repo:` SHALL be emitted as a fallback + +### Requirement: Show-toplevel not called when remote URL is parseable +The system SHALL NOT invoke `git rev-parse --show-toplevel` when the origin remote URL is present and successfully parsed by `repo_from_remote_url`, to avoid a redundant git subprocess in the common case. + +#### Scenario: Remote present and parseable +- GIVEN a git repository with a valid origin remote URL (SCP-style, ssh://, or https://) +- WHEN `gather_env_tags` collects tags +- THEN `repo:` SHALL be derived from `repo_from_remote_url` +- AND `git rev-parse --show-toplevel` SHALL NOT be invoked + +### Requirement: repo_from_remote_url URL normalisation +The system SHALL provide a `repo_from_remote_url` function that normalises git remote URLs identically to `org_from_remote_url` but returns the last path segment (repository name) instead of the second-to-last (organisation). It SHALL return `None` for local paths and unparseable URLs. + +#### Scenario: SCP-style URL +- GIVEN `repo_from_remote_url("git@github.com:acme/widgets.git")` +- WHEN the function is called +- THEN it SHALL return `Some("widgets")` + +#### Scenario: HTTPS URL +- GIVEN `repo_from_remote_url("https://github.com/acme/widgets.git")` +- WHEN the function is called +- THEN it SHALL return `Some("widgets")` + +#### Scenario: ssh:// protocol URL +- GIVEN `repo_from_remote_url("ssh://git@github.com/acme/widgets.git")` +- WHEN the function is called +- THEN it SHALL return `Some("widgets")` + +#### Scenario: HTTPS URL without .git suffix +- GIVEN `repo_from_remote_url("https://github.com/acme/widgets")` +- WHEN the function is called +- THEN it SHALL return `Some("widgets")` + +#### Scenario: GitLab subgroup URL +- GIVEN `repo_from_remote_url("git@gitlab.com:acme/platform/widgets.git")` +- WHEN the function is called +- THEN it SHALL return `Some("widgets")` + +#### Scenario: Local path +- GIVEN `repo_from_remote_url("/home/doug/projects/widgets")` +- WHEN the function is called +- THEN it SHALL return `None` + +### Requirement: Org tag derivation unchanged +The system SHALL derive the `org:` tag from `org_from_remote_url` applied to the origin remote URL, identically to the pre-change behaviour. The restructure of the repo and org tag blocks into a single coordinated block SHALL NOT alter the org tag's value, ordering (after `repo:`), or fallback behaviour (no org tag when no remote or unparseable URL).