sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/pod-utils/gcs/target.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package gcs 18 19 import ( 20 "fmt" 21 "path" 22 "strconv" 23 "strings" 24 25 "github.com/sirupsen/logrus" 26 27 prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" 28 gerritsource "sigs.k8s.io/prow/pkg/gerrit/source" 29 "sigs.k8s.io/prow/pkg/pod-utils/downwardapi" 30 ) 31 32 const ( 33 // PRLogs is the name of the directory we put PR logs in. 34 PRLogs = "pr-logs" 35 // NonPRLogs is the name of directory we put logs that are not PR logs in. 36 NonPRLogs = "logs" 37 ) 38 39 // PathForSpec determines the GCS path prefix for files uploaded 40 // for a specific job spec 41 func PathForSpec(spec *downwardapi.JobSpec, pathSegment RepoPathBuilder) string { 42 switch spec.Type { 43 case prowapi.PeriodicJob, prowapi.PostsubmitJob: 44 return path.Join(NonPRLogs, spec.Job, spec.BuildID) 45 case prowapi.PresubmitJob: 46 return path.Join(PRLogs, "pull", pathSegment(spec.Refs.Org, spec.Refs.Repo), strconv.Itoa(spec.Refs.Pulls[0].Number), spec.Job, spec.BuildID) 47 case prowapi.BatchJob: 48 return path.Join(PRLogs, "pull", "batch", spec.Job, spec.BuildID) 49 default: 50 logrus.Fatalf("unknown job spec type: %v", spec.Type) 51 } 52 return "" 53 } 54 55 // AliasForSpec determines the GCS path aliases for a job spec 56 func AliasForSpec(spec *downwardapi.JobSpec) string { 57 switch spec.Type { 58 case prowapi.PeriodicJob, prowapi.PostsubmitJob, prowapi.BatchJob: 59 return "" 60 case prowapi.PresubmitJob: 61 return path.Join(PRLogs, "directory", spec.Job, fmt.Sprintf("%s.txt", spec.BuildID)) 62 default: 63 logrus.Fatalf("unknown job spec type: %v", spec.Type) 64 } 65 return "" 66 } 67 68 // LatestBuildForSpec determines the GCS path for storing the latest 69 // build id for a job. pathSegment can be nil so callers of this 70 // helper are not required to choose a path strategy but can still 71 // get back a result. 72 func LatestBuildForSpec(spec *downwardapi.JobSpec, pathSegment RepoPathBuilder) []string { 73 var latestBuilds []string 74 switch spec.Type { 75 case prowapi.PeriodicJob, prowapi.PostsubmitJob: 76 latestBuilds = append(latestBuilds, path.Join(NonPRLogs, spec.Job, "latest-build.txt")) 77 case prowapi.PresubmitJob: 78 latestBuilds = append(latestBuilds, path.Join(PRLogs, "directory", spec.Job, "latest-build.txt")) 79 // Gubernator expects presubmit tests to upload latest-build.txt 80 // under the PR-specific directory too. 81 if pathSegment != nil { 82 latestBuilds = append(latestBuilds, path.Join(PRLogs, "pull", pathSegment(spec.Refs.Org, spec.Refs.Repo), strconv.Itoa(spec.Refs.Pulls[0].Number), spec.Job, "latest-build.txt")) 83 } 84 case prowapi.BatchJob: 85 latestBuilds = append(latestBuilds, path.Join(PRLogs, "directory", spec.Job, "latest-build.txt")) 86 default: 87 logrus.Errorf("unknown job spec type: %v", spec.Type) 88 return nil 89 } 90 return latestBuilds 91 } 92 93 // RootForSpec determines the root GCS path for storing artifacts about 94 // the provided job. 95 func RootForSpec(spec *downwardapi.JobSpec) string { 96 switch spec.Type { 97 case prowapi.PeriodicJob, prowapi.PostsubmitJob: 98 return path.Join(NonPRLogs, spec.Job) 99 case prowapi.PresubmitJob, prowapi.BatchJob: 100 return path.Join(PRLogs, "directory", spec.Job) 101 default: 102 logrus.Errorf("unknown job spec type: %v", spec.Type) 103 } 104 return "" 105 } 106 107 // RepoPathBuilder builds GCS path segments and embeds defaulting behavior 108 type RepoPathBuilder func(org, repo string) string 109 110 // NewLegacyRepoPathBuilder returns a builder that handles the legacy path 111 // encoding where a path will only contain an org or repo if they are non-default 112 func NewLegacyRepoPathBuilder(defaultOrg, defaultRepo string) RepoPathBuilder { 113 return func(org, repo string) string { 114 if org == defaultOrg { 115 if repo == defaultRepo { 116 return "" 117 } 118 return repo 119 } 120 // handle gerrit repo 121 org = gerritsource.TrimHTTPSPrefix(org) 122 repo = strings.Replace(repo, "/", "_", -1) 123 return fmt.Sprintf("%s_%s", org, repo) 124 } 125 } 126 127 // NewSingleDefaultRepoPathBuilder returns a builder that handles the legacy path 128 // encoding where a path will contain org and repo for all but one default repo 129 func NewSingleDefaultRepoPathBuilder(defaultOrg, defaultRepo string) RepoPathBuilder { 130 return func(org, repo string) string { 131 if org == defaultOrg && repo == defaultRepo { 132 return "" 133 } 134 // handle gerrit repo 135 org = gerritsource.TrimHTTPSPrefix(org) 136 repo = strings.Replace(repo, "/", "_", -1) 137 return fmt.Sprintf("%s_%s", org, repo) 138 } 139 } 140 141 // NewExplicitRepoPathBuilder returns a builder that handles the path encoding 142 // where a path will always have an explicit "org_repo" path segment 143 func NewExplicitRepoPathBuilder() RepoPathBuilder { 144 return func(org, repo string) string { 145 // handle gerrit repo 146 org = gerritsource.TrimHTTPSPrefix(org) 147 repo = strings.Replace(repo, "/", "_", -1) 148 return fmt.Sprintf("%s_%s", org, repo) 149 } 150 }