github.com/nilium/gitlab-runner@v12.5.0+incompatible/commands/exec.go (about)

     1  package commands
     2  
     3  import (
     4  	"os"
     5  	"os/exec"
     6  	"strings"
     7  
     8  	"github.com/sirupsen/logrus"
     9  	"github.com/urfave/cli"
    10  	"gitlab.com/ayufan/golang-cli-helpers"
    11  
    12  	"gitlab.com/gitlab-org/gitlab-runner/common"
    13  	"gitlab.com/gitlab-org/gitlab-runner/helpers/gitlab_ci_yaml_parser"
    14  	// Force to load all executors, executes init() on them
    15  	_ "gitlab.com/gitlab-org/gitlab-runner/executors/custom"
    16  	_ "gitlab.com/gitlab-org/gitlab-runner/executors/docker"
    17  	_ "gitlab.com/gitlab-org/gitlab-runner/executors/parallels"
    18  	_ "gitlab.com/gitlab-org/gitlab-runner/executors/shell"
    19  	_ "gitlab.com/gitlab-org/gitlab-runner/executors/ssh"
    20  	_ "gitlab.com/gitlab-org/gitlab-runner/executors/virtualbox"
    21  )
    22  
    23  type ExecCommand struct {
    24  	common.RunnerSettings
    25  	Job     string
    26  	Timeout int `long:"timeout" description:"Job execution timeout (in seconds)"`
    27  }
    28  
    29  func (c *ExecCommand) runCommand(name string, arg ...string) (string, error) {
    30  	cmd := exec.Command(name, arg...)
    31  	cmd.Env = os.Environ()
    32  	cmd.Stderr = os.Stderr
    33  	result, err := cmd.Output()
    34  	return string(result), err
    35  }
    36  
    37  func (c *ExecCommand) createBuild(repoURL string, abortSignal chan os.Signal) (build *common.Build, err error) {
    38  	// Check if we have uncommitted changes
    39  	_, err = c.runCommand("git", "diff", "--quiet", "HEAD")
    40  	if err != nil {
    41  		logrus.Warningln("You most probably have uncommitted changes.")
    42  		logrus.Warningln("These changes will not be tested.")
    43  	}
    44  
    45  	// Parse Git settings
    46  	sha, err := c.runCommand("git", "rev-parse", "HEAD")
    47  	if err != nil {
    48  		return
    49  	}
    50  
    51  	beforeSha, err := c.runCommand("git", "rev-parse", "HEAD~1")
    52  	if err != nil {
    53  		beforeSha = "0000000000000000000000000000000000000000"
    54  	}
    55  
    56  	refName, err := c.runCommand("git", "rev-parse", "--abbrev-ref", "HEAD")
    57  	if err != nil {
    58  		return
    59  	}
    60  
    61  	jobResponse := common.JobResponse{
    62  		ID:            1,
    63  		Token:         "",
    64  		AllowGitFetch: false,
    65  		JobInfo: common.JobInfo{
    66  			Name:        "",
    67  			Stage:       "",
    68  			ProjectID:   1,
    69  			ProjectName: "",
    70  		},
    71  		GitInfo: common.GitInfo{
    72  			RepoURL:   repoURL,
    73  			Ref:       strings.TrimSpace(refName),
    74  			Sha:       strings.TrimSpace(sha),
    75  			BeforeSha: strings.TrimSpace(beforeSha),
    76  		},
    77  		RunnerInfo: common.RunnerInfo{
    78  			Timeout: c.getTimeout(),
    79  		},
    80  	}
    81  
    82  	runner := &common.RunnerConfig{
    83  		RunnerSettings: c.RunnerSettings,
    84  	}
    85  
    86  	build, err = common.NewBuild(jobResponse, runner, abortSignal, nil)
    87  
    88  	return
    89  }
    90  
    91  func (c *ExecCommand) getTimeout() int {
    92  	if c.Timeout > 0 {
    93  		return c.Timeout
    94  	}
    95  
    96  	return common.DefaultExecTimeout
    97  }
    98  
    99  func (c *ExecCommand) Execute(context *cli.Context) {
   100  	wd, err := os.Getwd()
   101  	if err != nil {
   102  		logrus.Fatalln(err)
   103  	}
   104  
   105  	switch len(context.Args()) {
   106  	case 1:
   107  		c.Job = context.Args().Get(0)
   108  	default:
   109  		cli.ShowSubcommandHelp(context)
   110  		os.Exit(1)
   111  		return
   112  	}
   113  
   114  	c.Executor = context.Command.Name
   115  
   116  	abortSignal := make(chan os.Signal)
   117  	doneSignal := make(chan int, 1)
   118  
   119  	go waitForInterrupts(nil, abortSignal, doneSignal, nil)
   120  
   121  	// Add self-volume to docker
   122  	if c.RunnerSettings.Docker == nil {
   123  		c.RunnerSettings.Docker = &common.DockerConfig{}
   124  	}
   125  	c.RunnerSettings.Docker.Volumes = append(c.RunnerSettings.Docker.Volumes, wd+":"+wd+":ro")
   126  
   127  	// Create build
   128  	build, err := c.createBuild(wd, abortSignal)
   129  	if err != nil {
   130  		logrus.Fatalln(err)
   131  	}
   132  
   133  	parser := gitlab_ci_yaml_parser.NewGitLabCiYamlParser(c.Job)
   134  	err = parser.ParseYaml(&build.JobResponse)
   135  	if err != nil {
   136  		logrus.Fatalln(err)
   137  	}
   138  
   139  	err = build.Run(&common.Config{}, &common.Trace{Writer: os.Stdout})
   140  	if err != nil {
   141  		logrus.Fatalln(err)
   142  	}
   143  }
   144  
   145  func init() {
   146  	cmd := &ExecCommand{}
   147  
   148  	flags := clihelpers.GetFlagsFromStruct(cmd)
   149  	cliCmd := cli.Command{
   150  		Name:  "exec",
   151  		Usage: "execute a build locally",
   152  	}
   153  
   154  	for _, executor := range common.GetExecutors() {
   155  		subCmd := cli.Command{
   156  			Name:   executor,
   157  			Usage:  "use " + executor + " executor",
   158  			Action: cmd.Execute,
   159  			Flags:  flags,
   160  		}
   161  		cliCmd.Subcommands = append(cliCmd.Subcommands, subCmd)
   162  	}
   163  
   164  	common.RegisterCommand(cliCmd)
   165  }