// 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 main import ( "errors" "fmt" "log" "os" "os/exec" "path/filepath" "strings" "github.com/kelseyhightower/envconfig" "github.com/appleboy/drone-git-push/repo" ) // Args provides plugin execution arguments. type Args struct { Folder string `required:"true" envconfig:"INPUT_FOLDER"` RemoteFolder string `envconfig:"INPUT_REMOTE_FOLDER" default:"/"` SshKey string `envconfig:"INPUT_SSH_KEY"` GitRemote string `envconfig:"INPUT_GIT_REMOTE"` GitBranch string `envconfig:"INPUT_GIT_BRANCH"` GitName string `envconfig:"INPUT_GIT_NAME" default:"[BOT] pages deployer"` GitEmail string `envconfig:"INPUT_GIT_EMAIL" default:"noreply@pages.bot"` Token string `envconfig:"INPUT_TOKEN"` Username string `envconfig:"INPUT_USERNAME"` Force bool `envconfig:"INPUT_FORCE" default:"false"` GithubToken string `envconfig:"GITHUB_TOKEN"` GithubTokenActor string `envconfig:"GITHUB_ACTOR"` GithubRepository string `envconfig:"GITHUB_REPOSITORY"` GithubServerUrl string `envconfig:"GITHUB_SERVER_URL"` } const BRANCH_NAME = "pages" func main() { var args Args if err := envconfig.Process("", &args); err != nil { log.Fatalln(err) } if err := Exec(args); err != nil { log.Fatalln(err) } } // Exec executes the plugin. func Exec(args Args) error { if err := checkArgs(&args); err != nil { return err } if args.SshKey != "" { if err := repo.WriteKey(strings.ReplaceAll(args.SshKey, "\\n", "\n") + "\n"); err != nil { return err } } else { var err error args.GitRemote, err = repo.WriteToken(args.GitRemote, args.Username, args.Token) if err != nil { return err } } if err := cleanTempDir(); err != nil { return err } if args.Force { if err := initRepo(args); err != nil { return err } } else { if err := cloneRepo(args); err != nil { return err } } if err := copyFiles(args); err != nil { return err } if err := writeConfig(args); err != nil { return err } if err := doCommit(args); err != nil { return err } if err := push(args); err != nil { return err } // write code here return nil } func checkArgs(args *Args) error { if args.Token == "" && args.GithubToken != "" { args.Token = args.GithubToken } if args.Username == "" && args.GithubTokenActor != "" { args.Username = args.GithubTokenActor } if (args.Token == "" || args.Username == "") && args.SshKey == "" { return errors.New("(INPUT_TOKEN and INPUT_USERNAME) or INPUT_SSH_KEY is required!") } if folderInfo, err := os.Stat(args.Folder); os.IsNotExist(err) || !folderInfo.IsDir() { return errors.New("INPUT_FOLDER is not a folder!") } if args.GitRemote == "" && (args.GithubServerUrl == "" || args.GithubRepository == "") { return errors.New("INPUT_GIT_REMOTE is required!") } if args.GitRemote == "" { args.GitRemote = fmt.Sprintf("%s/%s.git", args.GithubServerUrl, args.GithubRepository) } if args.GitBranch == "" { args.GitBranch = BRANCH_NAME } folder, err := filepath.Abs(args.Folder) if err != nil { return err } args.Folder = folder _, err = os.Stat(args.Folder) if err != nil { return err } return nil } func writeConfig(args Args) error { if err := execute(exec.Command("git", "config", "user.name", args.GitName)); err != nil { return err } if err := execute(exec.Command("git", "config", "user.email", args.GitEmail)); err != nil { return err } return nil } func cleanTempDir() error { if err := os.RemoveAll("/tmp/pages"); err != nil { return err } if err := os.MkdirAll("/tmp", 777); err != nil { return err } return nil } func copyFiles(args Args) error { if args.Folder[len(args.Folder)-1:] != "/" { args.Folder += "/" } if args.RemoteFolder[:1] != "/" { args.RemoteFolder = "/" + args.RemoteFolder } cmd := exec.Command("rsync", "-av", args.Folder, "/tmp/pages"+args.RemoteFolder, "--exclude", ".git", "--ignore-times", "--delete") if err := execute(cmd); err != nil { return err } if err := os.Chown("/tmp/pages", os.Getuid(), os.Getgid()); err != nil { return err } return nil } func initRepo(args Args) error { cmd := exec.Command( "git", "init", "-b", args.GitBranch, "/tmp/pages") if err := execute(cmd); err != nil { return err } return os.Chdir("/tmp/pages") } func cloneRepo(args Args) error { cmd := exec.Command( "git", "clone", args.GitRemote, "/tmp/pages") if err := execute(cmd); err != nil { return err } // check if branch exists and create if not cmd = exec.Command( "git", "ls-remote", "--heads", args.GitRemote, args.GitBranch) out, err := cmd.Output() if err != nil { return err } fmt.Println("remote branch: ", string(out)) if err := os.Chdir("/tmp/pages"); err != nil { return err } if len(out) == 0 { cmd = exec.Command( "git", "checkout", "-b", args.GitBranch) } else { cmd = exec.Command( "git", "checkout", args.GitBranch) } if err := execute(cmd); err != nil { return err } return nil } func doCommit(args Args) error { if err := execute(repo.Add()); err != nil { return err } if err := execute(repo.ForceCommit("Update pages 🚀", true, args.GitName, args.GitEmail)); err != nil { return err } return nil } func push(args Args) error { return execute(repo.RemotePushNamedBranch(args.GitRemote, args.GitBranch, args.GitBranch, args.Force, false)) } func execute(cmd *exec.Cmd) error { fmt.Println("+", strings.Join(cmd.Args, " ")) cmd.Env = os.Environ() cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin return cmd.Run() }