mirror of
https://github.com/thegeeklab/wp-git-action.git
synced 2024-11-22 00:00:39 +00:00
refactor: rework plugin structure and add pages action (#7)
This commit is contained in:
parent
686de4edfd
commit
e8c4aad467
@ -3,3 +3,4 @@ github
|
||||
url
|
||||
gh
|
||||
drone-git-action
|
||||
rsync
|
||||
|
@ -24,9 +24,12 @@ kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: commit artifact
|
||||
- name: commit changelog
|
||||
image: thegeeklab/drone-git-action
|
||||
settings:
|
||||
action:
|
||||
- commit
|
||||
- push
|
||||
netrc_password: ghp_3LbMg9Kncpdkhjp3bh3dMnKNXLjVMTsXk4sM
|
||||
author_name: octobot
|
||||
author_email: octobot@example.com
|
||||
@ -41,6 +44,30 @@ steps:
|
||||
<!-- spellchecker-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
### Examples
|
||||
|
||||
#### Publish GitHub pages
|
||||
|
||||
The plugin can be used to publish GitHub pages to the pages branch. Remember that the `pages` action cannot be combined with other actions.
|
||||
|
||||
```YAML
|
||||
kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: publish
|
||||
image: thegeeklab/drone-git-action
|
||||
settings:
|
||||
action:
|
||||
- pages
|
||||
author_email: bot@thegeeklab.de
|
||||
author_name: thegeeklab-bot
|
||||
message: "update pages"
|
||||
branch: gh-pages
|
||||
pages_directory: docs/
|
||||
netrc_password: ghp_3LbMg9Kncpdkhjp3bh3dMnKNXLjVMTsXk4sM
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
Build the binary with the following command:
|
||||
|
@ -1,7 +1,14 @@
|
||||
---
|
||||
properties:
|
||||
- name: actions
|
||||
description: "Git actions to to execute. Supported actions: `clone|commit|push`."
|
||||
- name: action
|
||||
description: |
|
||||
Git actions to be executed. Supported actions: `clone | commit | push | pages`. Specified actions are executed in the specified order
|
||||
|
||||
- **clone:** Clones the repository in `remote` and checks out the `branch` to `path`.
|
||||
- **commit:** Adds a commit to the default drone repository or the repository in `remote`.
|
||||
- **push:** Pushes all commits to the default drone repository or the repository set in `remote`.
|
||||
- **pages:** The `pages` action is a special action that cannot be combined with other actions. It is intended for use for
|
||||
GitHub pages. It synchronizes the contents of `pages_directory` with the target `branch` using `rsync` and pushes the changes automatically.
|
||||
required: true
|
||||
type: list
|
||||
|
||||
@ -43,7 +50,7 @@ properties:
|
||||
type: string
|
||||
|
||||
- name: path
|
||||
description: Path to git repository.
|
||||
description: Path to clone the git repository.
|
||||
type: string
|
||||
|
||||
- name: message
|
||||
@ -75,3 +82,17 @@ properties:
|
||||
description: Bypass the pre-commit and commit-msg hooks.
|
||||
defaultvalue: false
|
||||
type: bool
|
||||
|
||||
- name: pages_directory
|
||||
description: Source directory to be synchronized with the pages `branch`.
|
||||
defaultvalue: docs/
|
||||
type: string
|
||||
|
||||
- name: pages_exclude
|
||||
description: Files or directories to exclude from the rsync command.
|
||||
type: list
|
||||
|
||||
- name: pages_delete
|
||||
description: When set to `true`, the `--delete` flag is added to the rsync command to remove files from the `branch` that do not exist in the `pages_directory` either.
|
||||
defaultvalue: true
|
||||
type: bool
|
||||
|
@ -9,33 +9,32 @@ import (
|
||||
func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "actions",
|
||||
Usage: "git actions to to execute",
|
||||
EnvVars: []string{"PLUGIN_ACTIONS"},
|
||||
Destination: &settings.Actions,
|
||||
Name: "action",
|
||||
Usage: "git action to to execute",
|
||||
EnvVars: []string{"PLUGIN_ACTION"},
|
||||
Destination: &settings.Action,
|
||||
Required: true,
|
||||
Category: category,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "commit-author-name",
|
||||
Name: "author-name",
|
||||
Usage: "git author name",
|
||||
EnvVars: []string{"PLUGIN_AUTHOR_NAME", "DRONE_COMMIT_AUTHOR"},
|
||||
Destination: &settings.Commit.Author.Name,
|
||||
Destination: &settings.Repo.Author.Name,
|
||||
Required: true,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "commit-author-email",
|
||||
Name: "author-email",
|
||||
Usage: "git author email",
|
||||
EnvVars: []string{"PLUGIN_AUTHOR_EMAIL", "DRONE_COMMIT_AUTHOR_EMAIL"},
|
||||
Destination: &settings.Commit.Author.Email,
|
||||
Destination: &settings.Repo.Author.Email,
|
||||
Required: true,
|
||||
Category: category,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "netrc-machine",
|
||||
Name: "netrc.machine",
|
||||
Usage: "netrc remote machine name",
|
||||
EnvVars: []string{"PLUGIN_NETRC_MACHINE", "DRONE_NETRC_MACHINE"},
|
||||
Destination: &settings.Netrc.Machine,
|
||||
@ -43,7 +42,7 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "netrc-username",
|
||||
Name: "netrc.username",
|
||||
Usage: "netrc login user on the remote machine",
|
||||
EnvVars: []string{"PLUGIN_NETRC_USERNAME", "DRONE_NETRC_USERNAME"},
|
||||
Destination: &settings.Netrc.Login,
|
||||
@ -51,7 +50,7 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "netrc-password",
|
||||
Name: "netrc.password",
|
||||
Usage: "netrc login password on the remote machine",
|
||||
EnvVars: []string{"PLUGIN_NETRC_PASSWORD", "DRONE_NETRC_PASSWORD"},
|
||||
Destination: &settings.Netrc.Password,
|
||||
@ -68,41 +67,38 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
&cli.StringFlag{
|
||||
Name: "remote",
|
||||
Usage: "url of the remote repository",
|
||||
EnvVars: []string{"PLUGIN_REMOTE"},
|
||||
Destination: &settings.Remote,
|
||||
EnvVars: []string{"PLUGIN_REMOTE", "DRONE_REMOTE_URL"},
|
||||
Destination: &settings.Repo.RemoteURL,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "branch",
|
||||
Usage: "name of the git branch",
|
||||
Usage: "name of the git source branch",
|
||||
EnvVars: []string{"PLUGIN_BRANCH"},
|
||||
Destination: &settings.Branch,
|
||||
Destination: &settings.Repo.Branch,
|
||||
Value: "main",
|
||||
Category: category,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "path",
|
||||
Usage: "path to git repository",
|
||||
Usage: "path to clone git repository",
|
||||
EnvVars: []string{"PLUGIN_PATH"},
|
||||
Destination: &settings.Path,
|
||||
Destination: &settings.Repo.WorkDir,
|
||||
Category: category,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "message",
|
||||
Name: "commit-message",
|
||||
Usage: "commit message",
|
||||
EnvVars: []string{"PLUGIN_MESSAGE"},
|
||||
Destination: &settings.Message,
|
||||
Destination: &settings.Repo.CommitMsg,
|
||||
Value: "[skip ci] commit dirty state",
|
||||
Category: category,
|
||||
},
|
||||
|
||||
&cli.BoolFlag{
|
||||
Name: "force",
|
||||
Name: "force-push",
|
||||
Usage: "enable force push to remote repository",
|
||||
EnvVars: []string{"PLUGIN_FORCE"},
|
||||
Destination: &settings.Force,
|
||||
Destination: &settings.Repo.ForcePush,
|
||||
Value: false,
|
||||
Category: category,
|
||||
},
|
||||
@ -110,7 +106,7 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
Name: "followtags",
|
||||
Usage: "follow tags for pushes to remote repository",
|
||||
EnvVars: []string{"PLUGIN_FOLLOWTAGS"},
|
||||
Destination: &settings.FollowTags,
|
||||
Destination: &settings.Repo.PushFollowTags,
|
||||
Value: false,
|
||||
Category: category,
|
||||
},
|
||||
@ -118,7 +114,7 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
Name: "insecure-ssl-verify",
|
||||
Usage: "set SSL verification of the remote machine",
|
||||
EnvVars: []string{"PLUGIN_INSECURE_SSL_VERIFY"},
|
||||
Destination: &settings.InsecureSSLVerify,
|
||||
Destination: &settings.Repo.InsecureSSLVerify,
|
||||
Value: false,
|
||||
Category: category,
|
||||
},
|
||||
@ -126,7 +122,7 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
Name: "empty-commit",
|
||||
Usage: "allow empty commits",
|
||||
EnvVars: []string{"PLUGIN_EMPTY_COMMIT"},
|
||||
Destination: &settings.EmptyCommit,
|
||||
Destination: &settings.Repo.EmptyCommit,
|
||||
Value: false,
|
||||
Category: category,
|
||||
},
|
||||
@ -134,9 +130,32 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
Name: "no-verify",
|
||||
Usage: "bypass the pre-commit and commit-msg hooks",
|
||||
EnvVars: []string{"PLUGIN_NO_VERIFY"},
|
||||
Destination: &settings.NoVerify,
|
||||
Destination: &settings.Repo.NoVerify,
|
||||
Value: false,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pages.directory",
|
||||
Usage: "source directory for pages sync",
|
||||
EnvVars: []string{"PLUGIN_PAGES_DIRECTORY"},
|
||||
Destination: &settings.Pages.Directory,
|
||||
Value: "docs/",
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "pages.exclude",
|
||||
Usage: "exclude flag added to pages rsnyc command",
|
||||
EnvVars: []string{"PLUGIN_PAGES_EXCLUDE"},
|
||||
Destination: &settings.Pages.Exclude,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "pages.delete",
|
||||
Usage: "delete flag added to pages rsync command",
|
||||
EnvVars: []string{"PLUGIN_PAGES_DELETE"},
|
||||
Destination: &settings.Pages.Delete,
|
||||
Value: true,
|
||||
Category: category,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ LABEL org.opencontainers.image.url="https://github.com/thegeeklab/drone-git-acti
|
||||
LABEL org.opencontainers.image.source="https://github.com/thegeeklab/drone-git-action"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/thegeeklab/drone-git-action"
|
||||
|
||||
RUN apk --update add --no-cache git && \
|
||||
RUN apk --update add --no-cache git rsync && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
rm -rf /tmp/*
|
||||
|
||||
|
@ -7,7 +7,7 @@ LABEL org.opencontainers.image.url="https://github.com/thegeeklab/drone-git-acti
|
||||
LABEL org.opencontainers.image.source="https://github.com/thegeeklab/drone-git-action"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/thegeeklab/drone-git-action"
|
||||
|
||||
RUN apk --update add --no-cache git && \
|
||||
RUN apk --update add --no-cache git rsync && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
rm -rf /tmp/*
|
||||
|
||||
|
@ -7,7 +7,7 @@ LABEL org.opencontainers.image.url="https://github.com/thegeeklab/drone-git-acti
|
||||
LABEL org.opencontainers.image.source="https://github.com/thegeeklab/drone-git-action"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/thegeeklab/drone-git-action"
|
||||
|
||||
RUN apk --update add --no-cache git && \
|
||||
RUN apk --update add --no-cache git rsync && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
rm -rf /tmp/*
|
||||
|
||||
|
35
git/clone.go
Normal file
35
git/clone.go
Normal file
@ -0,0 +1,35 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// FetchSource fetches the source from remote.
|
||||
func FetchSource(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"fetch",
|
||||
"origin",
|
||||
fmt.Sprintf("+%s:", repo.Branch),
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CheckoutHead handles branch checkout.
|
||||
func CheckoutHead(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"checkout",
|
||||
"-qf",
|
||||
repo.Branch,
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
@ -1,74 +1,89 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// ForceAdd forces the addition of all dirty files.
|
||||
func ForceAdd() *exec.Cmd {
|
||||
func ForceAdd(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"add",
|
||||
"--all",
|
||||
"--force")
|
||||
"--force",
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Add updates the index to match the working tree.
|
||||
func Add() *exec.Cmd {
|
||||
func Add(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"add",
|
||||
"--all")
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if repo.Add != "" {
|
||||
cmd.Args = append(cmd.Args, repo.Add)
|
||||
} else {
|
||||
cmd.Args = append(cmd.Args, "--all")
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TestCleanTree returns non-zero if diff between index and local repository
|
||||
func TestCleanTree() *exec.Cmd {
|
||||
func TestCleanTree(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"diff-index",
|
||||
"--quiet",
|
||||
"HEAD",
|
||||
"--ignore-submodules")
|
||||
"--ignore-submodules",
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// EmptyCommit simply create an empty commit
|
||||
func EmptyCommit(msg string, noVerify bool) *exec.Cmd {
|
||||
func EmptyCommit(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"commit",
|
||||
"--allow-empty",
|
||||
"-m",
|
||||
msg,
|
||||
repo.CommitMsg,
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if noVerify {
|
||||
cmd.Args = append(
|
||||
cmd.Args,
|
||||
"--no-verify")
|
||||
if repo.NoVerify {
|
||||
cmd.Args = append(cmd.Args, "--no-verify")
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ForceCommit commits every change while skipping CI.
|
||||
func ForceCommit(msg string, noVerify bool) *exec.Cmd {
|
||||
func ForceCommit(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"commit",
|
||||
"-m",
|
||||
msg,
|
||||
repo.CommitMsg,
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if noVerify {
|
||||
cmd.Args = append(
|
||||
cmd.Args,
|
||||
"--no-verify")
|
||||
if repo.NoVerify {
|
||||
cmd.Args = append(cmd.Args, "--no-verify")
|
||||
}
|
||||
|
||||
return cmd
|
||||
|
@ -1,42 +1,67 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// SetUserEmail sets the global git author email.
|
||||
func SetUserEmail(email string) *exec.Cmd {
|
||||
// repoUserEmail sets the global git author email.
|
||||
func ConfigAutocorrect(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"config",
|
||||
"--local",
|
||||
"help.autocorrect",
|
||||
repo.Autocorrect,
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// repoUserEmail sets the global git author email.
|
||||
func ConfigUserEmail(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"config",
|
||||
"--local",
|
||||
"user.email",
|
||||
email)
|
||||
repo.Author.Email,
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SetUserName sets the global git author name.
|
||||
func SetUserName(author string) *exec.Cmd {
|
||||
// repoUserName sets the global git author name.
|
||||
func ConfigUserName(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"config",
|
||||
"--local",
|
||||
"user.name",
|
||||
author)
|
||||
repo.Author.Name,
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SetSSLSkipVerify disables globally the git ssl verification.
|
||||
func SetSSLVerify(sslVerify bool) *exec.Cmd {
|
||||
// repoSSLVerify disables globally the git ssl verification.
|
||||
func ConfigSSLVerify(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"config",
|
||||
"--local",
|
||||
"http.sslVerify",
|
||||
strconv.FormatBool(sslVerify))
|
||||
strconv.FormatBool(repo.SSLVerify),
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -1,52 +1,59 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// RemoteRemove drops the defined remote from a git repo.
|
||||
func RemoteRemove(name string) *exec.Cmd {
|
||||
func RemoteRemove(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"remote",
|
||||
"rm",
|
||||
name)
|
||||
repo.RemoteName,
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// RemoteAdd adds an additional remote to a git repo.
|
||||
func RemoteAdd(name, url string) *exec.Cmd {
|
||||
func RemoteAdd(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"remote",
|
||||
"add",
|
||||
name,
|
||||
url)
|
||||
repo.RemoteName,
|
||||
repo.RemoteURL,
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// RemotePush pushs the changes from the local head to a remote branch.
|
||||
func RemotePush(remote, branch string, force, followtags bool) *exec.Cmd {
|
||||
return RemotePushNamedBranch(remote, "HEAD", branch, force, followtags)
|
||||
}
|
||||
|
||||
// RemotePushNamedBranch puchs changes from a local to a remote branch.
|
||||
func RemotePushNamedBranch(remote, localbranch, branch string, force, followtags bool) *exec.Cmd {
|
||||
func RemotePush(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"push",
|
||||
remote,
|
||||
localbranch+":"+branch)
|
||||
repo.RemoteName,
|
||||
fmt.Sprintf("HEAD:%s", repo.Branch),
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if force {
|
||||
if repo.ForcePush {
|
||||
cmd.Args = append(
|
||||
cmd.Args,
|
||||
"--force")
|
||||
"--force",
|
||||
)
|
||||
}
|
||||
|
||||
if followtags {
|
||||
if repo.PushFollowTags {
|
||||
cmd.Args = append(
|
||||
cmd.Args,
|
||||
"--follow-tags")
|
||||
|
42
git/status.go
Normal file
42
git/status.go
Normal file
@ -0,0 +1,42 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func Status(repo Repository) *exec.Cmd {
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"status",
|
||||
"--porcelain",
|
||||
)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func IsDirty(repo Repository) bool {
|
||||
res := bytes.NewBufferString("")
|
||||
|
||||
cmd := Status(repo)
|
||||
cmd.Dir = repo.WorkDir
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = res
|
||||
cmd.Stderr = res
|
||||
|
||||
err := runCommand(cmd)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if res.Len() > 0 {
|
||||
fmt.Print(res.String())
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
27
git/type.go
Normal file
27
git/type.go
Normal file
@ -0,0 +1,27 @@
|
||||
package git
|
||||
|
||||
type Author struct {
|
||||
Name string
|
||||
Email string
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
RemoteName string
|
||||
RemoteURL string
|
||||
Branch string
|
||||
|
||||
Add string
|
||||
CommitMsg string
|
||||
|
||||
Autocorrect string
|
||||
NoVerify bool
|
||||
InsecureSSLVerify bool
|
||||
EmptyCommit bool
|
||||
PushFollowTags bool
|
||||
ForcePush bool
|
||||
SSLVerify bool
|
||||
WorkDir string
|
||||
InitExists bool
|
||||
|
||||
Author Author
|
||||
}
|
32
git/utils.go
32
git/utils.go
@ -3,8 +3,10 @@ package git
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const netrcFile = `
|
||||
@ -27,17 +29,13 @@ func WriteSSHKey(privateKey string) error {
|
||||
home = currentUser.HomeDir
|
||||
}
|
||||
|
||||
sshpath := filepath.Join(
|
||||
home,
|
||||
".ssh")
|
||||
sshpath := filepath.Join(home, ".ssh")
|
||||
|
||||
if err := os.MkdirAll(sshpath, 0o700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
confpath := filepath.Join(
|
||||
sshpath,
|
||||
"config")
|
||||
confpath := filepath.Join(sshpath, "config")
|
||||
|
||||
if err := os.WriteFile(
|
||||
confpath,
|
||||
@ -47,10 +45,7 @@ func WriteSSHKey(privateKey string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
privpath := filepath.Join(
|
||||
sshpath,
|
||||
"id_rsa",
|
||||
)
|
||||
privpath := filepath.Join(sshpath, "id_rsa")
|
||||
|
||||
if err := os.WriteFile(
|
||||
privpath,
|
||||
@ -89,3 +84,20 @@ func WriteNetrc(machine, login, password string) error {
|
||||
0o600,
|
||||
)
|
||||
}
|
||||
|
||||
func trace(cmd *exec.Cmd) {
|
||||
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
||||
func runCommand(cmd *exec.Cmd) error {
|
||||
if cmd.Stdout == nil {
|
||||
cmd.Stdout = os.Stdout
|
||||
}
|
||||
|
||||
if cmd.Stderr == nil {
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
|
||||
trace(cmd)
|
||||
return cmd.Run()
|
||||
}
|
||||
|
111
plugin/git.go
111
plugin/git.go
@ -1,111 +0,0 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/thegeeklab/drone-git-action/git"
|
||||
)
|
||||
|
||||
// InitRepo initializes the repository.
|
||||
func (p Plugin) initRepo() error {
|
||||
path := filepath.Join(p.settings.Path, ".git")
|
||||
if err := os.MkdirAll(p.settings.Path, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Chdir(p.settings.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isDirEmpty(path) {
|
||||
return execute(exec.Command(
|
||||
"git",
|
||||
"init",
|
||||
))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRemote adds a remote to repository.
|
||||
func (p Plugin) addRemote() error {
|
||||
if p.settings.Remote != "" {
|
||||
if err := execute(git.RemoteAdd("origin", p.settings.Remote)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FetchSource fetches the source from remote.
|
||||
func (p Plugin) fetchSource() error {
|
||||
return execute(exec.Command(
|
||||
"git",
|
||||
"fetch",
|
||||
"origin",
|
||||
fmt.Sprintf("+%s:", p.settings.Branch),
|
||||
))
|
||||
}
|
||||
|
||||
// CheckoutHead handles branch checkout.
|
||||
func (p Plugin) checkoutHead() error {
|
||||
return execute(exec.Command(
|
||||
"git",
|
||||
"checkout",
|
||||
"-qf",
|
||||
p.settings.Branch,
|
||||
))
|
||||
}
|
||||
|
||||
// HandleClone clones remote.
|
||||
func (p Plugin) handleClone() error {
|
||||
if err := p.addRemote(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.fetchSource(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.checkoutHead(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandleCommit commits changes locally.
|
||||
func (p Plugin) handleCommit() error {
|
||||
if err := execute(git.Add()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := execute(git.TestCleanTree()); err != nil {
|
||||
if err := execute(git.ForceCommit(p.settings.Message, p.settings.NoVerify)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if p.settings.EmptyCommit {
|
||||
if err := execute(git.EmptyCommit(p.settings.Message, p.settings.NoVerify)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandlePush pushs changes to remote.
|
||||
func (p Plugin) handlePush() error {
|
||||
return execute(git.RemotePushNamedBranch(
|
||||
"origin",
|
||||
p.settings.Branch,
|
||||
p.settings.Branch,
|
||||
p.settings.Force,
|
||||
p.settings.FollowTags,
|
||||
))
|
||||
}
|
176
plugin/impl.go
176
plugin/impl.go
@ -3,6 +3,8 @@ package plugin
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/thegeeklab/drone-git-action/git"
|
||||
"github.com/urfave/cli/v2"
|
||||
@ -14,37 +16,38 @@ type Netrc struct {
|
||||
Password string
|
||||
}
|
||||
|
||||
type Commit struct {
|
||||
Author Author
|
||||
}
|
||||
|
||||
type Author struct {
|
||||
Name string
|
||||
Email string
|
||||
type Pages struct {
|
||||
Directory string
|
||||
Exclude cli.StringSlice
|
||||
Delete bool
|
||||
}
|
||||
|
||||
// Settings for the Plugin.
|
||||
type Settings struct {
|
||||
Actions cli.StringSlice
|
||||
Action cli.StringSlice
|
||||
SSHKey string
|
||||
Remote string
|
||||
Branch string
|
||||
Path string
|
||||
Message string
|
||||
Force bool
|
||||
FollowTags bool
|
||||
InsecureSSLVerify bool
|
||||
EmptyCommit bool
|
||||
NoVerify bool
|
||||
|
||||
Netrc Netrc
|
||||
Commit Commit
|
||||
Author Author
|
||||
Pages Pages
|
||||
Repo git.Repository
|
||||
}
|
||||
|
||||
// Validate handles the settings validation of the plugin.
|
||||
func (p *Plugin) Validate() error {
|
||||
for _, action := range p.settings.Actions.Value() {
|
||||
var err error
|
||||
|
||||
p.settings.Repo.Autocorrect = "never"
|
||||
p.settings.Repo.RemoteName = "origin"
|
||||
p.settings.Repo.Add = ""
|
||||
|
||||
if p.settings.Repo.WorkDir == "" {
|
||||
p.settings.Repo.WorkDir, err = os.Getwd()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, action := range p.settings.Action.Value() {
|
||||
switch action {
|
||||
case "clone":
|
||||
continue
|
||||
@ -52,7 +55,30 @@ func (p *Plugin) Validate() error {
|
||||
continue
|
||||
case "push":
|
||||
if p.settings.SSHKey == "" && p.settings.Netrc.Password == "" {
|
||||
return fmt.Errorf("either SSH key or netrc password are required")
|
||||
return fmt.Errorf("either SSH key or netrc password is required")
|
||||
}
|
||||
case "pages":
|
||||
p.settings.Pages.Directory = filepath.Join(p.settings.Repo.WorkDir, p.settings.Pages.Directory)
|
||||
p.settings.Repo.WorkDir = filepath.Join(p.settings.Repo.WorkDir, ".tmp")
|
||||
|
||||
if _, err := os.Stat(p.settings.Pages.Directory); os.IsNotExist(err) {
|
||||
return fmt.Errorf("pages directory '%s' must exist", p.settings.Pages.Directory)
|
||||
}
|
||||
|
||||
if info, _ := os.Stat(p.settings.Pages.Directory); !info.IsDir() {
|
||||
return fmt.Errorf("pages directory '%s' is not a directory", p.settings.Pages.Directory)
|
||||
}
|
||||
|
||||
if p.settings.SSHKey == "" && p.settings.Netrc.Password == "" {
|
||||
return fmt.Errorf("either SSH key or netrc password is required")
|
||||
}
|
||||
|
||||
if p.settings.Pages.Directory == "" {
|
||||
return fmt.Errorf("pages source directory needs to be set")
|
||||
}
|
||||
|
||||
if len(p.settings.Action.Value()) > 1 {
|
||||
return fmt.Errorf("pages action can not be combined with other actions")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown action %s", action)
|
||||
@ -81,19 +107,20 @@ func (p *Plugin) Execute() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.settings.Path != "" {
|
||||
if err := p.initRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := git.SetUserName(p.settings.Commit.Author.Name).Run(); err != nil {
|
||||
if err := git.ConfigAutocorrect(p.settings.Repo).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := git.SetUserEmail(p.settings.Commit.Author.Email).Run(); err != nil {
|
||||
if err := git.ConfigUserName(p.settings.Repo).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := git.SetSSLVerify(p.settings.InsecureSSLVerify).Run(); err != nil {
|
||||
if err := git.ConfigUserEmail(p.settings.Repo).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := git.ConfigSSLVerify(p.settings.Repo).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -107,7 +134,7 @@ func (p *Plugin) Execute() error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, action := range p.settings.Actions.Value() {
|
||||
for _, action := range p.settings.Action.Value() {
|
||||
switch action {
|
||||
case "clone":
|
||||
if err := p.handleClone(); err != nil {
|
||||
@ -121,8 +148,103 @@ func (p *Plugin) Execute() error {
|
||||
if err := p.handlePush(); err != nil {
|
||||
return err
|
||||
}
|
||||
case "pages":
|
||||
if err := p.handlePages(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitRepo initializes the repository.
|
||||
func (p *Plugin) initRepo() error {
|
||||
path := filepath.Join(p.settings.Repo.WorkDir, ".git")
|
||||
if err := os.MkdirAll(p.settings.Repo.WorkDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
p.settings.Repo.InitExists = true
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"git",
|
||||
"init",
|
||||
)
|
||||
cmd.Dir = p.settings.Repo.WorkDir
|
||||
|
||||
return execute(cmd)
|
||||
}
|
||||
|
||||
// HandleClone clones remote.
|
||||
func (p *Plugin) handleClone() error {
|
||||
if p.settings.Repo.InitExists {
|
||||
return fmt.Errorf("destination '%s' already exists and is not an empty directory", p.settings.Repo.WorkDir)
|
||||
}
|
||||
|
||||
if p.settings.Repo.RemoteURL != "" {
|
||||
if err := execute(git.RemoteAdd(p.settings.Repo)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := execute(git.FetchSource(p.settings.Repo)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := execute(git.CheckoutHead(p.settings.Repo)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandleCommit commits changes locally.
|
||||
func (p *Plugin) handleCommit() error {
|
||||
if err := execute(git.Add(p.settings.Repo)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := execute(git.TestCleanTree(p.settings.Repo)); err != nil {
|
||||
if err := execute(git.ForceCommit(p.settings.Repo)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if p.settings.Repo.EmptyCommit {
|
||||
if err := execute(git.EmptyCommit(p.settings.Repo)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandlePush pushs changes to remote.
|
||||
func (p *Plugin) handlePush() error {
|
||||
return execute(git.RemotePush(p.settings.Repo))
|
||||
}
|
||||
|
||||
// HandlePages syncs, commits and pushes the changes from the pages directory to the pages branch.
|
||||
func (p *Plugin) handlePages() error {
|
||||
defer os.RemoveAll(p.settings.Repo.WorkDir)
|
||||
|
||||
if err := p.handleClone(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := execute(
|
||||
rsyncDirectories(p.settings.Pages, p.settings.Repo),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.handleCommit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.handlePush()
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/thegeeklab/drone-git-action/git"
|
||||
)
|
||||
|
||||
// helper function to simply wrap os execte command.
|
||||
@ -19,15 +20,39 @@ func execute(cmd *exec.Cmd) error {
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// helper function returns true if directory dir is empty.
|
||||
func isDirEmpty(dir string) bool {
|
||||
f, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return true
|
||||
func rsyncDirectories(pages Pages, repo git.Repository) *exec.Cmd {
|
||||
args := []string{
|
||||
"-r",
|
||||
"--exclude",
|
||||
".git",
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
for _, item := range pages.Exclude.Value() {
|
||||
args = append(
|
||||
args,
|
||||
"--exclude",
|
||||
item,
|
||||
)
|
||||
}
|
||||
|
||||
_, err = f.Readdir(1)
|
||||
return err == io.EOF
|
||||
if pages.Delete {
|
||||
args = append(
|
||||
args,
|
||||
"--delete",
|
||||
)
|
||||
}
|
||||
|
||||
args = append(
|
||||
args,
|
||||
".",
|
||||
repo.WorkDir,
|
||||
)
|
||||
|
||||
cmd := exec.Command(
|
||||
"rsync",
|
||||
args...,
|
||||
)
|
||||
cmd.Dir = pages.Directory
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user