Skip to content
2 changes: 1 addition & 1 deletion cmd/kosli/assertPRGithub.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func newAssertPullRequestGithubCmd(out io.Writer) *cobra.Command {
}

func (o *assertPullRequestGithubOptions) run(args []string) error {
pullRequestsEvidence, err := o.retriever.PREvidenceForCommitV2(o.commit)
pullRequestsEvidence, err := o.retriever.PREvidenceForCommitHybrid(o.commit)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/kosli/pullrequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (o *attestPROptions) run(args []string) error {
o.payload.GitProvider, label = o.getRetriever().ProviderAndLabel()

var pullRequestsEvidence []*types.PREvidence
pullRequestsEvidence, err = o.getRetriever().PREvidenceForCommitV2(o.payload.Commit.Sha1)
pullRequestsEvidence, err = o.getRetriever().PREvidenceForCommitHybrid(o.payload.Commit.Sha1)
if err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions internal/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ func (c *AzureConfig) PREvidenceForCommitV1(commit string) ([]*types.PREvidence,
return pullRequestsEvidence, nil
}

func (c *AzureConfig) PREvidenceForCommitHybrid(commit string) ([]*types.PREvidence, error) {
return c.PREvidenceForCommitV2(commit)
}

// This is the new implementation, it will be used for Azure
func (c *AzureConfig) PREvidenceForCommitV2(commit string) ([]*types.PREvidence, error) {
pullRequestsEvidence := []*types.PREvidence{}
Expand Down
4 changes: 4 additions & 0 deletions internal/bitbucket/bitbucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func (c *Config) PREvidenceForCommitV1(commit string) ([]*types.PREvidence, erro
return c.getPullRequestsFromBitbucketApi(commit, 1)
}

func (c *Config) PREvidenceForCommitHybrid(commit string) ([]*types.PREvidence, error) {
return c.PREvidenceForCommitV2(commit)
}

// This is the new implementation, it will be used for Bitbucket
func (c *Config) PREvidenceForCommitV2(commit string) ([]*types.PREvidence, error) {
return c.getPullRequestsFromBitbucketApi(commit, 2)
Expand Down
50 changes: 50 additions & 0 deletions internal/github/fake_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ var errInjected = errors.New("injected error")

// FakeGitHubClient is an in-memory implementation of types.PRRetriever for
// testing. Seed PRsByCommit with the commits and PR evidence you want returned.
// Seed PRsByNumber with PR numbers and their evidence for PREvidenceByPRNumber.
// Seed PRNumbersByCommit + PRsByNumber to exercise the hybrid fallback path
// (V2 empty → V1 discovery → per-PR GraphQL).
// Set Err to simulate a network or API failure.
type FakeGitHubClient struct {
// PRsByCommit maps a commit SHA to the PR evidence returned for that commit.
PRsByCommit map[string][]*types.PREvidence
// PRsByNumber maps a PR number to the PR evidence returned for that number.
PRsByNumber map[int]*types.PREvidence
// PRNumbersByCommit maps a commit SHA to PR numbers for the hybrid fallback path.
PRNumbersByCommit map[string][]int
// Err, if set, is returned by all calls regardless of commit.
Err error
}
Expand All @@ -38,6 +45,49 @@ func (f *FakeGitHubClient) PREvidenceForCommitV1(commit string) ([]*types.PREvid
return prs, nil
}

// PREvidenceForCommitHybrid mirrors the hybrid strategy: tries V2 (PRsByCommit)
// first; if empty, falls back through PRNumbersByCommit + PREvidenceByPRNumber.
// Returns empty (no error) when the commit is not found in either map.
func (f *FakeGitHubClient) PREvidenceForCommitHybrid(commit string) ([]*types.PREvidence, error) {
if f.Err != nil {
return nil, f.Err
}
prs, err := f.PREvidenceForCommitV2(commit)
if err != nil {
return nil, err
}
if len(prs) > 0 {
return prs, nil
}
// Fallback: use PRNumbersByCommit for V1-style discovery.
prNumbers := f.PRNumbersByCommit[commit]
result := []*types.PREvidence{}
for _, n := range prNumbers {
evidence, err := f.PREvidenceByPRNumber(n)
if err != nil {
return nil, err
}
if evidence != nil {
result = append(result, evidence)
}
}
return result, nil
}

// PREvidenceByPRNumber mirrors the GraphQL API: returns an error for PR numbers
// not present in PRsByNumber (matching the real GitHub behaviour of returning
// an error for non-existent pull requests).
func (f *FakeGitHubClient) PREvidenceByPRNumber(prNumber int) (*types.PREvidence, error) {
if f.Err != nil {
return nil, f.Err
}
pr, ok := f.PRsByNumber[prNumber]
if !ok {
return nil, fmt.Errorf("could not resolve to a pull request with number %d", prNumber)
}
return pr, nil
}

// PREvidenceForCommitV2 mirrors the GraphQL API: returns empty with no error
// for commits not present in PRsByCommit (matching the real GitHub V2 behaviour
// of returning null for unknown commits).
Expand Down
Loading
Loading