//LoadLastUpdate loads the last update func LoadLastUpdate(fname string) (Update, error) { file, err := ioutil.ReadFile(fname) log.Infof("opening file: \"%s\"...", fname) if err != nil { log.Warnf("error occured opening file: \"%s\" ...", fname) log.Warnf(err.Error()) log.Warnf("continue the process with the new settings") update := Update{ Time: time.Date(1970, time.November, 10, 15, 0, 0, 0, time.Local), Succeeded: true, Status: "inprogress"} return update, nil } log.Infof("loading last update form \"%s\"\n", string(file)) var update Update if err := json.Unmarshal(file, &update); err != nil { log.Warnf("failed to load \"%s\" ...", fname) log.Warnf(err.Error()) log.Warnf("continue the process with the new settings") update := Update{ Time: time.Now(), Succeeded: true, Status: "inprogress"} return update, nil } if update.Status == "inprogress" { return Update{}, errors.New("update is currently run in another process") } log.Info("setting update status into \"inprogress\"...") return update, nil }
func (e *Walter) runService() bool { // load .walter-update log.Infof("Loading update file... \"%s\"", e.Engine.Resources.RepoService.GetUpdateFilePath()) update, err := services.LoadLastUpdate(e.Engine.Resources.RepoService.GetUpdateFilePath()) log.Infof("Succeeded loading update file") log.Info("Updating status...") update.Status = "inprogress" result := services.SaveLastUpdate(e.Engine.Resources.RepoService.GetUpdateFilePath(), update) if result == false { log.Error("Failed to save status update") return false } log.Info("Succeeded updating status") // get latest commit and pull requests log.Info("downloading commits and pull requests...") commits, err := e.Engine.Resources.RepoService.GetCommits(update) if err != nil { log.Errorf("Failed getting commits: %s", err) return false } log.Info("Succeeded getting commits") log.Info("Size of commits: " + strconv.Itoa(commits.Len())) hasFailedProcess := false for commit := commits.Front(); commit != nil; commit = commit.Next() { commitType := reflect.TypeOf(commit.Value) if commitType.Name() == "RepositoryCommit" { log.Info("Found new repository commit") trunkCommit := commit.Value.(github.RepositoryCommit) if result := e.processTrunkCommit(trunkCommit); result == false { hasFailedProcess = true } } else if commitType.Name() == "PullRequest" { log.Info("Found new pull request commit") pullreq := commit.Value.(github.PullRequest) if result := e.processPullRequest(pullreq); result == false { hasFailedProcess = true } } else { log.Errorf("Nothing commit type: %s", commitType) hasFailedProcess = true } } // save .walter-update log.Info("Saving update file...") update.Status = "finished" update.Time = time.Now() result = services.SaveLastUpdate(e.Engine.Resources.RepoService.GetUpdateFilePath(), update) if result == false { log.Error("Failed to save update") return false } return !hasFailedProcess }
func (e *Engine) executePipeline(pipeline *pipelines.Pipeline, name string) stages.Mediator { log.Infof("Preparing to run %s process...", name) var mediator stages.Mediator for stageItem := pipeline.Stages.Front(); stageItem != nil; stageItem = stageItem.Next() { log.Debugf("Executing planned stage: %s\n", stageItem.Value) mediator = e.Execute(stageItem.Value.(stages.Stage), mediator) } log.Infof("Finished running %s process...", name) return mediator }
// Run exectues specified shell script. func (shellScriptStage *ShellScriptStage) Run() bool { log.Infof("[shell] exec: %s", shellScriptStage.BaseStage.StageName) log.Debugf("[shell] specified file: %s\n", shellScriptStage.File) if shellScriptStage.preCheck() == false { log.Infof("failed preCheck before running script...") return false } shellScriptStage.AddCommand("sh " + shellScriptStage.File) return shellScriptStage.CommandStage.Run() }
func (commandStage *CommandStage) runOnlyIf() bool { if commandStage.OnlyIf == "" { return true } log.Infof("[command] only_if: found \"only_if\" attribute in stage \"%s\"", commandStage.BaseStage.StageName) cmd := exec.Command("sh", "-c", commandStage.OnlyIf) log.Infof("[command] only_if: %s", commandStage.BaseStage.StageName) log.Debugf("[command] only_if literal: %s", commandStage.OnlyIf) cmd.Dir = commandStage.Directory result, _, _ := execCommand(cmd, "only_if", commandStage.BaseStage.StageName) return result }
//Post posts a message to slack func (slack *Slack) Post(message string, c ...string) bool { if slack.Channel[0] != '#' { log.Infof("Add # to channel name: %s", slack.Channel) slack.Channel = "#" + slack.Channel } var color string if len(c) > 0 { color = c[0] } if strings.Contains(message, "[RESULT] Failed") { color = "danger" } else if strings.Contains(message, "[RESULT] Skipped") { color = "warning" } else if strings.Contains(message, "[RESULT] Succeeded") { color = "good" } attachment := map[string]string{ "text": message, "color": color, } attachments := []map[string]string{attachment} params, _ := json.Marshal(struct { FakeSlack Attachments []map[string]string `json:"attachments"` }{ FakeSlack: FakeSlack(*slack), Attachments: attachments, }) resp, err := http.PostForm( slack.IncomingURL, url.Values{"payload": {string(params)}}, ) if err != nil { log.Errorf("Failed post message to Slack...: %s", message) return false } defer resp.Body.Close() if body, err := ioutil.ReadAll(resp.Body); err == nil { log.Infof("Slack post result...: %s", body) return true } log.Errorf("Failed to read result from Slack...") return false }
//GetCommits get a list of all the commits for the current update func (githubClient *GitHubClient) GetCommits(update Update) (*list.List, error) { log.Info("getting commits\n") commits := list.New() ts := oauth2.StaticTokenSource( &oauth2.Token{AccessToken: githubClient.Token}, ) tc := oauth2.NewClient(oauth2.NoContext, ts) client := github.NewClient(tc) // get a list of pull requests with Pull Request API pullreqs, _, err := client.PullRequests.List( githubClient.From, githubClient.Repo, &github.PullRequestListOptions{}) if err != nil { log.Errorf("Failed to get pull requests") return list.New(), err } re, err := regexp.Compile(githubClient.TargetBranch) if err != nil { log.Error("Failed to compile branch pattern...") return list.New(), err } log.Infof("Size of pull reqests: %d", len(pullreqs)) for _, pullreq := range pullreqs { log.Infof("Branch name is \"%s\"", *pullreq.Head.Ref) if githubClient.TargetBranch != "" { matched := re.Match([]byte(*pullreq.Head.Ref)) if matched != true { log.Infof("Not add a branch, \"%s\" since this branch name is not match the filtering pattern", *pullreq.Head.Ref) continue } } if *pullreq.State == "open" && pullreq.UpdatedAt.After(update.Time) { log.Infof("Adding pullrequest %d", *pullreq.Number) commits.PushBack(pullreq) } } // get the latest commit with Commit API if the commit is newer than last update masterCommits, _, _ := client.Repositories.ListCommits( githubClient.From, githubClient.Repo, &github.CommitsListOptions{}) if masterCommits[0].Commit.Author.Date.After(update.Time) { commits.PushBack(masterCommits[0]) } return commits, nil }
// New creates a Walter instance. func New(opts *config.Opts) (*Walter, error) { log.Infof("Pipeline file path: \"%s\"", opts.PipelineFilePath) configData, err := config.ReadConfig(opts.PipelineFilePath) if err != nil { log.Warn("failed to read the configuration file") return nil, err } envs := config.NewEnvVariables() parser := &config.Parser{ConfigData: configData, EnvVariables: envs} resources, err := parser.Parse() if err != nil { log.Warn("failed to parse the configuration") return nil, err } monitorCh := make(chan stages.Mediator) engine := &engine.Engine{ Resources: resources, Opts: opts, MonitorCh: &monitorCh, EnvVariables: envs, } return &Walter{ Opts: opts, Engine: engine, }, nil }
//RegisterResult registers the supplied result func (githubClient *GitHubClient) RegisterResult(result Result) error { ts := oauth2.StaticTokenSource( &oauth2.Token{AccessToken: githubClient.Token}, ) tc := oauth2.NewClient(oauth2.NoContext, ts) client := github.NewClient(tc) if githubClient.BaseUrl != nil { client.BaseURL = githubClient.BaseUrl } log.Info("Submitting result") repositories := client.Repositories status, _, err := repositories.CreateStatus( githubClient.From, githubClient.Repo, result.SHA, &github.RepoStatus{ State: github.String(result.State), TargetURL: github.String(result.Url), Description: github.String(result.Message), Context: github.String("continuous-integraion/walter"), }) log.Infof("Submit status: %s", status) if err != nil { log.Errorf("Failed to register result: %s", err) } return err }
func printOutput(r io.Reader, prefix string, name string, out chan string, done chan bool) { scanner := bufio.NewScanner(r) for scanner.Scan() { log.Infof("[%s][command] %s output: %s", name, prefix, scanner.Text()) out <- fmt.Sprintf("%s\n", scanner.Text()) } done <- true }
func (commandStage *CommandStage) runCommand() bool { cmd := exec.Command("sh", "-c", commandStage.Command) log.Infof("[command] exec: %s", commandStage.BaseStage.StageName) log.Debugf("[command] exec command literal: %s", commandStage.Command) cmd.Dir = commandStage.Directory result, outResult, errResult := execCommand(cmd, "exec", commandStage.BaseStage.StageName) commandStage.SetOutResult(*outResult) commandStage.SetErrResult(*errResult) return result }
func (e *Walter) processTrunkCommit(commit github.RepositoryCommit) bool { log.Infof("Checkout master branch") _, err := exec.Command("git", "checkout", "master", "-f").Output() if err != nil { log.Errorf("Failed to checkout master branch: %s", err) return false } log.Infof("Downloading new commit from master") _, err = exec.Command("git", "pull", "origin", "master").Output() if err != nil { log.Errorf("Failed to download new commit from master: %s", err) return false } log.Infof("Running the latest commit in master") w, err := New(e.Opts) if err != nil { log.Errorf("Failed to create Walter object...: %s", err) log.Error("Skip execution...") return false } result := w.Engine.RunOnce() // register the result to hosting service if result.IsSucceeded() { log.Info("Succeeded.") e.Engine.Resources.RepoService.RegisterResult( services.Result{ State: "success", Message: "Succeeded running pipeline...", SHA: *commit.SHA}) return true } log.Error("Error reported...") e.Engine.Resources.RepoService.RegisterResult( services.Result{ State: "failure", Message: "Failed running pipleline ...", SHA: *commit.SHA}) return false }
func (commandStage *CommandStage) runCommand() bool { cmd := exec.Command("sh", "-c", commandStage.Command) log.Infof("[command] exec: %s", commandStage.BaseStage.StageName) log.Debugf("[command] exec command literal: %s", commandStage.Command) cmd.Dir = commandStage.Directory commandStage.SetStart(time.Now().Unix()) result, outResult, errResult, combinedResult := execCommand(cmd, "exec", commandStage.BaseStage.StageName) commandStage.SetEnd(time.Now().Unix()) commandStage.SetOutResult(*outResult) commandStage.SetErrResult(*errResult) commandStage.SetCombinedResult(*combinedResult) commandStage.SetReturnValue(result) return result }
//SaveLastUpdate saves the supplied update to the filename func SaveLastUpdate(fname string, update Update) bool { log.Infof("writing down new update: \"%s\"\n", string(fname)) bytes, err := json.Marshal(update) if err != nil { log.Errorf("failed to convert update to string...: %s\n", err) return false } if exist := fileExists(fname); exist == true { log.Infof("file exist: \"%s\"", fname) if err := os.Remove(fname); err != nil { log.Errorf("failed to remove \"%s\" with error: \"%s\"", fname, err) return false } log.Infof("succeeded to remove: \"%s\"", fname) } if err := ioutil.WriteFile(fname, bytes, 0644); err != nil { log.Errorf("failed to write update to file...: \"%s\"\n", err) return false } log.Infof("succeeded to write update file: \"%s\"", fname) return true }
func printOutput(r io.Reader, prefix string, name string, out chan string, done chan bool) { reader := bufio.NewReaderSize(r, 1048576) for { line, _, err := reader.ReadLine() if err == io.EOF { break } else if err != nil { log.Error(err.Error()) os.Exit(1) } log.Infof("[%s][command] %s output: %s", name, prefix, string(line)) out <- fmt.Sprintf("%s\n", string(line)) } done <- true }
func copyStream(reader io.Reader, prefix string, name string) string { var err error var n int var buffer bytes.Buffer tmpBuf := make([]byte, 1024) for { if n, err = reader.Read(tmpBuf); err != nil { break } buffer.Write(tmpBuf[0:n]) log.Infof("[%s][command] %s output: %s", name, prefix, tmpBuf[0:n]) } if err == io.EOF { err = nil } else { log.Error("ERROR: " + err.Error()) } return buffer.String() }
//RegisterResult registers the supplied result func (githubClient *GitHubClient) RegisterResult(result Result) error { t := &oauth.Transport{ Token: &oauth.Token{AccessToken: githubClient.Token}, } client := github.NewClient(t.Client()) log.Info("Submitting result") repositories := client.Repositories status, _, err := repositories.CreateStatus( githubClient.From, githubClient.Repo, result.SHA, &github.RepoStatus{ State: github.String(result.State), TargetURL: github.String(result.Url), Description: github.String(result.Message), Context: github.String("continuous-integraion/walter"), }) log.Infof("Submit status: %s", status) if err != nil { log.Errorf("Failed to register result: %s", err) } return err }