-
Notifications
You must be signed in to change notification settings - Fork 81
/
generate.go
251 lines (220 loc) · 7.12 KB
/
generate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
package generate
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/openshift-pipelines/pipelines-as-code/pkg/cli"
"github.com/openshift-pipelines/pipelines-as-code/pkg/cli/prompt"
"github.com/openshift-pipelines/pipelines-as-code/pkg/git"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var eventTypes = map[string]string{"pull_request": "Pull Request", "push": "Push to a Branch or a Tag"}
const (
gitCloneClusterTaskName = "git-clone"
defaultEventType = "Pull Request"
mainBranch = "main"
)
type Opts struct {
Event *info.Event
GitInfo *git.Info
IOStreams *cli.IOStreams
CLIOpts *cli.PacCliOpts
pipelineRunName string
FileName string
overwrite bool
language string
generateWithClusterTask bool
}
func MakeOpts() *Opts {
return &Opts{
Event: info.NewEvent(),
GitInfo: &git.Info{},
IOStreams: &cli.IOStreams{},
CLIOpts: &cli.PacCliOpts{},
}
}
func Command(run *params.Run, ioStreams *cli.IOStreams) *cobra.Command {
gopt := MakeOpts()
gopt.IOStreams = ioStreams
cmd := &cobra.Command{
Use: "generate",
Aliases: []string{"gen"},
Short: "Generate PipelineRun",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
gopt.CLIOpts = cli.NewCliOptions()
gopt.IOStreams.SetColorEnabled(!gopt.CLIOpts.NoColoring)
if !gopt.generateWithClusterTask {
if err := run.Clients.NewClients(ctx, &run.Info); err != nil {
// if we don't have access to the cluster we can't do much about it
gopt.generateWithClusterTask = false
} else {
// NOTE(chmou): This is for v1beta1, we need to figure out how to do this for v1.
// Trying to find resolver with that same name?
_, err := run.Clients.Tekton.TektonV1beta1().ClusterTasks().Get(ctx, gitCloneClusterTaskName,
metav1.GetOptions{})
if err == nil {
gopt.generateWithClusterTask = true
}
}
}
cwd, err := os.Getwd()
if err != nil {
return err
}
gopt.GitInfo = git.GetGitInfo(cwd)
return Generate(gopt, true)
},
Annotations: map[string]string{
"commandType": "main",
},
}
cmd.PersistentFlags().StringVar(&gopt.Event.BaseBranch, "branch", "",
"The target branch of the repository event to handle (eg: main, nightly)")
cmd.PersistentFlags().StringVar(&gopt.Event.EventType, "event-type", "",
"The event type of the repository event to handle (eg: pull_request, push)")
cmd.PersistentFlags().StringVar(&gopt.pipelineRunName, "pipeline-name", "",
"The pipeline name")
cmd.PersistentFlags().StringVarP(&gopt.FileName, "file-name", "f", "",
"The file name location")
cmd.PersistentFlags().BoolVar(&gopt.overwrite, "overwrite", false,
"Wether to overwrite the file if it exist")
cmd.PersistentFlags().StringVarP(&gopt.language, "language", "l", "",
"Generate for this programming language")
cmd.PersistentFlags().BoolVarP(&gopt.generateWithClusterTask, "use-clustertasks", "", false,
"By default we will generate the pipeline using task from hub. If you want to use cluster tasks, set this flag")
return cmd
}
func Generate(o *Opts, recreateTemplate bool) error {
if err := o.targetEvent(); err != nil {
return err
}
if err := o.branchOrTag(); err != nil {
return err
}
return o.samplePipeline(recreateTemplate)
}
func (o *Opts) targetEvent() error {
var choice string
if o.Event.EventType != "" {
return nil
}
msg := "Enter the Git event type for triggering the pipeline: "
eventLabels := make([]string, 0, len(eventTypes))
for _, label := range eventTypes {
eventLabels = append(eventLabels, label)
}
if err := prompt.SurveyAskOne(
&survey.Select{
Message: msg,
Options: eventLabels,
Default: 0,
}, &choice); err != nil {
return err
}
if choice == "" {
choice = defaultEventType
}
for k, v := range eventTypes {
if v == choice {
o.Event.EventType = k
return nil
}
}
return fmt.Errorf("invalid event type: %s", choice)
}
func (o *Opts) branchOrTag() error {
var msg string
choice := new(string)
if o.Event.BaseBranch != "" {
return nil
}
o.Event.BaseBranch = mainBranch
if o.Event.EventType == "pull_request" {
msg = "Enter the target GIT branch for the Pull Request (default: %s): "
} else if o.Event.EventType == "push" {
msg = "Enter a target GIT branch or a tag for the push (default: %s)"
}
if err := prompt.SurveyAskOne(
&survey.Input{
Message: fmt.Sprintf(msg, mainBranch),
}, choice); err != nil {
return err
}
if *choice != "" {
o.Event.BaseBranch = *choice
}
return nil
}
func generatefileName(eventType string) string {
var filename string
types := strings.Split(eventType, ",")
if len(types) > 1 {
filename = "pipelinerun"
} else {
filename = strings.ReplaceAll(eventType, "_", "-")
}
return fmt.Sprintf("%s.yaml", filename)
}
// samplePipeline will try to create a basic pipeline in tekton
// directory.
func (o *Opts) samplePipeline(recreateTemplate bool) error {
cs := o.IOStreams.ColorScheme()
var relpath, fpath string
if o.FileName != "" {
fpath = o.FileName
relpath = fpath
} else {
fname := generatefileName(o.Event.EventType)
fpath = filepath.Join(o.GitInfo.TopLevelPath, ".tekton", fname)
relpath, _ = filepath.Rel(o.GitInfo.TopLevelPath, fpath)
if _, err := os.Stat(filepath.Join(o.GitInfo.TopLevelPath, ".tekton")); os.IsNotExist(err) {
if err := os.MkdirAll(filepath.Join(o.GitInfo.TopLevelPath, ".tekton"), 0o755); err != nil {
return err
}
fmt.Fprintf(o.IOStreams.Out, "%s Directory %s has been created.\n",
cs.InfoIcon(),
cs.Bold(".tekton"),
)
}
}
if _, err := os.Stat(fpath); !os.IsNotExist(err) && !o.overwrite {
if recreateTemplate {
var overwrite bool
msg := fmt.Sprintf("There is already a file named: %s would you like me to override it?", relpath)
if err := prompt.SurveyAskOne(&survey.Confirm{Message: msg, Default: false}, &overwrite); err != nil {
return err
}
if !overwrite {
fmt.Fprintf(o.IOStreams.ErrOut, "%s Not overwriting file, exiting...\n", cs.WarningIcon())
fmt.Fprintf(o.IOStreams.ErrOut, "%s Feel free to use the -f flag if you want to target another file name\n...", cs.InfoIcon())
}
} else {
fmt.Fprintf(o.IOStreams.Out, "%s There is already a file named: %s, skipping template generation, feel free to use \"%s pac generate\" command to generate sample template.\n", cs.InfoIcon(), relpath,
settings.TknBinaryName)
}
return nil
}
tmpl, err := o.genTmpl()
if err != nil {
return err
}
//nolint: gosec
err = os.WriteFile(fpath, tmpl.Bytes(), 0o644)
if err != nil {
return fmt.Errorf("cannot write template to %s: %w", fpath, err)
}
fmt.Fprintf(o.IOStreams.Out, "%s A basic template has been created in %s, feel free to customize it.\n",
cs.SuccessIcon(),
cs.Bold(fpath),
)
fmt.Fprintf(o.IOStreams.Out, "%s You can test your pipeline by pushing generated template to your git repository\n", cs.InfoIcon())
return nil
}