Skip to content

feat: Initialize-GitDefaults.ps1 -- compose .gitattributes/.gitignore from upstream templates#161

Open
MarkMichaelis wants to merge 10 commits into
mainfrom
feat/160-init-git-defaults
Open

feat: Initialize-GitDefaults.ps1 -- compose .gitattributes/.gitignore from upstream templates#161
MarkMichaelis wants to merge 10 commits into
mainfrom
feat/160-init-git-defaults

Conversation

@MarkMichaelis
Copy link
Copy Markdown
Contributor

Summary

Ship Initialize-GitDefaults.ps1 (repo root) and retire the static .gitattributes.template first-sync scaffold. Composes .gitattributes and .gitignore for a consumer project from per-language community templates plus a curated PowerShell block.

Closes #160

Pinned upstream sources

File Upstream Authority Pinned SHA
*.gitattributes alexkaratarakis/gitattributes Community de facto -- no GitHub-org source exists fddc586cf0f10ec4485028d0d2dd6f73197a4258
*.gitignore github/gitignore GitHub-org authoritative -- powers GitHub's picker dcc0fc7bc2b5ba480cf117ad1be31bafceeaff46

(verified: gh api repos/github/gitattributes/commits/main returns 404 at pin time.)

Discoveries (documented in SOURCES.md)

  1. VisualStudio.gitattributes does NOT exist in alexkaratarakis/gitattributes at the pinned SHA. Decision: dropped from bundle; ASP.NET inherits only CSharp.gitattributes.
  2. PowerShell.gitattributes DOES exist upstream but per the spec we ship a curated in-script block (smaller surface, signing-aware, linguist-language=PowerShell hints).

Language coverage

Language gitattributes gitignore
CSharp Common + CSharp VisualStudio
PowerShell Common + curated block curated block
TypeScript Common + Web Node
ASP.NET Common + CSharp (dep) VisualStudio (shared)

Dependency graph: ASP.NET -> CSharp. Backed by Resolve-GitDefaultsLanguages.

Pull-SDLC.ai.ps1 integration

  • git rm .gitattributes.template
  • Removed .gitattributes.template from $script:TemplateScaffoldMap and $script:UpstreamManagedPaths.
  • Added .github/templates/git-defaults/ to $script:UpstreamManagedPaths so bundled snapshots flow to consumers on sync.
  • New Write-GitDefaultsHint (called from Write-NextStepsBanner) prints a one-liner pointing at ./Initialize-GitDefaults.ps1 when .gitattributes or .gitignore is missing. Never auto-invokes.

Tests

  • Initialize-GitDefaults.Tests.ps1 -- 28/28 GREEN (unit + integration; -WhatIf; backup/force; full target stack).
  • Pull-SDLC.ai.Tests.ps1 targeted groups (Invoke-TemplateScaffold, README.md.template, Write-NextStepsBanner, Issue Pull-SDLC.ai bootstrap: 4 findings on fresh-repo carve-out path #148 carve-out, Initialize-GitDefaults migration, Write-GitDefaultsHint, etc.) -- 87/87 GREEN.
  • Anti-collusion sabotage verified: 11 behavioural failures in unit tests when Resolve-GitDefaultsLanguages is short-circuited; targeted failures in the migration suite when managed-paths surgery is reverted.

PSScriptAnalyzer

  • Initialize-GitDefaults.ps1 -- 0 findings (file-level SuppressMessageAttribute for project-wide accepted patterns: Write-Host, New-* pure-string-builder ShouldProcess, plural noun for set operations).
  • Pull-SDLC.ai.ps1 -- 94 findings, identical to main baseline (0 new).

Acceptance criteria status

  • Invoke-Pester on Initialize-GitDefaults.Tests.ps1 -- 28/28 PASS
  • Invoke-Pester on targeted Pull-SDLC.ai.Tests.ps1 groups -- 87/87 PASS (full file scheduled for CI)
  • PSScriptAnalyzer reports zero new findings vs main on both scripts
  • ./Initialize-GitDefaults.ps1 -Language CSharp,PowerShell,TypeScript -Force in fresh temp dir composes both files end-to-end, exit 0 (see evidence)
  • ./Initialize-GitDefaults.ps1 -Language ASP.NET -Force includes CSharp content (dependency resolved)
  • .gitattributes.template gone from repo
  • Fresh sync into consumer worktree without .gitattributes prints the hint (observed in carve-out integration test stdout)

How to verify locally

Invoke-Pester -Path .\Initialize-GitDefaults.Tests.ps1
Invoke-Pester -Path .\Pull-SDLC.ai.Tests.ps1

End-to-end smoke:

$probe = Join-Path $env:TEMP "init-gd-probe"
New-Item -ItemType Directory -Path $probe -Force | Out-Null
Set-Location $probe; git init --quiet
& "<repo>/Initialize-GitDefaults.ps1" -Language CSharp,PowerShell,TypeScript,ASP.NET -Force
Get-Content .gitattributes | Select-Object -First 12
Get-Content .gitignore     | Select-Object -First 12

Compose .gitattributes and .gitignore for a consumer project from
per-language community templates (alexkaratarakis/gitattributes,
github/gitignore) plus a curated PowerShell block.

Languages: CSharp, PowerShell, TypeScript, ASP.NET (depends on
CSharp). Pinned SHAs bundled under .github/templates/git-defaults.
Discovery note: alexkaratarakis/gitattributes has no
VisualStudio.gitattributes at the pinned SHA; ASP.NET inherits
CSharp only.

Tests: 28/28 Pester green. Anti-collusion sabotage verified: 11
behavioural failures when Resolve-GitDefaultsLanguages returns a
fixed value.

Refs #160
…aults.ps1

- Remove .gitattributes.template from upstream (deleted file).
- Remove the .gitattributes.template -> .gitattributes scaffold map
  entry; drop .gitattributes.template from $script:UpstreamManagedPaths.
- Add .github/templates/git-defaults/ to $script:UpstreamManagedPaths
  so the bundled snapshots flow into consumer projects on sync.
- Extend Write-NextStepsBanner: new Write-GitDefaultsHint prints a
  one-line pointer to ./Initialize-GitDefaults.ps1 when a fresh
  consumer worktree is missing .gitattributes or .gitignore. We do
  NOT auto-invoke -- language selection is project-specific.
- Replace the obsolete '.gitattributes.template bootstrap (#119)'
  Describe block with a generic Invoke-TemplateScaffold block plus
  new migration regression tests covering both data structures and
  the hint banner.
- README.md / CLAUDE.md / copilot-instructions.md: document
  Initialize-GitDefaults.ps1 alongside Pull-SDLC.ai.ps1; remove
  .gitattributes.template references.
- SOURCES.md: pinned-SHA + authority distinction + refresh recipe.
- PSScriptAnalyzer: 0 new findings on Initialize-GitDefaults.ps1
  (file-level suppressions for the Write-Host / ShouldProcess /
  SingularNouns false positives the project already tolerates) and
  Pull-SDLC.ai.ps1 stays at the 94-finding main baseline.

Tests:
- Initialize-GitDefaults.Tests.ps1: 28/28 GREEN
- Targeted Pull-SDLC.ai.Tests.ps1 (87 tests in the changed-code
  groups, incl. the issue #148 carve-out e2e fixture): GREEN
- Anti-collusion sabotage confirmed behavioural sensitivity in both
  test files.

Closes #160
@MarkMichaelis
Copy link
Copy Markdown
Contributor Author

Phase 5b Evidence -- Initialize-GitDefaults.ps1 end-to-end

Issue: #160
Branch: feat/160-init-git-defaults
HEAD: d0cce8a
Captured: 2026-05-31T02:58:48Z

Intent (from issue #160)

Compose .gitattributes and .gitignore for a consumer project by
combining per-language community templates (alexkaratarakis/gitattributes

  • github/gitignore) plus a curated PowerShell block. The full target
    stack today is CSharp + PowerShell + TypeScript + ASP.NET (depends on
    CSharp).

Canonical command

./Initialize-GitDefaults.ps1 -Language CSharp,PowerShell,TypeScript,ASP.NET -Force

run inside a fresh temp git repo.

Captured stdout

Wrote .gitattributes (ASP.NET, CSharp, PowerShell, TypeScript)
Wrote .gitignore (ASP.NET, CSharp, PowerShell, TypeScript)

Resulting .gitattributes (head)

Line count: 354

# Generated by Initialize-GitDefaults.ps1 on 2026-05-31T02:58:47Z
# Languages: ASP.NET, CSharp, PowerShell, TypeScript
# Sources:
#   alexkaratarakis/gitattributes @ fddc586cf0f10ec4485028d0d2dd6f73197a4258 (community de facto; no GitHub-org source exists) -> Common, CSharp, Web
# Curated additions: PowerShell (no upstream template)
# Re-run Initialize-GitDefaults.ps1 to refresh or add languages.


# === Common (Common.gitattributes) ===

# Common settings that generally should always be used with your language specific settings

Section dividers found:

# === Common (Common.gitattributes) ===
# === CSharp (CSharp.gitattributes) ===
# === PowerShell (curated in-script) ===
# === Web (Web.gitattributes) ===

Resulting .gitignore (head)

Line count: 592

# Generated by Initialize-GitDefaults.ps1 on 2026-05-31T02:58:48Z
# Languages: ASP.NET, CSharp, PowerShell, TypeScript
# Sources:
#   github/gitignore @ dcc0fc7bc2b5ba480cf117ad1be31bafceeaff46 (GitHub-org authoritative) -> VisualStudio, Node
# Curated additions: PowerShell (no upstream template)
# Re-run Initialize-GitDefaults.ps1 to refresh or add languages.


# === VisualStudio (VisualStudio.gitignore) ===

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

Section dividers found:

# === VisualStudio (VisualStudio.gitignore) ===
# === PowerShell (curated in-script) ===
# === Node (Node.gitignore) ===

Test summary

  • Invoke-Pester Initialize-GitDefaults.Tests.ps1 -> 28/28 GREEN
  • Targeted Pull-SDLC.ai.Tests.ps1 groups (Invoke-TemplateScaffold,
    Write-NextStepsBanner, Initialize-GitDefaults migration,
    Write-GitDefaultsHint, Issue Pull-SDLC.ai bootstrap: 4 findings on fresh-repo carve-out path #148 carve-out, README.md.template, etc.)
    -> 87/87 GREEN (61 + 26)
  • PSScriptAnalyzer on Initialize-GitDefaults.ps1 -> 0 findings
  • PSScriptAnalyzer on Pull-SDLC.ai.ps1 -> 94 findings, same as
    baseline on main (no new findings)

Verdict

A = yes: the captured artifact shows both files written end-to-end with
the expected per-language sections (Common, CSharp, Web, PowerShell for
gitattributes; VisualStudio, Node, PowerShell for gitignore) and ASP.NET
dependency-expanded into CSharp.

B = no: no regressions in adjacent test groups; analyzer baseline holds.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the static .gitattributes.template bootstrap path with a new Initialize-GitDefaults.ps1 workflow that composes .gitattributes and .gitignore from bundled upstream language templates plus curated PowerShell defaults.

Changes:

  • Adds Initialize-GitDefaults.ps1, tests, and pinned git-default template snapshots.
  • Updates Pull-SDLC.ai.ps1 to stop scaffolding .gitattributes.template and print a git-defaults hint.
  • Updates README and agent instruction docs to describe the new initialization flow.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
README.md Documents removal of static .gitattributes scaffolding and new git-defaults script.
CLAUDE.md Adds guidance for running Initialize-GitDefaults.ps1.
.github/copilot-instructions.md Mirrors the new git-defaults initialization guidance.
Pull-SDLC.ai.ps1 Removes .gitattributes.template management and adds git-defaults hinting.
Pull-SDLC.ai.Tests.ps1 Updates scaffold tests and adds migration/hint coverage.
Initialize-GitDefaults.ps1 New script to compose .gitattributes and .gitignore.
Initialize-GitDefaults.Tests.ps1 New Pester coverage for language resolution, content generation, and integration behavior.
.gitattributes.template Removes the retired static template.
.github/templates/git-defaults/* Adds pinned bundled gitignore/gitattributes source snapshots and source documentation.

Comment thread Pull-SDLC.ai.ps1
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1
- UpstreamManagedPaths now lists Initialize-GitDefaults.ps1 and its
  Tests file so Pull-SDLC.ai will replace local edits on sync.
- -Refresh hard-errors with a clear "not yet implemented" message
  instead of silently using bundled snapshots under a misleading
  header. Overriding -GitattributesRef/-GitignoreRef without -Refresh
  is also blocked to prevent header drift.
- When -Language is omitted in an interactive host, a simple
  comma-separated picker now runs with detected languages offered as
  the default. New Get-GitDefaultsDetectedLanguages function scans
  the working tree for .csproj/.psm1/tsconfig.json/appsettings.json
  indicator files; ASP.NET requires both .csproj AND appsettings.
- Backup-GitDefaultsFile now uses tick-resolution (100ns) suffixes
  on .bak collisions, with a uniqueness loop, so two backups in the
  same second can never overwrite each other.
- Help block rewritten to honestly describe the implemented behaviour
  (no more reserved-future-feature wording in the synopsis).

Tests: 36 Pester tests passing (was 28); new coverage for the four
review threads. PSScriptAnalyzer clean.

Co-authored-by: GitHub Copilot <noreply@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 7 comments.

Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Pull-SDLC.ai.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1
Seven new findings, all addressed:

- Preflight existence check: Initialize-GitDefaults now tests for ALL
  requested target files before writing ANY of them, so when -Force
  is omitted and (say) only .gitignore exists, the script aborts
  without leaving a freshly-written .gitattributes behind. Previously
  the first write succeeded and the second threw, producing a partial
  result.
- Curated PowerShell block: the in-script comment and the generated
  file header both said "no upstream template" but SOURCES.md
  documents that PowerShell.gitattributes DOES exist upstream and is
  intentionally overridden. Comments + header now describe the
  override honestly and point at SOURCES.md.
- Generated-file footer no longer tells consumers to "re-run to
  refresh" -- that wording implied -Refresh works, which it does not.
  Footer now reads "regenerate or add languages".
- Get-GitDefaultsTemplateContent error no longer suggests -Refresh
  for a missing bundled snapshot; it suggests re-running Pull-SDLC.ai
  instead (which is what actually restores .github/templates/).
- Global/Backup.gitignore was bundled but never emitted; .gitignore
  now always includes the cross-platform Backup section as its final
  block.
- Write-GitDefaultsHint (Pull-SDLC.ai.ps1) now branches three ways
  -- both missing / only .gitattributes missing / only .gitignore
  missing -- and gives the appropriate single-file command
  (-IncludeGitignore:$false or -IncludeGitattributes:$false) so the
  hint does not steer users into the preflight abort.

Tests: 39 Pester tests on Initialize-GitDefaults (added 5);
Write-GitDefaultsHint suite expanded from 3 to 5 cases. All targeted
suites green, PSScriptAnalyzer baseline unchanged.

Co-authored-by: GitHub Copilot <noreply@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comment thread Initialize-GitDefaults.ps1
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1
Three findings, all addressed:

- Kind-aware curated PowerShell header: the previous "intentional
  override of upstream" line was emitted for both generated files,
  but it is only honest for .gitattributes (where upstream DOES ship
  a PowerShell.gitattributes that we replace). For .gitignore the
  header now says "no upstream PowerShell.gitignore exists in
  github/gitignore", matching the in-script comment on the curated
  block and SOURCES.md.
- Removed dead GiboName metadata from $script:GitDefaultsLanguages.
  No code reads it; carrying it invited drift between the registry
  and actual composition behaviour. Re-introduce it if/when the
  network-fetch path is wired in.
- New behaviour-first tests for the no-Language branch using Pester
  Mock to simulate both the non-interactive picker (returns null,
  Initialize-GitDefaults throws with the supported-language list)
  and the interactive picker (returns CSharp+PowerShell, full
  generation proceeds end-to-end). Plus an additional kitchen-sink
  test that exercises every heuristic in
  Get-GitDefaultsDetectedLanguages.

Tests: 45 Pester (added 6); all green. PSScriptAnalyzer clean.

Co-authored-by: GitHub Copilot <noreply@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Comment thread Initialize-GitDefaults.ps1
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1
Comment thread Initialize-GitDefaults.ps1
Four findings, all addressed:

- Strict mode: Initialize-GitDefaults.ps1 now sets
  Set-StrictMode -Version Latest and $ErrorActionPreference = 'Stop'
  immediately after the param block, matching the convention used by
  Pull-SDLC.ai.ps1, Cleanup-Worktree.ps1, and Consolidate-Tasks.ps1.
  Catches undefined variables and non-terminating cmdlet errors that
  would previously continue silently while composing consumer files.

- -Refresh is now implemented (previously hard-errored). New helpers:
    * Get-GitDefaultsCacheRoot   -- platform-aware cache dir
      ($LOCALAPPDATA on Windows, $XDG_CACHE_HOME / $HOME/.cache on
      Unix, falling back to temp).
    * Resolve-GitDefaultsSourceRepo -- maps a template file name to
      (Repo, Ref) using the appropriate ref param.
    * Get-GitDefaultsRefreshedContent -- fetches from
      raw.githubusercontent.com/<repo>/<ref>/<file>, writes the
      response into the cache directory, and returns the content.
      If the fetch fails AND a previously-cached copy exists, falls
      back to the cache with a warning. If both fail, throws with a
      clear message naming the URL and cache path.
  Get-GitDefaultsTemplateContent now accepts -Refresh and routes
  through Get-GitDefaultsRefreshedContent in that case. The compose
  functions thread -Refresh / -GitattributesRef / -GitignoreRef
  through to each fetch call. Generated-file headers now include a
  "Source mode: bundled snapshot" or "Source mode: fetched from
  upstream" line so consumers can tell at a glance which path was
  used. The curated PowerShell block is always in-script and is
  unaffected by -Refresh.

- gibo non-dependency: SOURCES.md now has a "Why not gibo?" section
  explaining why Initialize-GitDefaults talks directly to
  raw.githubusercontent.com instead of shelling out to the gibo
  helper (same upstream, but with SHA pinning + cache-fallback that
  gibo does not offer). Closes the spec-vs-implementation gap raised
  by the reviewer.

- Tests for one-file invocations: -IncludeGitignore:$false and
  -IncludeGitattributes:$false each get their own behaviour-first
  test proving the existing untouched-file is preserved (no .bak
  written, content byte-identical), the requested file is created,
  and the omitted file is not silently created in the empty-tree
  case. Plus 6 new tests exercising the -Refresh code path end-to-
  end via mocked Invoke-WebRequest: verifies the fetched URLs
  (CSharp set), verifies sentinel content lands in the generated
  files, verifies the "fetched" / "bundled" header label, verifies
  override of -GitattributesRef changes the fetch URL, verifies
  cache fallback on network failure, and verifies the no-cache hard
  error message.

Tests: 53 Pester (was 45). All targeted Pull-SDLC tests still green.
PSScriptAnalyzer baseline unchanged (0 on Initialize-GitDefaults.ps1,
94 pre-existing on Pull-SDLC.ai.ps1).

Co-authored-by: GitHub Copilot <noreply@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Comment thread Initialize-GitDefaults.ps1
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread .github/templates/git-defaults/SOURCES.md Outdated
Comment thread Pull-SDLC.ai.ps1
Comment thread Pull-SDLC.ai.Tests.ps1 Outdated
Five threads from the round-5 Copilot review on PR #161:

1. d9R atomic compose-then-write: Initialize-GitDefaults composes
   both .gitattributes and .gitignore in memory BEFORE writing
   either. A failure during the second compose (network/cache miss
   under -Refresh) no longer leaves the consumer half-updated.

2. d9T -WhatIf cache safety: Get-GitDefaultsRefreshedContent now
   uses SupportsShouldProcess and gates the cache write through
   ShouldProcess so -WhatIf does not mutate the on-disk cache.
   Fetched content is still returned so the dry-run preview
   composes correctly.

3. d9X SOURCES.md stale procedure: rewrote the Refresh procedure
   section to distinguish (A) the now-implemented runtime cache
   refresh consumers get via -Refresh from (B) the maintainer-only
   bundled-snapshot bump procedure in this repo.

4. d9Y + d9d tombstone: retained .gitattributes.template in
   $script:UpstreamManagedPaths as a tombstone (with explanatory
   comment) so already-onboarded consumers receive the deletion op
   from Get-UpstreamOps. Inverted the corresponding Pester
   assertion.

Tests: 55 Initialize-GitDefaults tests + 21 targeted Pull-SDLC
tests all GREEN. PSSA unchanged from prior commit (3 baseline on
Initialize-GitDefaults.ps1, 146 baseline on Pull-SDLC.ai.ps1; the
3 on the new script are pre-existing PSUseOutputTypeCorrectly
findings unrelated to this change).

Refs #160
Co-authored-by: GitHub Copilot <noreply@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Comment thread Initialize-GitDefaults.Tests.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Pull-SDLC.ai.ps1
Five new threads from the round-6 Copilot review on PR #161:

1. hJM cache pollution from tests: the round-4 -Refresh tests used
   the real default pinned SHAs while mocking Invoke-WebRequest,
   so sentinel content was being written into the user's real
   cache for production refs. The tests now generate a synthetic
   per-test ref, pass it explicitly to every Initialize-GitDefaults
   call, and clean up the cache entries in AfterEach.

2. hJQ dynamic-scope hazard in New-GitDefaultsHeader: -GitattributesRef
   / -GitignoreRef are now explicit parameters of the helper with
   defaults from $script:DefaultGit*Ref. Both internal call sites
   (New-GitAttributesContent, New-GitIgnoreContent) pass them
   through. The helper no longer relies on the caller's scope.

3. hJY swallowed cache-write failures: split the single try/catch
   in Get-GitDefaultsRefreshedContent so that (a) fetch failures
   fall back to a cached copy if available, and (b) a successful
   fetch whose cache write later fails warns once and still returns
   the freshly-fetched content. Stale cached copies can no longer
   silently replace a good download.

4. hJd .slnx detection gap: Get-GitDefaultsDetectedLanguages now
   includes *.slnx alongside *.csproj and *.sln when detecting
   CSharp, matching the generated .gitattributes which already
   handles .slnx.

5. hJg tombstone staging gap: the Pull-SDLC.ai staging loop now
   includes a tracked-but-deleted managed path (via
   git ls-files --error-unmatch) so the D op produced for the
   .gitattributes.template tombstone reaches the sync commit
   instead of being left unstaged.

Tests: 57 Initialize-GitDefaults tests + 22 targeted Pull-SDLC
tests (including a new "Tombstone deletion staging" describe that
verifies a tracked-but-deleted path gets staged as a deletion) all
GREEN. PSSA baseline unchanged: 3 on Initialize-GitDefaults.ps1,
146 on Pull-SDLC.ai.ps1.

Refs #160
Co-authored-by: GitHub Copilot <noreply@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comment thread Initialize-GitDefaults.ps1
Comment thread Pull-SDLC.ai.ps1 Outdated
Comment thread Pull-SDLC.ai.Tests.ps1 Outdated
Three new threads from the round-7 Copilot review on PR #161:

1. jkb auto-detection of PowerShell from IntelliSDLC.ai's own
   .ps1 files: Get-GitDefaultsDetectedLanguages now excludes a
   known list of tool files (Pull-SDLC.ai.ps1,
   Initialize-GitDefaults.ps1, Cleanup-Worktree.ps1,
   Consolidate-Tasks.ps1, run.ps1, their *.Tests.ps1 siblings)
   and anything under .github/. Consumers who only have the
   synced tooling no longer get PowerShell pre-selected; adding
   a single consumer .ps1 alongside the tooling still detects.

2. jkg Write-GitDefaultsHint suppressed when Pull-SDLC.ai had
   merge-created a vanilla .gitignore: the hint now uses a new
   Test-GitDefaultsGeneratedMarker helper that scans the first
   4 KB of each file for the "# Generated by
   Initialize-GitDefaults.ps1" header. Mere file presence is no
   longer treated as "the consumer has the language-aware file
   they need." Hint copy updated to "No language-aware ..."
   for honesty.

3. jkk in-process tombstone test was simulating production
   logic instead of exercising it: replaced with a real
   end-to-end test that builds a New-DiffReplayFixture where
   the anchor commit has .gitattributes.template and the next
   upstream commit deletes it, then invokes Invoke-PullSDLC
   and asserts (a) the file is gone from the working tree,
   (b) git status is clean (no unstaged deletion), and
   (c) the tip commit actually contains the D entry.

Tests: 59 Initialize-GitDefaults tests + 23 targeted Pull-SDLC
tests (added 2 detection-exclusion tests, 1 merge-created
hint test, replaced 1 tombstone test with a real e2e). PSSA
baseline unchanged: 3 / 146.

Refs #160
Co-authored-by: GitHub Copilot <noreply@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Comment thread Initialize-GitDefaults.ps1 Outdated
Comment thread Pull-SDLC.ai.ps1 Outdated
Two new threads from the round-8 Copilot review on PR #161:

1. k2H Windows path-separator gap: GetRelativePath returns
   backslash-separated paths on Windows, so the round-7
   `.github/*` filter never matched tooling files under
   `.github\` and PowerShell could still be wrongly
   pre-selected. The filter now normalizes the relative path
   with `-replace '\\','/'` before the like-match.

2. k2P round-7's "Generated by" header check would mistreat
   every hand-maintained .gitattributes/.gitignore as missing
   and badger consumers every sync. Replaced with file-presence
   PLUS an explicit `-NewlyMergedFiles` signal from
   Pull-SDLC.ai: Invoke-PullSDLC now snapshots which paths in
   $script:MergePaths existed BEFORE the union-merge step and
   passes the set of freshly-created ones (e.g. a vanilla
   .gitignore that the sync just merge-created from upstream)
   to Write-NextStepsBanner -> Write-GitDefaultsHint. The hint
   fires when a file is missing OR was just merge-created on
   this sync; pre-existing hand-maintained files are left
   alone. Test-GitDefaultsGeneratedMarker helper removed.

Tests: 60 Initialize-GitDefaults tests (added 1 .github\
backslash test) + targeted Pull-SDLC tests including the full
10-test Invoke-PullSDLC end-to-end suite and 7 Write-GitDefaultsHint
cases (added 2 round-8 cases: "merge-created file still prompts"
and "hand-maintained files leave the consumer alone") all
GREEN. PSSA baseline unchanged: 3 / 146.

Refs #160
Co-authored-by: GitHub Copilot <noreply@github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Comment on lines +418 to +423
function New-GitIgnoreContent {
<#
.SYNOPSIS
Compose a complete .gitignore file body for the supplied languages.
#>
[CmdletBinding()]
Comment on lines +663 to +674
# Default both switches to on when neither is supplied.
if (-not $PSBoundParameters.ContainsKey('IncludeGitignore') -and
-not $PSBoundParameters.ContainsKey('IncludeGitattributes')) {
$IncludeGitignore = $true
$IncludeGitattributes = $true
}
elseif (-not $PSBoundParameters.ContainsKey('IncludeGitignore')) {
$IncludeGitignore = $true
}
elseif (-not $PSBoundParameters.ContainsKey('IncludeGitattributes')) {
$IncludeGitattributes = $true
}
Comment on lines +171 to +185
$resolved = [System.Collections.Generic.HashSet[string]]::new()
foreach ($lang in $Language) {
if (-not $lang) { continue }
$key = $lang.ToLowerInvariant()
if (-not $canonicalMap.ContainsKey($key)) {
$supported = ($script:GitDefaultsLanguages.Keys | Sort-Object) -join ', '
throw "Unknown language '$lang'. Supported languages: $supported."
}
$canonical = $canonicalMap[$key]
[void]$resolved.Add($canonical)
foreach ($dep in $script:GitDefaultsLanguages[$canonical].Deps) {
[void]$resolved.Add($dep)
}
}
return @($resolved | Sort-Object)
@@ -0,0 +1,739 @@
<#
Comment on lines +676 to +678
if (-not (Test-GitDefaultsRepo)) {
throw "Current directory is not a git repository. Run 'git init' first or cd into a repo."
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Initialize-GitDefaults.ps1 -- compose .gitattributes/.gitignore from upstream templates

2 participants