Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 15 additions & 2 deletions .agents/skills/repo-conventions/references/convention-authoring.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions apm.lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions conventions/agentic-repo/convention.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ conventions:
name: agentic-repo
text: |
.agents/
.github/instructions/
apm.lock.yaml
apm.yml
- path: ../apm
Expand Down
9 changes: 9 additions & 0 deletions conventions/copilot-lsp/convention.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
conventions:
- path: ../prettierignore-section
commit:
message: Update .prettierignore for copilot-lsp
settings:
name: copilot-lsp
text: |
.github/lsp.json

pull-request:
auto-merge: true
75 changes: 75 additions & 0 deletions conventions/gitattributes-lf/convention.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,79 @@ Describe 'gitattributes-lf convention' {
}
}

It 'bypasses commit hooks when git no-verify is requested' {
$testDirectory = New-TemporaryDirectory

try {
# Arrange a noncompliant repository whose commit-msg hook rejects every commit.
Initialize-TestRepository -Path $testDirectory
$gitattributesPath = Join-Path $testDirectory '.gitattributes'
[System.IO.File]::WriteAllText($gitattributesPath, "* -text`n", $utf8)
$hookPath = Join-Path $testDirectory '.git' 'hooks' 'commit-msg'
[System.IO.File]::WriteAllText($hookPath, "#!/bin/sh`nexit 1`n", $utf8)
if ($IsLinux -or $IsMacOS) {
& chmod '+x' $hookPath
}

Push-Location $testDirectory
try {
& git add -A
& git commit -m 'Add noncompliant gitattributes' --no-verify | Out-Null
}
finally {
Pop-Location
}

# Build a RepoConventions input that requests the git hook bypass.
$inputPath = New-ConventionInputFile -Settings @{} -GitNoVerify

try {
# Apply the convention; its commits must succeed despite the failing hook.
Invoke-ConventionScript -ScriptPath $script:conventionScriptPath -RepositoryRoot $testDirectory -InputPath $inputPath | Out-Null
}
finally {
Remove-Item -LiteralPath $inputPath -ErrorAction SilentlyContinue
}

# Assert the convention created its bypassing commit and left the tree clean.
$commitSubjects = @(Get-CommitSubjects -TestDirectory $testDirectory -Count 1)
$commitSubjects[0] | Should -Be 'Use LF'
(@(Get-GitStatusLines -TestDirectory $testDirectory)).Count | Should -Be 0
}
finally {
Remove-Item -LiteralPath $testDirectory -Recurse -Force
}
}

It 'fails on commit hooks when git no-verify is not requested' {
$testDirectory = New-TemporaryDirectory

try {
# Arrange a noncompliant repository whose commit-msg hook rejects every commit.
Initialize-TestRepository -Path $testDirectory
$gitattributesPath = Join-Path $testDirectory '.gitattributes'
[System.IO.File]::WriteAllText($gitattributesPath, "* -text`n", $utf8)
$hookPath = Join-Path $testDirectory '.git' 'hooks' 'commit-msg'
[System.IO.File]::WriteAllText($hookPath, "#!/bin/sh`nexit 1`n", $utf8)
if ($IsLinux -or $IsMacOS) {
& chmod '+x' $hookPath
}

Push-Location $testDirectory
try {
& git add -A
& git commit -m 'Add noncompliant gitattributes' --no-verify | Out-Null
}
finally {
Pop-Location
}

# Apply the convention without requesting the bypass; the hook must block the commit.
{ InvokeGitattributesLfConvention -TestDirectory $testDirectory } | Should -Throw "*Failed to create commit 'Use LF'.*"
}
finally {
Remove-Item -LiteralPath $testDirectory -Recurse -Force
}
}

}
10 changes: 9 additions & 1 deletion conventions/gitattributes-lf/convention.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ $OutputEncoding = $utf8
$helpersPath = Join-Path $PSScriptRoot '..' 'scripts' 'Helpers.ps1'
. $helpersPath

# Honor the RepoConventions git hook bypass request
$gitNoVerify = Read-ConventionGitNoVerify -InputPath $args[0]

$requiredRule = '* text=auto eol=lf'
$gitattributesPath = Join-Path -Path (Get-Location) -ChildPath '.gitattributes'
$gitattributesDisplayPath = Format-RepositoryRelativePath -Path $gitattributesPath
Expand Down Expand Up @@ -58,7 +61,12 @@ function NewCommitFromStagedChanges {
return $null
}

InvokeGit -Arguments @('commit', '-m', $Message) -FailureMessage "Failed to create commit '$Message'."
$commitArguments = @('commit', '-m', $Message)
if ($gitNoVerify) {
$commitArguments += '--no-verify'
}

InvokeGit -Arguments $commitArguments -FailureMessage "Failed to create commit '$Message'."
[string[]] $headLines = @(InvokeGit -Arguments @('rev-parse', 'HEAD') -CaptureOutput -FailureMessage 'Failed to read the current commit ID.')
return $headLines[0]
}
Expand Down
14 changes: 14 additions & 0 deletions conventions/scripts/Helpers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,20 @@ function Read-ConventionSettings {
return (Get-Content -LiteralPath $InputPath -Raw | ConvertFrom-Json -AsHashtable).settings
}

<#
.SYNOPSIS
Reads whether RepoConventions requested that git hooks be bypassed for this run.
#>
function Read-ConventionGitNoVerify {
param(
[Parameter(Mandatory = $true)]
[string] $InputPath
)

# RepoConventions exposes the --git-no-verify flag under git.noVerify.
return [bool] (Get-Content -LiteralPath $InputPath -Raw | ConvertFrom-Json -AsHashtable).git.noVerify
}

<#
.SYNOPSIS
Resolves a repository-root-relative path setting to a full path.
Expand Down
17 changes: 10 additions & 7 deletions conventions/scripts/TestHelpers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,26 @@ $helpersPath = Join-Path $PSScriptRoot 'Helpers.ps1'
Creates a temporary RepoConventions input file for a test.
#>
function New-ConventionInputFile {
[CmdletBinding(DefaultParameterSetName = 'Settings')]
[CmdletBinding(DefaultParameterSetName = 'Structured')]
param(
[Parameter(Mandatory = $true, ParameterSetName = 'Settings')]
[Parameter(Mandatory = $true, ParameterSetName = 'Structured')]
[hashtable] $Settings,

[Parameter(Mandatory = $true, ParameterSetName = 'Json')]
[Parameter(ParameterSetName = 'Structured')]
[switch] $GitNoVerify,

[Parameter(Mandatory = $true, ParameterSetName = 'Verbatim')]
[string] $InputJson
)

# Place each generated RepoConventions input in a unique temp JSON file.
$inputPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid().ToString('N') + '.json')
$content = if ($PSCmdlet.ParameterSetName -eq 'Settings') {
# Wrap settings in the input shape consumed by convention scripts.
@{ settings = $Settings } | ConvertTo-Json -Depth 10 -Compress
$content = if ($PSCmdlet.ParameterSetName -eq 'Structured') {
# Mirror the input shape RepoConventions produces.
@{ settings = $Settings; git = @{ noVerify = [bool] $GitNoVerify } } | ConvertTo-Json -Depth 10 -Compress
}
else {
# Use caller-supplied JSON verbatim for malformed-input tests.
# Use caller-supplied JSON verbatim for specialized (e.g., malformed) test cases.
$InputJson
}

Expand Down
Loading