k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/experiment/manual-trigger/manual-trigger.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 // manual-trigger triggers jenkins jobs based a specified github pull request 18 package main 19 20 import ( 21 "flag" 22 "fmt" 23 "log" 24 "net/url" 25 "strings" 26 27 "github.com/sirupsen/logrus" 28 29 prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" 30 "sigs.k8s.io/prow/pkg/config/secret" 31 "sigs.k8s.io/prow/pkg/github" 32 "sigs.k8s.io/prow/pkg/jenkins" 33 "sigs.k8s.io/prow/pkg/pod-utils/downwardapi" 34 ) 35 36 type options struct { 37 githubEndpoint string 38 graphqlEndpoint string 39 githubTokenFile string 40 jenkinsBearerTokenFile string 41 jenkinsURL string 42 jenkinsTokenFile string 43 jenkinsUserName string 44 jobName string 45 num int 46 org string 47 repo string 48 } 49 50 func flagOptions() options { 51 o := options{} 52 53 flag.StringVar(&o.jenkinsBearerTokenFile, "jenkins-bearer-token-file", "", "Path to the file containing the Jenkins API bearer token.") 54 flag.StringVar(&o.jenkinsURL, "jenkins-url", "", "Jenkins URL.") 55 flag.StringVar(&o.jenkinsTokenFile, "jenkins-token-file", "", "Path to the file containing the Jenkins API token.") 56 flag.StringVar(&o.jenkinsUserName, "jenkins-user-name", "", "Jenkins username.") 57 58 flag.StringVar(&o.githubEndpoint, "github-endpoint", github.DefaultAPIEndpoint, "GitHub's API endpoint.") 59 flag.StringVar(&o.graphqlEndpoint, "graphql-endpoint", github.DefaultGraphQLEndpoint, "GitHub's GraphQL API endpoint.") 60 flag.StringVar(&o.githubTokenFile, "github-token-file", "", "Path to file containing GitHub OAuth token.") 61 62 flag.StringVar(&o.jobName, "job-name", "", "Name of Jenkins job") 63 64 flag.IntVar(&o.num, "num", 0, "GitHub issue number") 65 flag.StringVar(&o.org, "org", "", "GitHub organization") 66 flag.StringVar(&o.repo, "repo", "", "GitHub repository") 67 flag.Parse() 68 return o 69 } 70 71 func sanityCheckFlags(o options) error { 72 if o.num <= 0 { 73 return fmt.Errorf("empty or invalid --num") 74 } 75 if o.org == "" { 76 return fmt.Errorf("empty --org") 77 } 78 if o.repo == "" { 79 return fmt.Errorf("empty --repo") 80 } 81 if o.githubTokenFile == "" { 82 return fmt.Errorf("empty --github-token-file") 83 } 84 if o.jobName == "" { 85 return fmt.Errorf("empty --job-name") 86 } 87 88 if o.jenkinsBearerTokenFile == "" && (o.jenkinsUserName == "" || o.jenkinsTokenFile == "") { 89 return fmt.Errorf("neither --jenkins-bearer-token-file nor the combination of --jenkins-user-name and --jenkins-token-file were provided") 90 } 91 92 if o.githubEndpoint == "" { 93 return fmt.Errorf("empty --github-endpoint") 94 } else if _, err := url.Parse(o.githubEndpoint); err != nil { 95 return fmt.Errorf("bad --github-endpoint provided: %w", err) 96 } 97 98 if o.graphqlEndpoint == "" { 99 return fmt.Errorf("empty --graphql-endpoint") 100 } else if _, err := url.Parse(o.graphqlEndpoint); err != nil { 101 return fmt.Errorf("bad --graphql-endpoint provided: %w", err) 102 } 103 104 if o.jenkinsURL == "" { 105 return fmt.Errorf("empty --jenkins-url") 106 } else if _, err := url.Parse(o.jenkinsURL); err != nil { 107 return fmt.Errorf("bad --jenkins-url provided: %w", err) 108 } 109 110 return nil 111 } 112 113 func main() { 114 o := flagOptions() 115 err := sanityCheckFlags(o) 116 if err != nil { 117 log.Fatal(err) 118 } 119 120 var tokens []string 121 tokens = append(tokens, o.githubTokenFile) 122 123 if o.jenkinsTokenFile != "" { 124 tokens = append(tokens, o.jenkinsTokenFile) 125 } 126 127 if o.jenkinsBearerTokenFile != "" { 128 tokens = append(tokens, o.jenkinsBearerTokenFile) 129 } 130 131 if err := secret.Add(tokens...); err != nil { 132 logrus.WithError(err).Fatal("Error starting secrets agent.") 133 } 134 135 // TODO: dry this out 136 ac := jenkins.AuthConfig{} 137 if o.jenkinsTokenFile != "" { 138 ac.Basic = &jenkins.BasicAuthConfig{ 139 User: o.jenkinsUserName, 140 GetToken: secret.GetTokenGenerator(o.jenkinsTokenFile), 141 } 142 } else if o.jenkinsBearerTokenFile != "" { 143 ac.BearerToken = &jenkins.BearerTokenAuthConfig{ 144 GetToken: secret.GetTokenGenerator(o.jenkinsBearerTokenFile), 145 } 146 } else { 147 log.Fatalf("no jenkins auth token provided") 148 } 149 150 jc, err := jenkins.NewClient(o.jenkinsURL, false, nil, &ac, nil, nil) 151 if err != nil { 152 log.Fatalf("cannot setup Jenkins client: %v", err) 153 } 154 155 gc, err := github.NewClient(secret.GetTokenGenerator(o.githubTokenFile), secret.Censor, o.graphqlEndpoint, o.githubEndpoint) 156 if err != nil { 157 log.Fatalf("failed to construct GitHub client: %v", err) 158 } 159 160 pr, err := gc.GetPullRequest(o.org, o.repo, o.num) 161 if err != nil { 162 log.Fatalf("Unable to get information on pull request %s/%s#%d: %v", o.org, o.repo, o.num, err) 163 } 164 165 spec := prowapi.ProwJobSpec{ 166 Type: prowapi.PresubmitJob, 167 Job: o.jobName, 168 Refs: &prowapi.Refs{ 169 Org: o.org, 170 Repo: o.repo, 171 BaseRef: pr.Base.Ref, 172 BaseSHA: pr.Base.SHA, 173 Pulls: []prowapi.Pull{ 174 { 175 Number: pr.Number, 176 Author: pr.User.Login, 177 SHA: pr.Head.SHA, 178 HeadRef: pr.Head.Ref, 179 }, 180 }, 181 }, 182 183 Report: false, 184 Context: "", 185 RerunCommand: "", 186 MaxConcurrency: 1, 187 } 188 189 if err = jc.BuildFromSpec(&spec, "0", o.jobName); err != nil { 190 log.Println("Submitting the following to Jenkins:") 191 env, _ := downwardapi.EnvForSpec(downwardapi.NewJobSpec(spec, "0", o.jobName)) 192 for k, v := range env { 193 log.Printf(" %s=%s\n", k, v) 194 } 195 log.Fatalf("for %s/%s#%d resulted in an error: %v", o.org, o.repo, o.num, err) 196 } else { 197 slash := "/" 198 if strings.HasSuffix(o.jenkinsURL, "/") { 199 slash = "" 200 } 201 log.Printf("Successfully submitted job to %s%sjob/%s", o.jenkinsURL, slash, o.jobName) 202 } 203 }