github.com/vipcoin-gold/reviewdog@v1.0.2/cienv/cienv.go (about) 1 // Package cienv provides utility for environment variable in CI services. 2 package cienv 3 4 import ( 5 "errors" 6 "os" 7 "regexp" 8 "strconv" 9 "strings" 10 ) 11 12 // BuildInfo represents build information about GitHub or GitLab project. 13 type BuildInfo struct { 14 Owner string 15 Repo string 16 SHA string 17 18 // Optional. 19 PullRequest int // MergeRequest for GitLab. 20 21 // Optional. 22 Branch string 23 24 // Gerrit related params 25 GerritChangeID string 26 GerritRevisionID string 27 } 28 29 // GetBuildInfo returns BuildInfo from environment variables. 30 // 31 // Supported CI services' documents: 32 // - Travis CI: https://docs.travis-ci.com/user/environment-variables/ 33 // - Circle CI: https://circleci.com/docs/environment-variables/ 34 // - Drone.io: http://docs.drone.io/environment-reference/ 35 // - GitLab CI: https://docs.gitlab.com/ee/ci/variables/#predefined-variables-environment-variables 36 // - GitLab CI doesn't export ID of Merge Request. https://gitlab.com/gitlab-org/gitlab-ce/issues/15280 37 func GetBuildInfo() (prInfo *BuildInfo, isPR bool, err error) { 38 if IsInGitHubAction() { 39 return getBuildInfoFromGitHubAction() 40 } 41 owner, repo := getOwnerAndRepoFromSlug([]string{ 42 "TRAVIS_REPO_SLUG", 43 "DRONE_REPO", // drone<=0.4 44 "BITBUCKET_REPO_FULL_NAME", 45 }) 46 if owner == "" { 47 owner = getOneEnvValue([]string{ 48 "CI_REPO_OWNER", // common 49 "CIRCLE_PROJECT_USERNAME", 50 "DRONE_REPO_OWNER", 51 "CI_PROJECT_NAMESPACE", // GitLab CI 52 }) 53 } 54 if owner == "" { 55 return nil, false, errors.New("cannot get repo owner from environment variable. Set CI_REPO_OWNER?") 56 } 57 58 if repo == "" { 59 repo = getOneEnvValue([]string{ 60 "CI_REPO_NAME", // common 61 "CIRCLE_PROJECT_REPONAME", 62 "DRONE_REPO_NAME", 63 "CI_PROJECT_NAME", // GitLab CI 64 }) 65 } 66 67 if repo == "" { 68 return nil, false, errors.New("cannot get repo name from environment variable. Set CI_REPO_NAME?") 69 } 70 71 sha := getOneEnvValue([]string{ 72 "CI_COMMIT", // common 73 "TRAVIS_PULL_REQUEST_SHA", 74 "TRAVIS_COMMIT", 75 "CIRCLE_SHA1", 76 "DRONE_COMMIT", 77 "CI_COMMIT_SHA", // GitLab CI 78 "BITBUCKET_COMMIT", 79 }) 80 if sha == "" { 81 return nil, false, errors.New("cannot get commit SHA from environment variable. Set CI_COMMIT?") 82 } 83 84 branch := getOneEnvValue([]string{ 85 "CI_BRANCH", // common 86 "TRAVIS_PULL_REQUEST_BRANCH", 87 "CIRCLE_BRANCH", 88 "DRONE_COMMIT_BRANCH", 89 // present only if PR pipeline 90 "BITBUCKET_PR_DESTINATION_BRANCH", 91 "BITBUCKET_BRANCH", 92 }) 93 94 pr := getPullRequestNum() 95 96 return &BuildInfo{ 97 Owner: owner, 98 Repo: repo, 99 PullRequest: pr, 100 SHA: sha, 101 Branch: branch, 102 }, pr != 0, nil 103 } 104 105 // GetGerritBuildInfo returns Gerrit specific build info 106 func GetGerritBuildInfo() (*BuildInfo, error) { 107 changeID := os.Getenv("GERRIT_CHANGE_ID") 108 if changeID == "" { 109 return nil, errors.New("cannot get change id from environment variable. Set GERRIT_CHANGE_ID ?") 110 } 111 112 revisionID := os.Getenv("GERRIT_REVISION_ID") 113 if revisionID == "" { 114 return nil, errors.New("cannot get revision id from environment variable. Set GERRIT_REVISION_ID ?") 115 } 116 117 branch := os.Getenv("GERRIT_BRANCH") 118 if branch == "" { 119 return nil, errors.New("cannot get branch from environment variable. Set GERRIT_BRANCH ?") 120 } 121 122 return &BuildInfo{ 123 GerritChangeID: changeID, 124 GerritRevisionID: revisionID, 125 Branch: branch, 126 }, nil 127 } 128 129 func getPullRequestNum() int { 130 envs := []string{ 131 // Common. 132 "CI_PULL_REQUEST", 133 // Travis CI. 134 "TRAVIS_PULL_REQUEST", 135 // Circle CI. 136 "CIRCLE_PULL_REQUEST", // CircleCI 2.0 137 "CIRCLE_PR_NUMBER", // For Pull Request by a fork repository 138 // drone.io. 139 "DRONE_PULL_REQUEST", 140 // GitLab CI MergeTrains 141 "CI_MERGE_REQUEST_IID", 142 "BITBUCKET_PR_ID", 143 } 144 // regexp.MustCompile() in func intentionally because this func is called 145 // once for one run. 146 re := regexp.MustCompile(`[1-9]\d*$`) 147 for _, env := range envs { 148 prm := re.FindString(os.Getenv(env)) 149 pr, _ := strconv.Atoi(prm) 150 if pr != 0 { 151 return pr 152 } 153 } 154 return 0 155 } 156 157 func getOneEnvValue(envs []string) string { 158 for _, env := range envs { 159 if v := os.Getenv(env); v != "" { 160 return v 161 } 162 } 163 return "" 164 } 165 166 func getOwnerAndRepoFromSlug(slugEnvs []string) (string, string) { 167 repoSlug := getOneEnvValue(slugEnvs) 168 ownerAndRepo := strings.SplitN(repoSlug, "/", 2) 169 if len(ownerAndRepo) < 2 { 170 return "", "" 171 } 172 return ownerAndRepo[0], ownerAndRepo[1] 173 }