You've already forked woodpecker
mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-11-23 21:44:44 +02:00
Switch to GitHub REST API to load changed files (#5618)
Co-authored-by: 6543 <6543@obermui.de> ``` // GitHub has removed commit summaries from Events API payloads from 7th October 2025 onwards. ``` - switch to rest api to load changed files - added some small wording/var name adjustment - added test cases using GitHub mock client
This commit is contained in:
@@ -27,7 +27,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-github/v74/github"
|
||||
"github.com/google/go-github/v75/github"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
@@ -40,9 +40,12 @@ import (
|
||||
"go.woodpecker-ci.org/woodpecker/v3/shared/utils"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const (
|
||||
defaultURL = "https://github.com" // Default GitHub URL
|
||||
defaultAPI = "https://api.github.com/" // Default GitHub API URL
|
||||
defaultURL = "https://github.com" // Default GitHub URL
|
||||
defaultAPI = "https://api.github.com/" // Default GitHub API URL
|
||||
githubClientKey contextKey = "github_client"
|
||||
)
|
||||
|
||||
// Opts defines configuration options.
|
||||
@@ -459,7 +462,13 @@ func (c *client) newConfig() *oauth2.Config {
|
||||
}
|
||||
|
||||
// newClientToken returns the GitHub oauth2 client.
|
||||
// It first checks if a client is available in the context, otherwise creates a new one.
|
||||
func (c *client) newClientToken(ctx context.Context, token string) *github.Client {
|
||||
// Check if a client is already in the context
|
||||
if ctxClient, ok := ctx.Value(githubClientKey).(*github.Client); ok {
|
||||
return ctxClient
|
||||
}
|
||||
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: token},
|
||||
)
|
||||
@@ -606,7 +615,7 @@ func (c *client) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b
|
||||
// Hook parses the post-commit hook from the Request body
|
||||
// and returns the required data in a standard format.
|
||||
func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) {
|
||||
pull, repo, pipeline, err := parseHook(r, c.MergeRef)
|
||||
pull, repo, pipeline, currCommit, prevCommit, err := parseHook(r, c.MergeRef)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -620,11 +629,17 @@ func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model
|
||||
pipeline.Commit = sha
|
||||
}
|
||||
|
||||
if pull != nil && len(pipeline.ChangedFiles) == 0 {
|
||||
if pull != nil {
|
||||
pipeline, err = c.loadChangedFilesFromPullRequest(ctx, pull, repo, pipeline)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else if pipeline.Event == model.EventPush {
|
||||
// GitHub has removed commit summaries from Events API payloads from 7th October 2025 onwards.
|
||||
pipeline, err = c.loadChangedFilesFromCommits(ctx, repo, pipeline, prevCommit, currCommit)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return repo, pipeline, nil
|
||||
@@ -647,24 +662,24 @@ func (c *client) loadChangedFilesFromPullRequest(ctx context.Context, pull *gith
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipeline.ChangedFiles, err = utils.Paginate(func(page int) ([]string, error) {
|
||||
opts := &github.ListOptions{Page: page}
|
||||
fileList := make([]string, 0, 16)
|
||||
for opts.Page > 0 {
|
||||
files, resp, err := c.newClientToken(ctx, user.AccessToken).PullRequests.ListFiles(ctx, repo.Owner, repo.Name, pull.GetNumber(), opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gh := c.newClientToken(ctx, user.AccessToken)
|
||||
fileList := make([]string, 0, 16)
|
||||
|
||||
for _, file := range files {
|
||||
fileList = append(fileList, file.GetFilename(), file.GetPreviousFilename())
|
||||
}
|
||||
|
||||
opts.Page = resp.NextPage
|
||||
opts := &github.ListOptions{Page: 1}
|
||||
for opts.Page > 0 {
|
||||
files, resp, err := gh.PullRequests.ListFiles(ctx, repo.Owner, repo.Name, pull.GetNumber(), opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return utils.DeduplicateStrings(fileList), nil
|
||||
}, -1)
|
||||
|
||||
for _, file := range files {
|
||||
fileList = append(fileList, file.GetFilename(), file.GetPreviousFilename())
|
||||
}
|
||||
|
||||
opts.Page = resp.NextPage
|
||||
}
|
||||
|
||||
pipeline.ChangedFiles = utils.DeduplicateStrings(fileList)
|
||||
return pipeline, err
|
||||
}
|
||||
|
||||
@@ -710,3 +725,65 @@ func (c *client) getTagCommitSHA(ctx context.Context, repo *model.Repo, tagName
|
||||
}
|
||||
return tag.GetCommit().GetSHA(), nil
|
||||
}
|
||||
|
||||
func (c *client) loadChangedFilesFromCommits(ctx context.Context, tmpRepo *model.Repo, pipeline *model.Pipeline, curr, prev string) (*model.Pipeline, error) {
|
||||
_store, ok := store.TryFromContext(ctx)
|
||||
if !ok {
|
||||
log.Error().Msg("could not get store from context")
|
||||
return pipeline, nil
|
||||
}
|
||||
|
||||
switch prev {
|
||||
case curr:
|
||||
log.Error().Msg("GitHub push event contains the same commit before and after, no changes detected")
|
||||
return pipeline, nil
|
||||
case "0000000000000000000000000000000000000000":
|
||||
prev = ""
|
||||
fallthrough
|
||||
case "":
|
||||
// For tag events, prev is empty, but we can still fetch the changed files using the current commit
|
||||
log.Trace().Msg("GitHub tag event, fetching changed files using current commit")
|
||||
}
|
||||
|
||||
repo, err := _store.GetRepoNameFallback(tmpRepo.ForgeRemoteID, tmpRepo.FullName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, err := _store.GetUser(repo.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gh := c.newClientToken(ctx, user.AccessToken)
|
||||
fileList := make([]string, 0, 16)
|
||||
|
||||
if prev == "" {
|
||||
opts := &github.ListOptions{Page: 1}
|
||||
for opts.Page > 0 {
|
||||
commit, resp, err := gh.Repositories.GetCommit(ctx, repo.Owner, repo.Name, curr, &github.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, file := range commit.Files {
|
||||
fileList = append(fileList, file.GetFilename(), file.GetPreviousFilename())
|
||||
}
|
||||
opts.Page = resp.NextPage
|
||||
}
|
||||
} else {
|
||||
opts := &github.ListOptions{Page: 1}
|
||||
for opts.Page > 0 {
|
||||
comp, resp, err := gh.Repositories.CompareCommits(ctx, repo.Owner, repo.Name, prev, curr, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, file := range comp.Files {
|
||||
fileList = append(fileList, file.GetFilename(), file.GetPreviousFilename())
|
||||
}
|
||||
opts.Page = resp.NextPage
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.ChangedFiles = utils.DeduplicateStrings(fileList)
|
||||
return pipeline, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user