| package androidbuild |
| |
| import ( |
| "fmt" |
| "net/http" |
| "strings" |
| "time" |
| |
| androidbuildinternal "go.skia.org/infra/go/androidbuildinternal/v2beta1" |
| "go.skia.org/infra/go/sklog" |
| "go.skia.org/infra/go/vcsinfo" |
| ) |
| |
| // commits is an interface for querying for commits, it is used in Info. |
| type commits interface { |
| // List returns a list of ShortCommit's that match the branch, target and are in a build that is newer than endBuildID. |
| List(branch, target, endBuildID string) (map[string]*vcsinfo.ShortCommit, error) |
| |
| // Get returns a single ShortCommit for the specified branch, target and buildID. |
| Get(branch, target, buildID string) (*vcsinfo.ShortCommit, error) |
| } |
| |
| // androidCommits implements commits. |
| type androidCommits struct { |
| service *androidbuildinternal.Service |
| } |
| |
| // newAndroidCommits creates a new commits. |
| func newAndroidCommits(client *http.Client) (commits, error) { |
| service, err := androidbuildinternal.New(client) |
| if err != nil { |
| return nil, fmt.Errorf("Failed to build commits: %s", err) |
| } |
| |
| return &androidCommits{ |
| service: service, |
| }, nil |
| } |
| |
| // Find all buildIDs with Skia commits from latest build back to endBuildID. |
| // Pass in the empty string for endBuildID if you just want a range of IDs. |
| func (a *androidCommits) List(branch, target, endBuildID string) (map[string]*vcsinfo.ShortCommit, error) { |
| pageToken := "" |
| var err error |
| ret := map[string]*vcsinfo.ShortCommit{} |
| for { |
| pageToken, err = a.findCommitsPage(branch, target, endBuildID, ret, pageToken) |
| if err != nil { |
| return nil, err |
| } |
| // If we aren't looking a specific endpoint then stop when we've gathered |
| // enough commits. |
| if endBuildID == "" && len(ret) > 10 { |
| break |
| } |
| // We've reached the last page when no pageToken is returned. |
| if pageToken == "" { |
| break |
| } |
| } |
| return ret, nil |
| } |
| |
| // findCommitsPage requests a single page of the results and looks for commit info in each build returned. |
| // |
| // New commits are added to ret. |
| // |
| // A page token is returned along with an error. If there are no more pages of data |
| // then the page token is the empty string. |
| func (a *androidCommits) findCommitsPage(branch, target, endBuildID string, ret map[string]*vcsinfo.ShortCommit, pageToken string) (string, error) { |
| // We explicitly don't use exponential backoff since that increases the |
| // likelihood of getting a bad response. |
| for i := 0; i < NUM_RETRIES; i++ { |
| sklog.Infof("Querying for %q %q %q", branch, target, endBuildID) |
| request := a.service.Build.List().Successful(true).BuildType("submitted").Branch(branch).Target(target).ExtraFields("changeInfo").MaxResults(PAGE_SIZE) |
| if pageToken != "" { |
| request.PageToken(pageToken) |
| } |
| if endBuildID != "" { |
| request.EndBuildId(endBuildID) |
| } |
| resp, err := request.Do() |
| if err != nil { |
| sklog.Infof("Call failed: %s", err) |
| time.Sleep(SLEEP_DURATION * time.Second) |
| continue |
| } |
| if len(resp.Builds) == 0 { |
| sklog.Infof("No builds in response.") |
| time.Sleep(SLEEP_DURATION * time.Second) |
| continue |
| } |
| if len(resp.Builds[0].Changes) == 0 { |
| sklog.Infof("No Changes in builds.") |
| time.Sleep(SLEEP_DURATION * time.Second) |
| continue |
| } |
| sklog.Infof("Success after %d attempts.", i+1) |
| |
| for _, buildInfo := range resp.Builds { |
| sklog.Infof("BuildID: %s : %s", buildInfo.BuildId, buildInfo.Target.Name) |
| } |
| |
| for _, build := range resp.Builds { |
| for _, change := range CommitsFromChanges(build.Changes) { |
| ret[build.BuildId] = change |
| } |
| } |
| return resp.NextPageToken, nil |
| } |
| return "", fmt.Errorf("No valid responses from API after %d requests.", NUM_RETRIES) |
| } |
| |
| func CommitsFromChanges(changes []*androidbuildinternal.Change) []*vcsinfo.ShortCommit { |
| ret := []*vcsinfo.ShortCommit{} |
| automated_commit_message := "" |
| for _, changes := range changes { |
| if changes.Project == "platform/external/skia" { |
| for _, revision := range changes.Revisions { |
| authorName := revision.Commit.Author.Name |
| if authorName == "Skia_Android Canary Bot" { |
| automated_commit_message = revision.Commit.CommitMessage |
| } else if strings.Contains(automated_commit_message, revision.GitRevision) { |
| ret = append(ret, &vcsinfo.ShortCommit{ |
| Hash: revision.GitRevision, |
| Author: authorName, |
| Subject: revision.Commit.Subject, |
| }) |
| } |
| } |
| } |
| } |
| return ret |
| } |
| |
| func (a *androidCommits) Get(branch, target, buildID string) (*vcsinfo.ShortCommit, error) { |
| build, err := a.service.Build.Get(buildID, target).ExtraFields("changeInfo").Do() |
| if err != nil { |
| return nil, err |
| } |
| if len(build.Changes) > 1 { |
| changes := CommitsFromChanges(build.Changes) |
| if len(changes) > 1 { |
| return changes[0], nil |
| } |
| } |
| return nil, fmt.Errorf("Didn't find a Skia commit in the response.") |
| } |