github.com/devtron-labs/ci-runner@v0.0.0-20240518055909-b2672f3349d7/helper/GitManager.go (about) 1 /* 2 * Copyright 2020 Devtron Labs 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 18 package helper 19 20 import ( 21 "context" 22 "github.com/devtron-labs/ci-runner/util" 23 "log" 24 "os" 25 "path/filepath" 26 ) 27 28 type GitOptions struct { 29 UserName string `json:"userName"` 30 Password string `json:"password"` 31 SshPrivateKey string `json:"sshPrivateKey"` 32 AccessToken string `json:"accessToken"` 33 AuthMode AuthMode `json:"authMode"` 34 } 35 36 type WebhookData struct { 37 Id int `json:"id"` 38 EventActionType string `json:"eventActionType"` 39 Data map[string]string `json:"data"` 40 } 41 42 type GitContext struct { 43 context.Context // Embedding original Go context 44 Auth *BasicAuth 45 } 46 type BasicAuth struct { 47 Username, Password string 48 } 49 50 type AuthMode string 51 52 const ( 53 AUTH_MODE_USERNAME_PASSWORD AuthMode = "USERNAME_PASSWORD" 54 AUTH_MODE_SSH AuthMode = "SSH" 55 AUTH_MODE_ACCESS_TOKEN AuthMode = "ACCESS_TOKEN" 56 AUTH_MODE_ANONYMOUS AuthMode = "ANONYMOUS" 57 ) 58 59 type SourceType string 60 61 const ( 62 SOURCE_TYPE_BRANCH_FIXED SourceType = "SOURCE_TYPE_BRANCH_FIXED" 63 SOURCE_TYPE_WEBHOOK SourceType = "WEBHOOK" 64 ) 65 66 const ( 67 WEBHOOK_SELECTOR_TARGET_CHECKOUT_NAME string = "target checkout" 68 WEBHOOK_SELECTOR_SOURCE_CHECKOUT_NAME string = "source checkout" 69 WEBHOOK_SELECTOR_TARGET_CHECKOUT_BRANCH_NAME string = "target branch name" 70 71 WEBHOOK_EVENT_MERGED_ACTION_TYPE string = "merged" 72 WEBHOOK_EVENT_NON_MERGED_ACTION_TYPE string = "non-merged" 73 ) 74 75 type GitManager struct { 76 gitCliManager GitCliManager 77 } 78 79 func NewGitManagerImpl(gitCliManager GitCliManager) *GitManager { 80 return &GitManager{ 81 gitCliManager: gitCliManager, 82 } 83 } 84 85 func (impl *GitManager) CloneAndCheckout(ciProjectDetails []CiProjectDetails) error { 86 for index, prj := range ciProjectDetails { 87 // git clone 88 89 log.Println("-----> git " + prj.CloningMode + " cloning " + prj.GitRepository) 90 91 if prj.CheckoutPath != "./" { 92 if _, err := os.Stat(prj.CheckoutPath); os.IsNotExist(err) { 93 _ = os.Mkdir(prj.CheckoutPath, os.ModeDir) 94 } 95 } 96 var cErr error 97 var auth *BasicAuth 98 authMode := prj.GitOptions.AuthMode 99 switch authMode { 100 case AUTH_MODE_USERNAME_PASSWORD: 101 auth = &BasicAuth{Password: prj.GitOptions.Password, Username: prj.GitOptions.UserName} 102 case AUTH_MODE_ACCESS_TOKEN: 103 auth = &BasicAuth{Password: prj.GitOptions.AccessToken, Username: prj.GitOptions.UserName} 104 default: 105 auth = &BasicAuth{} 106 } 107 108 gitContext := GitContext{ 109 Auth: auth, 110 } 111 // create ssh private key on disk 112 if authMode == AUTH_MODE_SSH { 113 cErr = util.CreateSshPrivateKeyOnDisk(index, prj.GitOptions.SshPrivateKey) 114 cErr = util.CreateSshPrivateKeyOnDisk(index, prj.GitOptions.SshPrivateKey) 115 if cErr != nil { 116 log.Fatal("could not create ssh private key on disk ", " err ", cErr) 117 } 118 } 119 120 _, msgMsg, cErr := impl.gitCliManager.Clone(gitContext, prj) 121 if cErr != nil { 122 log.Fatal("could not clone repo ", " err ", cErr, "msgMsg", msgMsg) 123 } 124 125 // checkout code 126 if prj.SourceType == SOURCE_TYPE_BRANCH_FIXED { 127 // checkout incoming commit hash or branch name 128 checkoutSource := "" 129 if len(prj.CommitHash) > 0 { 130 checkoutSource = prj.CommitHash 131 } else { 132 if len(prj.SourceValue) == 0 { 133 prj.SourceValue = "main" 134 } 135 checkoutSource = prj.SourceValue 136 } 137 log.Println("checkout commit in branch fix : ", checkoutSource) 138 msgMsg, cErr = impl.gitCliManager.GitCheckout(gitContext, prj.CheckoutPath, checkoutSource, authMode, prj.FetchSubmodules, prj.GitRepository) 139 if cErr != nil { 140 log.Fatal("could not checkout hash ", " err ", cErr, "msgMsg", msgMsg) 141 } 142 143 } else if prj.SourceType == SOURCE_TYPE_WEBHOOK { 144 145 webhookData := prj.WebhookData 146 webhookDataData := webhookData.Data 147 148 targetCheckout := webhookDataData[WEBHOOK_SELECTOR_TARGET_CHECKOUT_NAME] 149 if len(targetCheckout) == 0 { 150 log.Fatal("could not get target checkout from request data") 151 } 152 153 log.Println("checkout commit in webhook : ", targetCheckout) 154 155 // checkout target hash 156 msgMsg, cErr = impl.gitCliManager.GitCheckout(gitContext, prj.CheckoutPath, targetCheckout, authMode, prj.FetchSubmodules, prj.GitRepository) 157 if cErr != nil { 158 log.Fatal("could not checkout ", "targetCheckout ", targetCheckout, " err ", cErr, " msgMsg", msgMsg) 159 return cErr 160 } 161 162 // merge source if action type is merged 163 if webhookData.EventActionType == WEBHOOK_EVENT_MERGED_ACTION_TYPE { 164 sourceCheckout := webhookDataData[WEBHOOK_SELECTOR_SOURCE_CHECKOUT_NAME] 165 166 // throw error if source checkout is empty 167 if len(sourceCheckout) == 0 { 168 log.Fatal("sourceCheckout is empty") 169 } 170 171 log.Println("merge commit in webhook : ", sourceCheckout) 172 173 // merge source 174 _, msgMsg, cErr = impl.gitCliManager.Merge(filepath.Join(util.WORKINGDIR, prj.CheckoutPath), sourceCheckout) 175 if cErr != nil { 176 log.Fatal("could not merge ", "sourceCheckout ", sourceCheckout, " err ", cErr, " msgMsg", msgMsg) 177 return cErr 178 } 179 180 } 181 182 } 183 184 } 185 return nil 186 }