2022-08-08 12:24:26 +02:00
|
|
|
// Copyright 2020 the Drone Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by the Blue Oak Model License
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package plugin
|
|
|
|
|
2022-08-08 14:31:05 +02:00
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/go-github/v45/github"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"golang.org/x/oauth2"
|
|
|
|
)
|
2022-08-08 12:24:26 +02:00
|
|
|
|
|
|
|
// Args provides plugin execution arguments.
|
|
|
|
type Args struct {
|
|
|
|
Pipeline
|
|
|
|
|
|
|
|
// Level defines the plugin log level.
|
|
|
|
Level string `envconfig:"PLUGIN_LOG_LEVEL"`
|
|
|
|
|
2022-08-08 14:31:05 +02:00
|
|
|
GithubToken string `envconfig:"PLUGIN_GITHUB_TOKEN"`
|
|
|
|
GithubRepo string `envconfig:"PLUGIN_GITHUB_REPO"`
|
|
|
|
|
|
|
|
WorkflowId string `envconfig:"PLUGIN_WORKFLOW_ID"`
|
|
|
|
WorkflowActions string `envconfig:"PLUGIN_WORKFLOW_ACTIONS"`
|
2022-08-08 12:24:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exec executes the plugin.
|
|
|
|
func Exec(ctx context.Context, args Args) error {
|
|
|
|
// write code here
|
2022-08-08 14:31:05 +02:00
|
|
|
ts := oauth2.StaticTokenSource(
|
|
|
|
&oauth2.Token{AccessToken: args.GithubToken},
|
|
|
|
)
|
|
|
|
tc := oauth2.NewClient(ctx, ts)
|
|
|
|
|
|
|
|
client := github.NewClient(tc)
|
|
|
|
|
|
|
|
repos, _, err := client.Repositories.List(ctx, "", nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
repoExists := false
|
|
|
|
for _, repo := range repos {
|
|
|
|
if repo.GetFullName() == args.GithubRepo {
|
|
|
|
repoExists = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !repoExists {
|
|
|
|
return fmt.Errorf("repo '%s' does not exist or you don't have permission to use it!\n", args.GithubRepo)
|
|
|
|
}
|
|
|
|
|
|
|
|
// split the workflow actions into an array
|
|
|
|
actions := strings.Split(args.WorkflowActions, ",")
|
|
|
|
logrus.Debugln("Actions: ", actions)
|
|
|
|
|
|
|
|
// execute the workflow actions
|
|
|
|
for _, action := range actions {
|
|
|
|
err := executeWorkflowAction(action, ctx, args, client)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func executeWorkflowAction(action string, ctx context.Context, args Args, client *github.Client) error {
|
|
|
|
// check which action to execute
|
|
|
|
if action == "start" {
|
|
|
|
// extract owner and repo from github repo
|
|
|
|
owner, repo := parseGithubRepo(args.GithubRepo)
|
|
|
|
|
|
|
|
// list all workflow runs
|
|
|
|
runs, _, err := client.Actions.ListWorkflowRunsByFileName(ctx, owner, repo, args.WorkflowId, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if workflow is already running
|
|
|
|
runExists := false
|
|
|
|
for _, run := range runs.WorkflowRuns {
|
|
|
|
logrus.Debugln("Checking run", run.GetCreatedAt(), run.GetStatus())
|
|
|
|
if contains([]string{"in_progress", "queued", "requested", "waiting"}, run.GetStatus()) {
|
|
|
|
runExists = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if runExists {
|
|
|
|
logrus.Debugln("Workflow is already running, nothing to do!")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a new workflow dispatch event
|
|
|
|
resp, err := client.Actions.CreateWorkflowDispatchEventByFileName(ctx, owner, repo, args.WorkflowId, github.CreateWorkflowDispatchEventRequest{Ref: "main"})
|
|
|
|
|
|
|
|
logrus.Debugln("Got response", resp)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else if action == "cancel" {
|
|
|
|
// extract owner and repo from github repo
|
|
|
|
owner, repo := parseGithubRepo(args.GithubRepo)
|
|
|
|
|
|
|
|
// list workflow runs
|
|
|
|
runs, _, err := client.Actions.ListWorkflowRunsByFileName(ctx, owner, repo, args.WorkflowId, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// calcel all running workflow runs
|
|
|
|
for _, run := range runs.WorkflowRuns {
|
|
|
|
logrus.Debugln("Checking run", run.GetCreatedAt(), run.GetStatus())
|
|
|
|
if contains([]string{"in_progress", "queued", "requested", "waiting"}, run.GetStatus()) {
|
|
|
|
logrus.Infoln("Cancelling run: ", run.GetID())
|
|
|
|
|
|
|
|
resp, err := client.Actions.CancelWorkflowRunByID(ctx, owner, repo, run.GetID())
|
|
|
|
logrus.Debugln("Got response", resp)
|
|
|
|
if err != nil && err.Error() != "job scheduled on GitHub side; try again later" {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = waitForRunStatus(ctx, client, owner, repo, run.GetID(), []string{"completed", "cancelled"})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if action == "delete" {
|
|
|
|
// extract owner and repo from github repo
|
|
|
|
owner, repo := parseGithubRepo(args.GithubRepo)
|
|
|
|
|
|
|
|
// list workflow runs
|
|
|
|
runs, _, err := client.Actions.ListWorkflowRunsByFileName(ctx, owner, repo, args.WorkflowId, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete all completed workflow runs
|
|
|
|
for _, run := range runs.WorkflowRuns {
|
|
|
|
logrus.Debugln("Checking run", run.GetCreatedAt(), run.GetStatus())
|
|
|
|
if contains([]string{"completed", "cancelled", "failure", "skipped", "success", "timed_out"}, run.GetStatus()) {
|
|
|
|
logrus.Infoln("Deleting run: ", run.GetID())
|
|
|
|
_, err := client.Actions.DeleteWorkflowRun(ctx, owner, repo, run.GetID())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return fmt.Errorf("unknown action '%s'\n", action)
|
|
|
|
}
|
|
|
|
|
2022-08-08 12:24:26 +02:00
|
|
|
return nil
|
|
|
|
}
|
2022-08-08 14:31:05 +02:00
|
|
|
|
|
|
|
func parseGithubRepo(repo string) (string, string) {
|
|
|
|
parts := strings.Split(repo, "/")
|
|
|
|
return parts[0], parts[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
func waitForRunStatus(ctx context.Context, client *github.Client, owner string, repo string, runId int64, status []string) error {
|
|
|
|
for {
|
|
|
|
run, _, err := client.Actions.GetWorkflowRunByID(ctx, owner, repo, runId)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
logrus.Debugln("Checking run", run.GetCreatedAt(), run.GetStatus())
|
|
|
|
if contains(status, run.GetStatus()) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func contains(slice []string, item string) bool {
|
|
|
|
for _, s := range slice {
|
|
|
|
if s == item {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|