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
85 changes: 0 additions & 85 deletions pkg/cli/add_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -565,91 +565,6 @@ func TestEnsureAddRepositoryInitializedWithDetails_AbsolutePaths(t *testing.T) {
require.Equal(t, filepath.Join(repoDir, filepath.FromSlash(writtenMarker)), files[0])
}

func TestConfirmAndInitializeAddRepository(t *testing.T) {
originalFindGitRoot := addFindGitRoot
originalInitRepository := addInitRepository
originalMissingInitMarkers := addMissingInitMarkers
originalConfirmAuthoringSupport := addConfirmAuthoringSupport
t.Cleanup(func() {
addFindGitRoot = originalFindGitRoot
addInitRepository = originalInitRepository
addMissingInitMarkers = originalMissingInitMarkers
addConfirmAuthoringSupport = originalConfirmAuthoringSupport
})

repoDir := t.TempDir()
addFindGitRoot = func() (string, error) { return repoDir, nil }

t.Run("already initialized skips confirmation", func(t *testing.T) {
addMissingInitMarkers = func(string, string) ([]string, error) { return nil, nil }
addConfirmAuthoringSupport = func(context.Context) (bool, error) {
t.Fatal("confirmation should not be shown when all support files exist")
return false, nil
}
addInitRepository = func(InitOptions) error {
t.Fatal("initialization should not run when all support files exist")
return nil
}

files, err := confirmAndInitializeAddRepository(context.Background(), "copilot", false, false)
require.NoError(t, err)
assert.Empty(t, files)
})

t.Run("declining creates no support files", func(t *testing.T) {
addMissingInitMarkers = func(string, string) ([]string, error) {
return []string{bootstrapAgenticSkillPath}, nil
}
addConfirmAuthoringSupport = func(context.Context) (bool, error) { return false, nil }
addInitRepository = func(InitOptions) error {
t.Fatal("initialization should not run after confirmation is declined")
return nil
}

files, err := confirmAndInitializeAddRepository(context.Background(), "copilot", false, false)
require.NoError(t, err)
assert.Empty(t, files)
})

t.Run("accepting quietly initializes support files", func(t *testing.T) {
marker := ".vscode/settings.json"
addMissingInitMarkers = func(string, string) ([]string, error) { return []string{marker}, nil }
addConfirmAuthoringSupport = func(context.Context) (bool, error) { return true, nil }
addInitRepository = func(opts InitOptions) error {
assert.True(t, opts.Quiet)
assert.Equal(t, "copilot", opts.Engine)
path := filepath.Join(repoDir, filepath.FromSlash(marker))
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0755))
return os.WriteFile(path, []byte(`{}`), 0644)
}

files, err := confirmAndInitializeAddRepository(context.Background(), "copilot", false, false)
require.NoError(t, err)
require.Equal(t, []addInitializedFile{{
path: filepath.Join(repoDir, filepath.FromSlash(marker)), displayPath: marker,
}}, files)
})

t.Run("preserves original contents for stale support files", func(t *testing.T) {
marker := ".vscode/settings.json"
markerPath := filepath.Join(repoDir, filepath.FromSlash(marker))
require.NoError(t, os.WriteFile(markerPath, []byte("original"), 0644))
addMissingInitMarkers = func(string, string) ([]string, error) { return []string{marker}, nil }
addConfirmAuthoringSupport = func(context.Context) (bool, error) { return true, nil }
addInitRepository = func(InitOptions) error {
return os.WriteFile(markerPath, []byte("updated"), 0644)
}

plan, err := confirmAddRepositoryInitialization(context.Background(), "copilot", false)
require.NoError(t, err)
files, err := applyAddRepositoryInitialization(plan, "copilot", false, false)
require.NoError(t, err)
require.Equal(t, []addInitializedFile{{
path: markerPath, displayPath: marker, wasExisting: true, originalContent: []byte("original"),
}}, files)
})
}

func TestAddResolvedWorkflows_IgnoresBootstrapRequireOwnerTypeDuringInstall(t *testing.T) {
originalCheckOwnerType := bootstrapCheckOwnerType
t.Cleanup(func() {
Expand Down
8 changes: 0 additions & 8 deletions pkg/cli/add_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,6 @@ func applyAddRepositoryInitialization(plan addRepositoryInitializationPlan, engi
return ensureAddRepositoryInitializedFromPlan(plan.files, engineOverride, verbose, noGitattributes)
}

func confirmAndInitializeAddRepository(ctx context.Context, engineOverride string, verbose bool, noGitattributes bool) ([]addInitializedFile, error) {
plan, err := confirmAddRepositoryInitialization(ctx, engineOverride, noGitattributes)
if err != nil {
return nil, err
}
return applyAddRepositoryInitialization(plan, engineOverride, verbose, noGitattributes)
}

func ensureAddRepositoryInitializedFromPlan(markers []string, engineOverride string, verbose bool, noGitattributes bool) ([]addInitializedFile, error) {
gitRoot, err := addFindGitRoot()
if err != nil {
Expand Down
8 changes: 0 additions & 8 deletions pkg/cli/add_interactive_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,14 +397,6 @@ func (c *AddInteractiveConfig) plannedAddPathsAtRoot(gitRoot string, workflowFil
return planned, nil
}

func inspectAddWorkingTree(plannedPaths []string) (addWorkingTreeBlockers, error) {
gitRoot, err := addFindGitRoot()
if err != nil {
return addWorkingTreeBlockers{}, fmt.Errorf("failed to determine repository root for PR preflight: %w", err)
}
return inspectAddWorkingTreeAtRoot(gitRoot, plannedPaths)
}

func inspectAddWorkingTreeAtRoot(gitRoot string, plannedPaths []string) (addWorkingTreeBlockers, error) {
cmd := exec.Command("git", "status", "--porcelain=v1", "-z", "--untracked-files=all")
cmd.Dir = gitRoot
Expand Down
55 changes: 0 additions & 55 deletions pkg/cli/add_interactive_git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,61 +186,6 @@ func runGitIn(t *testing.T, dir string, args ...string) {
require.NoError(t, err, "git %s failed: %s", strings.Join(args, " "), string(out))
}

func TestInspectAddWorkingTree(t *testing.T) {
tests := []struct {
name string
prepare func(t *testing.T, repoDir string)
plannedPaths []string
wantStaged []string
wantOverlapping []string
}{
{
name: "allows unrelated unstaged and untracked files",
prepare: func(t *testing.T, repoDir string) {
require.NoError(t, os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("changed\n"), 0644))
require.NoError(t, os.WriteFile(filepath.Join(repoDir, "notes.txt"), []byte("notes\n"), 0644))
},
plannedPaths: []string{".github/workflows/new-workflow.md"},
},
{
name: "blocks staged changes",
prepare: func(t *testing.T, repoDir string) {
require.NoError(t, os.WriteFile(filepath.Join(repoDir, "notes.txt"), []byte("notes\n"), 0644))
runGit(t, repoDir, "add", "notes.txt")
},
plannedPaths: []string{".github/workflows/new-workflow.md"},
wantStaged: []string{"notes.txt"},
},
{
name: "blocks unstaged changes to a planned path",
prepare: func(t *testing.T, repoDir string) {
workflowDir := filepath.Join(repoDir, ".github", "workflows")
require.NoError(t, os.MkdirAll(workflowDir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(workflowDir, "new-workflow.md"), []byte("local draft\n"), 0644))
},
plannedPaths: []string{".github/workflows/new-workflow.md"},
wantOverlapping: []string{".github/workflows/new-workflow.md"},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repoDir := t.TempDir()
runGit(t, repoDir, "init", "--initial-branch=main")
require.NoError(t, os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("initial\n"), 0644))
runGit(t, repoDir, "add", "README.md")
runGit(t, repoDir, "commit", "-m", "initial")
t.Chdir(repoDir)
tt.prepare(t, repoDir)

blockers, err := inspectAddWorkingTree(tt.plannedPaths)
require.NoError(t, err)
assert.Equal(t, tt.wantStaged, blockers.staged)
assert.Equal(t, tt.wantOverlapping, blockers.overlapping)
})
}
}

func TestBuildWorkingTreeResolutionOptions(t *testing.T) {
t.Run("offers overwrite first for overlapping unstaged files", func(t *testing.T) {
options := buildWorkingTreeResolutionOptions(true)
Expand Down
7 changes: 0 additions & 7 deletions pkg/cli/add_package_manifest_includes.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,13 +388,6 @@ func isSupportedManifestIncludePath(p string) bool {
return isSupportedPackageInstallablePath(p) || isSupportedSkillDirPath(p) || isSupportedAgentFilePath(p)
}

// isManifestIncludeWildcard reports whether p uses the supported wildcard form: a
// single trailing path segment named "*".
func isManifestIncludeWildcard(p string) bool {
_, ok := manifestIncludeWildcardParent(p)
return ok
}

func manifestIncludeWildcardParent(p string) (string, bool) {
slashed := filepath.ToSlash(p)
if !strings.HasSuffix(slashed, "/*") || strings.Count(slashed, "*") != 1 {
Expand Down
26 changes: 0 additions & 26 deletions pkg/cli/add_package_manifest_wildcard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,6 @@ import (
"github.com/stretchr/testify/require"
)

func TestIsManifestIncludeWildcard(t *testing.T) {
t.Parallel()
tests := []struct {
path string
want bool
}{
{"workflows/*", true},
{"agentic-workflows/*", true},
{".github/workflows/*", true},
{"skills/*", true},
{"*", false},
{"workflows/**", false},
{"workflows/review*.md", false},
{"workflows/*/nested", false},
{"workflows/../agents/*", false},
{"/workflows/*", false},
}

for _, tt := range tests {
t.Run(tt.path, func(t *testing.T) {
t.Parallel()
assert.Equal(t, tt.want, isManifestIncludeWildcard(tt.path))
})
}
}

func TestExtractManifestIncludesWithWildcard(t *testing.T) {
t.Parallel()
includes, warnings, err := extractManifestIncludes([]any{
Expand Down
6 changes: 0 additions & 6 deletions pkg/cli/logs_artifact_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,9 +383,3 @@ func applyGradersArtifact(artifacts []string, gradersOnly bool) []string {
func isEvalsArtifactRequested(evalsOnly bool, artifactSets []string) bool {
return evalsOnly || slices.Contains(artifactSets, string(ArtifactSetEvals))
}

// isGradersArtifactRequested reports whether grader artifacts were explicitly requested,
// either via --graders or by including --artifacts graders.
func isGradersArtifactRequested(gradersOnly bool, artifactSets []string) bool {
return gradersOnly || slices.Contains(artifactSets, string(ArtifactSetGraders))
}
7 changes: 0 additions & 7 deletions pkg/cli/logs_artifact_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,6 @@ func TestApplyGradersArtifact(t *testing.T) {
})
}

func TestIsGradersArtifactRequested(t *testing.T) {
t.Parallel()
assert.True(t, isGradersArtifactRequested(true, nil))
assert.True(t, isGradersArtifactRequested(false, []string{"graders"}))
assert.False(t, isGradersArtifactRequested(false, []string{"usage"}))
}

func TestIsEvalsArtifactRequested(t *testing.T) {
t.Parallel()
tests := []struct {
Expand Down
107 changes: 0 additions & 107 deletions pkg/cli/remote_workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1784,62 +1784,6 @@ safe-outputs:
}
}

// --- extractResources tests ---

// TestExtractResources_BasicList verifies that resource paths are extracted from the resources field.
func TestExtractResources_BasicList(t *testing.T) {
content := `---
engine: copilot
on: issues
resources:
- triage-issue.md
- close-stale.md
- my-action.yml
---

# Workflow
`
resources, err := extractResources(content)
require.NoError(t, err, "should not error for valid resources")
assert.Equal(t, []string{"triage-issue.md", "close-stale.md", "my-action.yml"}, resources, "should extract all listed resources")
}

func TestExtractResources_IncludesGraderEvaluator(t *testing.T) {
content := `---
engine: copilot
on: issues
resources:
- .github/workflows/graders/example-operational-value.sh
graders:
operational-value:
run: .github/workflows/graders/example-operational-value.sh
---

# Workflow
`
resources, err := extractResources(content)
require.NoError(t, err)
assert.Equal(t, []string{".github/workflows/graders/example-operational-value.sh"}, resources)
}

func TestExtractResources_IncludesDisabledGraderEvaluator(t *testing.T) {
content := `---
on: issues
graders:
operational-value:
enabled: false
run: ./graders/example-operational-value.sh
retries:
enabled: true
---

# Workflow
`
resources, err := extractResources(content)
require.NoError(t, err)
assert.Equal(t, []string{"./graders/example-operational-value.sh"}, resources)
}

func TestFetchAndSaveRemoteResources_InstallsAndRestoresGraderEvaluator(t *testing.T) {
tmpDir := t.TempDir()
setupMinimalGitRepo(t, tmpDir)
Expand Down Expand Up @@ -1994,57 +1938,6 @@ graders:
assert.NoFileExists(t, filepath.Join(outsideDir, "example-operational-value.sh"))
}

// TestExtractResources_MacroRejected verifies that an entry with GitHub Actions expression syntax causes an error.
func TestExtractResources_MacroRejected(t *testing.T) {
content := `---
engine: copilot
on: issues
resources:
- plain-workflow.md
- ${{ vars.WORKFLOW }}.md
---

# Workflow
`
resources, err := extractResources(content)
require.Error(t, err, "should error when a resource entry contains macro syntax")
assert.Nil(t, resources, "should return nil resources on error")
require.ErrorContains(t, err, "${{", "error message should mention the disallowed syntax")
}

// TestExtractResources_AllMacrosRejected verifies that all-macro lists return an error.
func TestExtractResources_AllMacrosRejected(t *testing.T) {
content := `---
engine: copilot
on: issues
resources:
- ${{ vars.WORKFLOW_A }}
- ${{ vars.WORKFLOW_B }}
---

# Workflow
`
resources, err := extractResources(content)
require.Error(t, err, "should error when all resources are macros")
assert.Nil(t, resources)
}

// TestExtractResources_NoResourcesField verifies that nil is returned when no resources field.
func TestExtractResources_NoResourcesField(t *testing.T) {
content := `---
engine: copilot
on: issues
---

# Workflow
`
resources, err := extractResources(content)
require.NoError(t, err, "should not error when no resources field")
assert.Empty(t, resources, "should return nil when no resources field")
}

// --- fetchAndSaveRemoteResources tests ---

// TestFetchAndSaveRemoteResources_NoResources verifies that the function is a no-op when the
// workflow has no resources field.
func TestFetchAndSaveRemoteResources_NoResources(t *testing.T) {
Expand Down
13 changes: 0 additions & 13 deletions pkg/cli/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,6 @@ func extractResourceEntries(content string) ([]extractedResource, error) {
return unique, nil
}

// extractResources returns the extracted resource paths in declaration order.
func extractResources(content string) ([]string, error) {
entries, err := extractResourceEntries(content)
if err != nil {
return nil, err
}
paths := make([]string, 0, len(entries))
for _, entry := range entries {
paths = append(paths, entry.path)
}
return paths, nil
}

// fetchAndSaveRemoteResources fetches files listed in the top-level "resources" frontmatter
// field from the same remote repository and saves them locally. Resources are resolved as
// relative paths from the same directory as the source workflow in the remote repo.
Expand Down
Loading