diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e557ac --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +codeberg-pages-deploy \ No newline at end of file diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..48fe6cc --- /dev/null +++ b/action.yml @@ -0,0 +1,24 @@ +name: "Codeberg pages deploy" +description: 'A drone plugin to deploy to codeberg pages. Basically takes a folder and pushes it to the "pages" branch in the same repo.' +runs: + using: "go" + main: "main.go" +inputs: + folder: + description: "The folder to deploy" + required: true + ssh_key: + description: "The private ssh key to use if pushing to an ssh remote" + required: false + git_remote: + description: "A custom git remote to push to" + required: false + git_branch: + description: "The branch to push to" + required: false + token: + description: "The token/password to use if pusing to a custom http remote" + required: false + username: + description: "The username to use if pusing to a custom http remote" + required: false diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6af4c49 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module codeberg-pages-deploy + +go 1.21.0 + +require github.com/appleboy/drone-git-push v1.0.5 + +require github.com/kelseyhightower/envconfig v1.4.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..75c778f --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/appleboy/drone-git-push v1.0.5 h1:2ndC+lcFpsbnaIt9dZ0acniewJnSAh6SOqDTiCAi4N8= +github.com/appleboy/drone-git-push v1.0.5/go.mod h1:A71Q1/0OVhVe872aipwdVrpcCyz2VxhspfZN1nAUZWg= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= diff --git a/main.go b/main.go new file mode 100644 index 0000000..66a1baa --- /dev/null +++ b/main.go @@ -0,0 +1,194 @@ +// 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:"INPUTS_FOLDER"` + SshKey string `envconfig:"INPUTS_SSH_KEY"` + GitRemote string `envconfig:"INPUTS_GIT_REMOTE"` + GitBranch string `envconfig:"INPUTS_GIT_BRANCH"` + Token string `envconfig:"INPUTS_TOKEN"` + Username string `envconfig:"INPUTS_USERNAME"` + + 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 := writeConfig(args); err != nil { + return err + } + + if err := copyFiles(args); err != nil { + return err + } + + if err := initRepo(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("(INPUTS_TOKEN and INPUTS_USERNAME) or INPUTS_SSH_KEY is required!") + } + + if folderInfo, err := os.Stat(args.Folder); os.IsNotExist(err) || !folderInfo.IsDir() { + return errors.New("INPUTS_FOLDER is not a folder!") + } + + if args.GitRemote == "" && (args.GithubServerUrl == "" || args.GithubRepository == "") { + return errors.New("INPUTS_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 + } + + return nil +} + +func writeConfig(args Args) error { + if err := repo.GlobalName("[BOT] pages deployer").Run(); err != nil { + return err + } + + if err := repo.GlobalUser("noreply@pages.bot").Run(); err != nil { + return err + } + + return nil +} + +func copyFiles(args Args) error { + if err := os.MkdirAll("/tmp", 777); err != nil { + return err + } + + folder, err := filepath.Abs(args.Folder) + if err != nil { + return err + } + + cmd := exec.Command("cp", "-r", folder, "/tmp/pages") + if err := execute(cmd); err != nil { + return err + } + + if err := os.Chown("/tmp/pages", os.Getuid(), os.Getgid()); err != nil { + return err + } + + return os.Chdir("/tmp/pages") +} + +func initRepo(args Args) error { + cmd := exec.Command( + "git", + "init", "-b", args.GitBranch, "/tmp/pages") + + 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, "[BOT] pages deployer", "noreply@pages.bot")); err != nil { + return err + } + + return nil +} + +func push(args Args) error { + return execute(repo.RemotePushNamedBranch(args.GitRemote, args.GitBranch, args.GitBranch, true, 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() +}