| // Copyright 2020 Google Inc. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package controllers | |
| import ( | |
| "context" | |
| "encoding/json" | |
| "fmt" | |
| "net/http" | |
| "os" | |
| "strconv" | |
| "strings" | |
| "text/template" | |
| secretmanager "cloud.google.com/go/secretmanager/apiv1" | |
| "cos.googlesource.com/cos/tools.git/src/pkg/changelog" | |
| "cos.googlesource.com/cos/tools.git/src/pkg/findbuild" | |
| "cos.googlesource.com/cos/tools.git/src/pkg/utils" | |
| log "github.com/sirupsen/logrus" | |
| ) | |
| const ( | |
| subjectLen int = 100 | |
| ) | |
| var ( | |
| internalGerritInstance string | |
| internalFallbackGerritInstance string | |
| internalGoBInstance string | |
| internalManifestRepo string | |
| croslandURL string | |
| externalGerritInstance string | |
| externalFallbackGerritInstance string | |
| externalGoBInstance string | |
| externalManifestRepo string | |
| envQuerySize string | |
| envBoard string | |
| artifactsBucket string | |
| staticBasePath string | |
| indexTemplate *template.Template | |
| readme *template.Template | |
| changelogTemplate *template.Template | |
| promptLoginTemplate *template.Template | |
| findBuildTemplate *template.Template | |
| findReleasedBuildTemplate *template.Template | |
| statusForbiddenTemplate *template.Template | |
| basicTextTemplate *template.Template | |
| ) | |
| func init() { | |
| var err error | |
| client, err := secretmanager.NewClient(context.Background()) | |
| if err != nil { | |
| log.Fatalf("Failed to setup client: %v", err) | |
| } | |
| internalGerritInstance, err = getSecret(client, os.Getenv("COS_INTERNAL_GERRIT_INSTANCE_NAME")) | |
| if err != nil { | |
| log.Fatalf("Failed to retrieve secret for COS_INTERNAL_GERRIT_INSTANCE_NAME with key name %s\n%v", os.Getenv("COS_INTERNAL_GERRIT_INSTANCE_NAME"), err) | |
| } | |
| internalFallbackGerritInstance, err = getSecret(client, os.Getenv("COS_INTERNAL_FALLBACK_GERRIT_INSTANCE_NAME")) | |
| if err != nil { | |
| log.Fatalf("Failed to retrieve secret for COS_INTERNAL_FALLBACK_GERRIT_INSTANCE_NAME with key name %s\n%v", os.Getenv("COS_INTERNAL_FALLBACK_GERRIT_INSTANCE_NAME"), err) | |
| } | |
| internalGoBInstance, err = getSecret(client, os.Getenv("COS_INTERNAL_GOB_INSTANCE_NAME")) | |
| if err != nil { | |
| log.Fatalf("Failed to retrieve secret for COS_INTERNAL_GOB_INSTANCE_NAME with key name %s\n%v", os.Getenv("COS_INTERNAL_GOB_INSTANCE_NAME"), err) | |
| } | |
| internalManifestRepo, err = getSecret(client, os.Getenv("COS_INTERNAL_MANIFEST_REPO_NAME")) | |
| if err != nil { | |
| log.Fatalf("Failed to retrieve secret for COS_INTERNAL_MANIFEST_REPO_NAME with key name %s\n%v", os.Getenv("COS_INTERNAL_MANIFEST_REPO_NAME"), err) | |
| } | |
| croslandURL, err = getSecret(client, os.Getenv("CROSLAND_NAME")) | |
| if err != nil { | |
| log.Fatalf("Failed to retrieve secret for CROSLAND_NAME with key name %s\n%v", os.Getenv("CROSLAND_NAME"), err) | |
| } | |
| artifactsBucket, err = getSecret(client, os.Getenv("COS_CHANGELOG_ARTIFACTS_BUCKET_NAME")) | |
| if err != nil { | |
| log.Fatalf("Failed to retrieve secret for COS_CHANGELOG_ARTIFACTS_BUCKET_NAME with key name %s\n%v", os.Getenv("COS_CHANGELOG_ARTIFACTS_BUCKET_NAME"), err) | |
| } | |
| externalGerritInstance = os.Getenv("COS_EXTERNAL_GERRIT_INSTANCE") | |
| externalFallbackGerritInstance = os.Getenv("COS_EXTERNAL_FALLBACK_GERRIT_INSTANCE") | |
| externalGoBInstance = os.Getenv("COS_EXTERNAL_GOB_INSTANCE") | |
| externalManifestRepo = os.Getenv("COS_EXTERNAL_MANIFEST_REPO") | |
| envBoard = os.Getenv("BOARD_NAME") | |
| envQuerySize = getIntVerifiedEnv("CHANGELOG_QUERY_SIZE") | |
| staticBasePath = os.Getenv("STATIC_BASE_PATH") | |
| indexTemplate = template.Must(template.ParseFiles(staticBasePath + "templates/index.html")) | |
| readme = template.Must(template.ParseFiles(staticBasePath + "templates/readme.html")) | |
| changelogTemplate = template.Must(template.ParseFiles(staticBasePath + "templates/changelog.html")) | |
| findBuildTemplate = template.Must(template.ParseFiles(staticBasePath + "templates/findBuild.html")) | |
| findReleasedBuildTemplate = template.Must(template.ParseFiles(staticBasePath + "templates/findReleasedBuild.html")) | |
| promptLoginTemplate = template.Must(template.ParseFiles(staticBasePath + "templates/promptLogin.html")) | |
| basicTextTemplate = template.Must(template.ParseFiles(staticBasePath + "templates/error.html")) | |
| } | |
| type changelogData struct { | |
| Source string | |
| Target string | |
| Additions map[string]*changelog.RepoLog | |
| Removals map[string]*changelog.RepoLog | |
| Internal bool | |
| } | |
| type changelogPage struct { | |
| Source string | |
| Target string | |
| SourceBoard string | |
| SourceMilestone string | |
| TargetBoard string | |
| TargetMilestone string | |
| QuerySize string | |
| RepoTables []*repoTable | |
| Internal bool | |
| Sysctl sysctlChanges | |
| } | |
| type sysctlChanges struct { | |
| Changes [][]string | |
| NotFound string | |
| NotEmpty bool | |
| } | |
| type findBuildPage struct { | |
| CL string | |
| CLNum string | |
| BuildNum string | |
| GerritLink string | |
| Internal bool | |
| } | |
| type statusPage struct { | |
| ActivePage string | |
| SignedIn bool | |
| } | |
| type basicTextPage struct { | |
| Header string | |
| Body string | |
| ActivePage string | |
| SignedIn bool | |
| } | |
| type repoTable struct { | |
| Name string | |
| Additions []*repoTableEntry | |
| Removals []*repoTableEntry | |
| AdditionsLink string | |
| RemovalsLink string | |
| } | |
| type repoTableEntry struct { | |
| IsAddition bool | |
| SHA *shaAttr | |
| Subject string | |
| Bugs []*bugAttr | |
| AuthorName string | |
| CommitterName string | |
| CommitTime string | |
| ReleaseNote string | |
| } | |
| type shaAttr struct { | |
| Name string | |
| URL string | |
| } | |
| type bugAttr struct { | |
| Name string | |
| URL string | |
| } | |
| // getIntVerifiedEnv retrieves an environment variable but checks that it can be | |
| // converted to int first | |
| func getIntVerifiedEnv(envName string) string { | |
| output := os.Getenv(envName) | |
| if _, err := strconv.Atoi(output); err != nil { | |
| log.Errorf("failed to parse env variable %s with value %s: %v", | |
| envName, os.Getenv(output), err) | |
| } | |
| return output | |
| } | |
| func gobCommitLink(instance, repo, SHA string) string { | |
| return fmt.Sprintf("https://%s/%s/+/%s", instance, repo, SHA) | |
| } | |
| func gobDiffLink(instance, repo, sourceSHA, targetSHA string, diffLink bool) string { | |
| if !diffLink { | |
| return fmt.Sprintf("https://%s/%s/+log/%s?n=10000", instance, repo, targetSHA) | |
| } | |
| return fmt.Sprintf("https://%s/%s/+log/%s..%s?n=10000", instance, repo, sourceSHA, targetSHA) | |
| } | |
| func createRepoTableEntry(instance, repo string, commit *changelog.Commit, isAddition bool) *repoTableEntry { | |
| entry := new(repoTableEntry) | |
| entry.IsAddition = isAddition | |
| entry.SHA = &shaAttr{Name: commit.SHA[:8], URL: gobCommitLink(instance, repo, commit.SHA)} | |
| entry.Subject = commit.Subject | |
| if len(entry.Subject) > subjectLen { | |
| entry.Subject = entry.Subject[:subjectLen] | |
| } | |
| entry.Bugs = make([]*bugAttr, len(commit.Bugs)) | |
| for i, bugURL := range commit.Bugs { | |
| name := bugURL[strings.Index(bugURL, "/")+1:] | |
| entry.Bugs[i] = &bugAttr{Name: name, URL: "http://" + bugURL} | |
| } | |
| entry.AuthorName = commit.AuthorName | |
| entry.CommitterName = commit.CommitterName | |
| entry.CommitTime = commit.CommitTime | |
| entry.ReleaseNote = commit.ReleaseNote | |
| return entry | |
| } | |
| func createChangelogPage(data changelogData) *changelogPage { | |
| page := &changelogPage{Source: data.Source, Target: data.Target, QuerySize: envQuerySize, Internal: data.Internal} | |
| for repoPath, addLog := range data.Additions { | |
| diffLink := false | |
| table := &repoTable{Name: repoPath} | |
| for _, commit := range addLog.Commits { | |
| tableEntry := createRepoTableEntry(addLog.InstanceURL, addLog.Repo, commit, true) | |
| table.Additions = append(table.Additions, tableEntry) | |
| } | |
| if rmLog, ok := data.Removals[repoPath]; ok { | |
| for _, commit := range data.Removals[repoPath].Commits { | |
| tableEntry := createRepoTableEntry(rmLog.InstanceURL, rmLog.Repo, commit, false) | |
| table.Removals = append(table.Removals, tableEntry) | |
| } | |
| if data.Removals[repoPath].HasMoreCommits { | |
| diffLink = addLog.Repo == rmLog.Repo | |
| table.RemovalsLink = gobDiffLink(rmLog.InstanceURL, rmLog.Repo, addLog.TargetSHA, rmLog.TargetSHA, diffLink) | |
| } | |
| } | |
| if addLog.HasMoreCommits { | |
| table.AdditionsLink = gobDiffLink(addLog.InstanceURL, addLog.Repo, addLog.SourceSHA, addLog.TargetSHA, diffLink) | |
| } | |
| page.RepoTables = append(page.RepoTables, table) | |
| } | |
| // Add remaining repos that had removals but no additions | |
| for repoPath, repoLog := range data.Removals { | |
| if _, ok := data.Additions[repoPath]; ok { | |
| continue | |
| } | |
| table := &repoTable{Name: repoPath} | |
| for _, commit := range repoLog.Commits { | |
| tableEntry := createRepoTableEntry(repoLog.InstanceURL, repoLog.Repo, commit, false) | |
| table.Removals = append(table.Removals, tableEntry) | |
| } | |
| page.RepoTables = append(page.RepoTables, table) | |
| if repoLog.HasMoreCommits { | |
| table.RemovalsLink = gobDiffLink(repoLog.InstanceURL, repoLog.Repo, repoLog.SourceSHA, repoLog.TargetSHA, false) | |
| } | |
| } | |
| return page | |
| } | |
| func findBuildWithFallback(httpClient *http.Client, gerrit, fallbackGerrit, gob, repo, cl string, internal bool) (*findbuild.BuildResponse, bool, utils.ChangelogError) { | |
| didFallback := false | |
| request := &findbuild.BuildRequest{ | |
| HTTPClient: httpClient, | |
| GerritHost: gerrit, | |
| GitilesHost: gob, | |
| ManifestRepo: repo, | |
| CL: cl, | |
| } | |
| buildData, err := findbuild.FindBuild(request) | |
| if err != nil && err.HTTPCode() == "404" { | |
| log.Debugf("Cl %s not found in Gerrit instance, using fallback", cl) | |
| fallbackRequest := &findbuild.BuildRequest{ | |
| HTTPClient: httpClient, | |
| GerritHost: fallbackGerrit, | |
| GitilesHost: gob, | |
| ManifestRepo: repo, | |
| CL: cl, | |
| } | |
| buildData, err = findbuild.FindBuild(fallbackRequest) | |
| didFallback = true | |
| } | |
| return buildData, didFallback, err | |
| } | |
| func findReleaseBuild(httpClient *http.Client, gerrit, gob, repo, cl string, internal bool) (*findbuild.BuildResponse, utils.ChangelogError) { | |
| request := &findbuild.BuildRequest{ | |
| HTTPClient: httpClient, | |
| GerritHost: gerrit, | |
| GitilesHost: gob, | |
| ManifestRepo: repo, | |
| CL: cl, | |
| } | |
| buildData, err := findbuild.FindReleasedBuild(request) | |
| if err != nil && err.HTTPCode() == "404" { | |
| log.Debugf("Cl %s not found in Gerrit instance", cl) | |
| } | |
| return buildData, err | |
| } | |
| // handleError creates the error page for a given error | |
| func handleError(w http.ResponseWriter, r *http.Request, displayErr utils.ChangelogError, currPage string) { | |
| err := basicTextTemplate.Execute(w, &basicTextPage{ | |
| Header: displayErr.Header(), | |
| Body: displayErr.HTMLError(), | |
| ActivePage: currPage, | |
| SignedIn: SignedIn(r), | |
| }) | |
| if err != nil { | |
| log.Error(err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| } | |
| // HandleIndex serves the home page | |
| func HandleIndex(w http.ResponseWriter, r *http.Request) { | |
| err := indexTemplate.Execute(w, &statusPage{SignedIn: SignedIn(r)}) | |
| if err != nil { | |
| log.Error(err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| } | |
| // HandleReadme serves the about page | |
| func HandleReadme(w http.ResponseWriter, r *http.Request) { | |
| err := readme.Execute(w, &statusPage{SignedIn: SignedIn(r)}) | |
| if err != nil { | |
| log.Error(err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| } | |
| // HandleChangelog serves the changelog page | |
| func HandleChangelog(w http.ResponseWriter, r *http.Request) { | |
| if RequireToken(w, r, "/changelog/") { | |
| return | |
| } | |
| var err error | |
| if err := r.ParseForm(); err != nil { | |
| err = changelogTemplate.Execute(w, &changelogPage{QuerySize: envQuerySize}) | |
| if err != nil { | |
| log.Errorf("error executing findbuild template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| return | |
| } | |
| source := r.FormValue("source") | |
| target := r.FormValue("target") | |
| sourceMilestone := r.FormValue("source-milestone") | |
| targetMilestone := r.FormValue("target-milestone") | |
| sourceBoard := r.FormValue("source-board") | |
| if sourceBoard == "" { | |
| sourceBoard = envBoard | |
| } | |
| targetBoard := r.FormValue("target-board") | |
| if targetBoard == "" { | |
| targetBoard = envBoard | |
| } | |
| // If no source/target values specified in request, display empty changelog page | |
| if source == "" || target == "" { | |
| err = changelogTemplate.Execute(w, &changelogPage{QuerySize: envQuerySize, Internal: true}) | |
| if err != nil { | |
| log.Errorf("error executing findbuild template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| return | |
| } | |
| querySize, err := strconv.Atoi(r.FormValue("n")) | |
| if err != nil { | |
| querySize, _ = strconv.Atoi(envQuerySize) | |
| } | |
| internal, instance, manifestRepo := false, externalGoBInstance, externalManifestRepo | |
| if r.FormValue("internal") == "true" { | |
| internal, instance, manifestRepo = true, internalGoBInstance, internalManifestRepo | |
| } | |
| httpClient, err := HTTPClient(w, r) | |
| if err != nil { | |
| loginURL := GetLoginURL("/changelog/", false) | |
| http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect) | |
| return | |
| } | |
| added, removed, utilErr := changelog.Changelog(httpClient, source, target, instance, manifestRepo, croslandURL, querySize) | |
| if utilErr != nil { | |
| log.Errorf("error retrieving changelog between builds %s and %s on GoB instance: %s with manifest repository: %s\n%v\n", | |
| source, target, externalGoBInstance, externalManifestRepo, utilErr) | |
| handleError(w, r, utilErr, "/changelog/") | |
| return | |
| } | |
| page := createChangelogPage(changelogData{ | |
| Source: source, | |
| Target: target, | |
| Additions: added, | |
| Removals: removed, | |
| Internal: internal, | |
| }) | |
| page.SourceMilestone = sourceMilestone | |
| page.SourceBoard = sourceBoard | |
| page.TargetMilestone = targetMilestone | |
| page.TargetBoard = targetBoard | |
| var foundSource, foundTarget bool | |
| page.Sysctl.Changes, foundSource, foundTarget = changelog.GetSysctlDiff(artifactsBucket, sourceBoard, | |
| sourceMilestone, source, targetBoard, targetMilestone, target) | |
| page.Sysctl.NotEmpty = false | |
| if !foundSource { | |
| page.Sysctl.NotFound += fmt.Sprintf("sysctl file for %s-%s-%s not found.<br>", sourceBoard, sourceMilestone, source) | |
| page.Sysctl.NotEmpty = true | |
| } | |
| if !foundTarget { | |
| page.Sysctl.NotFound += fmt.Sprintf("sysctl file for %s-%s-%s not found.<br>", targetBoard, targetMilestone, target) | |
| page.Sysctl.NotEmpty = true | |
| } | |
| if len(page.Sysctl.Changes) > 0 { | |
| page.Sysctl.NotEmpty = true | |
| } | |
| err = changelogTemplate.Execute(w, page) | |
| if err != nil { | |
| log.Errorf("error executing changelog template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| } | |
| // HandleFindBuild serves the Locate CL page | |
| func HandleFindBuild(w http.ResponseWriter, r *http.Request) { | |
| if RequireToken(w, r, "/findbuild/") { | |
| return | |
| } | |
| var err error | |
| if err = r.ParseForm(); err != nil { | |
| err = findBuildTemplate.Execute(w, &findBuildPage{Internal: true}) | |
| if err != nil { | |
| log.Errorf("error executing findbuild template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| return | |
| } | |
| cl := r.FormValue("cl") | |
| // If no CL value specified in request, display empty CL form | |
| if cl == "" { | |
| err = findBuildTemplate.Execute(w, &findBuildPage{Internal: true}) | |
| if err != nil { | |
| log.Errorf("error executing findbuild template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| return | |
| } | |
| internal, gerrit, fallbackGerrit, gob, repo := false, externalGerritInstance, externalFallbackGerritInstance, externalGoBInstance, externalManifestRepo | |
| if r.FormValue("cos-internal") == "true" { | |
| internal, gerrit, fallbackGerrit, gob, repo = true, internalGerritInstance, internalFallbackGerritInstance, internalGoBInstance, internalManifestRepo | |
| } | |
| httpClient, err := HTTPClient(w, r) | |
| if err != nil { | |
| loginURL := GetLoginURL("/findbuild/", false) | |
| http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect) | |
| return | |
| } | |
| buildData, didFallback, utilErr := findBuildWithFallback(httpClient, gerrit, fallbackGerrit, gob, repo, cl, internal) | |
| if utilErr != nil { | |
| log.Errorf("error retrieving build for CL %s with internal set to %t\n%v", cl, internal, utilErr) | |
| handleError(w, r, utilErr, "/findbuild/") | |
| return | |
| } | |
| var gerritLink string | |
| if didFallback { | |
| gerritLink = fallbackGerrit + "/c/" + buildData.CLNum | |
| } else { | |
| gerritLink = gerrit + "/c/" + buildData.CLNum | |
| } | |
| page := &findBuildPage{ | |
| CL: cl, | |
| CLNum: buildData.CLNum, | |
| BuildNum: buildData.BuildNum, | |
| Internal: internal, | |
| GerritLink: gerritLink, | |
| } | |
| err = findBuildTemplate.Execute(w, page) | |
| if err != nil { | |
| log.Errorf("error executing findbuild template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| } | |
| // HandleFindReleasedBuild serves the Locate CL page | |
| func HandleFindReleasedBuild(w http.ResponseWriter, r *http.Request) { | |
| if RequireToken(w, r, "/findreleasedbuild/") { // TODO add findreleasebuild.html | |
| return | |
| } | |
| var err error | |
| if err = r.ParseForm(); err != nil { | |
| err = findReleasedBuildTemplate.Execute(w, &findBuildPage{Internal: true}) | |
| if err != nil { | |
| log.Errorf("error executing findbuild template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| return | |
| } | |
| cl := r.FormValue("cl") | |
| // If no CL value specified in request, display empty CL form | |
| if cl == "" { | |
| err = findReleasedBuildTemplate.Execute(w, &findBuildPage{Internal: true}) | |
| if err != nil { | |
| log.Errorf("error executing findreleasedbuild template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| return | |
| } | |
| internal, gerrit, gob, repo := false, externalGerritInstance, externalGoBInstance, externalManifestRepo | |
| if r.FormValue("cos-internal") == "true" { | |
| internal, gerrit, gob, repo = true, internalGerritInstance, internalGoBInstance, internalManifestRepo | |
| } | |
| httpClient, err := HTTPClient(w, r) | |
| if err != nil { | |
| loginURL := GetLoginURL("/findreleasedbuild/", false) | |
| http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect) | |
| return | |
| } | |
| buildData, utilErr := findReleaseBuild(httpClient, gerrit, gob, repo, cl, internal) | |
| if utilErr != nil { | |
| log.Errorf("error retrieving build for CL %s with internal set to %t\n%v", cl, internal, utilErr) | |
| handleError(w, r, utilErr, "/findreleasedbuild/") | |
| return | |
| } | |
| gerritLink := gerrit + "/c/" + buildData.CLNum | |
| page := &findBuildPage{ | |
| CL: cl, | |
| CLNum: buildData.CLNum, | |
| BuildNum: buildData.BuildNum, | |
| Internal: internal, | |
| GerritLink: gerritLink, | |
| } | |
| err = findReleasedBuildTemplate.Execute(w, page) | |
| if err != nil { | |
| log.Errorf("error executing findreleasebuild template: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| } | |
| } | |
| // HandleFindReleasedBuildGerrit returns the released build number in JSON | |
| func HandleFindReleasedBuildGerrit(w http.ResponseWriter, r *http.Request) { | |
| w.Header().Set("Content-Type", "application/json") | |
| if origin, ok := allowedOrigin(r.Header.Get("Origin")); ok { | |
| w.Header().Set("Access-Control-Allow-Origin", origin) | |
| w.Header().Set("Access-Control-Allow-Credentials", "true") | |
| } | |
| var err error | |
| if err = r.ParseForm(); err != nil { | |
| log.Errorf("error parsing form: %v", err) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| return | |
| } | |
| cl := r.FormValue("cl") | |
| // If no CL value specified in request, display empty CL form | |
| if cl == "" { | |
| http.Error(w, "empty cl provided", http.StatusInternalServerError) | |
| return | |
| } | |
| internal, gerrit, gob, repo := false, externalGerritInstance, externalGoBInstance, externalManifestRepo | |
| if r.FormValue("cos-internal") == "true" { | |
| internal, gerrit, gob, repo = true, internalGerritInstance, internalGoBInstance, internalManifestRepo | |
| } | |
| buildData, utilErr := findReleaseBuild(nil, gerrit, gob, repo, cl, internal) | |
| if utilErr != nil { | |
| log.Errorf("error retrieving build for CL %s with internal set to %t\n%v", cl, internal, utilErr) | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| return | |
| } | |
| versions := []string{} | |
| if buildData.BuildNum == "0.000.0" { | |
| versions = append(versions, "no build") | |
| } else { | |
| versions = append(versions, buildData.BuildNum) | |
| } | |
| json.NewEncoder(w).Encode(map[string][]string{"versions": versions}) | |
| } | |
| func allowedOrigin(origin string) (string, bool) { | |
| if origin == "https://cos-review.googlesource.com" || | |
| origin == "https://cos-internal-review.googlesource.com" || | |
| origin == "https://cos-review.git.corp.google.com" || | |
| origin == "https://cos-internal-review.git.corp.google.com" { | |
| return origin, true | |
| } | |
| return "", false | |
| } |