Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
12 changes: 12 additions & 0 deletions pkg/workflow/pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package workflow

import (
"fmt"
"path/filepath"
"sort"
"strings"

Expand All @@ -21,6 +22,17 @@ func ShouldGeneratePRCheckoutStep(data *WorkflowData) bool {
if data.CheckoutDisabled || data.IsPullRequestTarget {
return false
}
// checkout_pr_branch and the subsequent base-folder restore operate on the
// workspace root, so neither may run when it belongs to another repository.
for _, checkout := range data.CheckoutConfigs {
if checkout == nil || (filepath.Clean(checkout.Path) != "." && !strings.Contains(checkout.Path, "${{")) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added a ContainsCheckout guard in pkg/workflow/pr.go and a compile regression confirming both generated steps are omitted for an external custom checkout. The affected lockfiles were recompiled. Commit: 38ae3bb.

continue
}
repository := strings.TrimSpace(checkout.Repository)
if checkout.Wiki || (repository != "" && repository != "${{ github.repository }}") {
return false
}
}
if data.CachedPermissions != nil {
return data.CachedPermissions.HasContentsReadAccess()
}
Expand Down
102 changes: 102 additions & 0 deletions pkg/workflow/pr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
package workflow

import (
"os"
"path/filepath"
"strings"
"testing"

Expand Down Expand Up @@ -106,6 +108,106 @@ func TestShouldGeneratePRCheckoutStep_CheckoutDisabled(t *testing.T) {
})
}

func TestShouldGeneratePRCheckoutStep_MultiCheckout(t *testing.T) {
tests := []struct {
name string
checkouts []*CheckoutConfig
want bool
}{
{
name: "external repository at root and workflow repository in subpath",
checkouts: []*CheckoutConfig{
{Repository: "${{ inputs.target_repo }}", Path: "."},
{Repository: "${{ github.repository }}", Path: "target"},
},
},
{
name: "literal external repository at root",
checkouts: []*CheckoutConfig{
{Repository: "other/project", Path: ".", PathExplicit: true},
},
},
{
name: "wiki repository at root",
checkouts: []*CheckoutConfig{
{Repository: "${{ github.repository }}", Wiki: true},
},
},
{
name: "workflow repository at root and external repository in subpath",
checkouts: []*CheckoutConfig{
{Repository: "${{ github.repository }}", Path: "."},
{Repository: "other/project", Path: "target"},
},
want: true,
},
{
name: "implicit workflow repository at root",
checkouts: []*CheckoutConfig{
{Path: "."},
{Repository: "other/project", Path: "target"},
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
data := &WorkflowData{Permissions: "contents: read", CheckoutConfigs: tt.checkouts}
assert.Equal(t, tt.want, ShouldGeneratePRCheckoutStep(data))
})
}
}

func TestPRCheckoutRestoreWithMultiCheckout(t *testing.T) {
for _, tt := range []struct {
name string
rootRepo string
wantPRStep bool
}{
{name: "target repository at root", rootRepo: "${{ inputs.target_repo }}"},
{name: "workflow repository at root", rootRepo: "${{ github.repository }}", wantPRStep: true},
} {
t.Run(tt.name, func(t *testing.T) {
dir := t.TempDir()
source := `---
on:
workflow_dispatch:
inputs:
target_repo:
type: string
required: true
permissions:
contents: read
checkout:
- repository: ` + tt.rootRepo + `
path: .
- repository: ${{ github.repository }}
path: target
strict: false
---
Test workflow.
`
path := filepath.Join(dir, "test.md")
if err := os.WriteFile(path, []byte(source), 0644); err != nil {
t.Fatal(err)
}
if err := NewCompiler().CompileWorkflow(path); err != nil {
t.Fatal(err)
}
lock, err := os.ReadFile(filepath.Join(dir, "test.lock.yml"))
if err != nil {
t.Fatal(err)
}
for _, step := range []string{
"- name: Checkout PR branch",
"- name: Restore agent config folders from base branch",
} {
assert.Equal(t, tt.wantPRStep, strings.Contains(string(lock), step), step)
}
})
}
}

func TestResolveAgentManifestPaths(t *testing.T) {
t.Run("includes defaults and only the selected engine", func(t *testing.T) {
folders, files := resolveAgentManifestPaths(NewEngineRegistry(), &WorkflowData{
Expand Down
Loading