github.com/khulnasoft/codebase@v0.0.0-20231214144635-a707781cbb24/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  		"CI_COMMIT_BRANCH", // Woodpecker CI
    90  		// present only if PR pipeline
    91  		"BITBUCKET_PR_DESTINATION_BRANCH",
    92  		"BITBUCKET_BRANCH",
    93  	})
    94  
    95  	pr := getPullRequestNum()
    96  
    97  	return &BuildInfo{
    98  		Owner:       owner,
    99  		Repo:        repo,
   100  		PullRequest: pr,
   101  		SHA:         sha,
   102  		Branch:      branch,
   103  	}, pr != 0, nil
   104  }
   105  
   106  // GetGerritBuildInfo returns Gerrit specific build info
   107  func GetGerritBuildInfo() (*BuildInfo, error) {
   108  	changeID := os.Getenv("GERRIT_CHANGE_ID")
   109  	if changeID == "" {
   110  		return nil, errors.New("cannot get change id from environment variable. Set GERRIT_CHANGE_ID ?")
   111  	}
   112  
   113  	revisionID := os.Getenv("GERRIT_REVISION_ID")
   114  	if revisionID == "" {
   115  		return nil, errors.New("cannot get revision id from environment variable. Set GERRIT_REVISION_ID ?")
   116  	}
   117  
   118  	branch := os.Getenv("GERRIT_BRANCH")
   119  	if branch == "" {
   120  		return nil, errors.New("cannot get branch from environment variable. Set GERRIT_BRANCH ?")
   121  	}
   122  
   123  	return &BuildInfo{
   124  		GerritChangeID:   changeID,
   125  		GerritRevisionID: revisionID,
   126  		Branch:           branch,
   127  	}, nil
   128  }
   129  
   130  func getPullRequestNum() int {
   131  	envs := []string{
   132  		// Common.
   133  		"CI_PULL_REQUEST",
   134  		// Travis CI.
   135  		"TRAVIS_PULL_REQUEST",
   136  		// Circle CI.
   137  		"CIRCLE_PULL_REQUEST", // CircleCI 2.0
   138  		"CIRCLE_PR_NUMBER",    // For Pull Request by a fork repository
   139  		// drone.io.
   140  		"DRONE_PULL_REQUEST",
   141  		// GitLab CI MergeTrains
   142  		"CI_MERGE_REQUEST_IID",
   143  		"BITBUCKET_PR_ID",
   144  		// Woodpecker CI
   145  		"CI_COMMIT_PULL_REQUEST",
   146  	}
   147  	// regexp.MustCompile() in func intentionally because this func is called
   148  	// once for one run.
   149  	re := regexp.MustCompile(`[1-9]\d*$`)
   150  	for _, env := range envs {
   151  		prm := re.FindString(os.Getenv(env))
   152  		pr, _ := strconv.Atoi(prm)
   153  		if pr != 0 {
   154  			return pr
   155  		}
   156  	}
   157  	return 0
   158  }
   159  
   160  func getOneEnvValue(envs []string) string {
   161  	for _, env := range envs {
   162  		if v := os.Getenv(env); v != "" {
   163  			return v
   164  		}
   165  	}
   166  	return ""
   167  }
   168  
   169  func getOwnerAndRepoFromSlug(slugEnvs []string) (string, string) {
   170  	repoSlug := getOneEnvValue(slugEnvs)
   171  	ownerAndRepo := strings.SplitN(repoSlug, "/", 2)
   172  	if len(ownerAndRepo) < 2 {
   173  		return "", ""
   174  	}
   175  	return ownerAndRepo[0], ownerAndRepo[1]
   176  }