2022-11-27 13:33:39 +00:00
|
|
|
package plugin
|
|
|
|
|
|
|
|
import (
|
2023-08-14 19:19:39 +00:00
|
|
|
"context"
|
2023-02-08 09:16:10 +00:00
|
|
|
"errors"
|
2022-11-27 13:33:39 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2022-12-02 21:21:35 +00:00
|
|
|
"path/filepath"
|
2022-11-27 13:33:39 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
"github.com/thegeeklab/wp-plugin-go/v2/file"
|
|
|
|
"github.com/thegeeklab/wp-plugin-go/v2/types"
|
2024-05-06 18:29:57 +00:00
|
|
|
"github.com/thegeeklab/wp-plugin-go/v2/util"
|
2022-11-27 13:33:39 +00:00
|
|
|
)
|
|
|
|
|
2023-02-08 09:16:10 +00:00
|
|
|
var (
|
|
|
|
ErrAuthSourceNotSet = errors.New("either SSH key or netrc password is required")
|
|
|
|
ErrPagesDirectoryNotExist = errors.New("pages directory must exist")
|
|
|
|
ErrPagesDirectoryNotValid = errors.New("pages directory not valid")
|
|
|
|
ErrPagesSourceNotSet = errors.New("pages source directory must be set")
|
|
|
|
ErrPagesActionNotExclusive = errors.New("pages action is mutual exclusive")
|
|
|
|
ErrActionUnknown = errors.New("action not found")
|
|
|
|
ErrGitCloneDestintionNotValid = errors.New("destination not valid")
|
|
|
|
)
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
const (
|
|
|
|
ActionClone Action = "clone"
|
|
|
|
ActionCommit Action = "commit"
|
|
|
|
ActionPush Action = "push"
|
|
|
|
ActionPages Action = "pages"
|
|
|
|
)
|
|
|
|
|
2023-08-14 19:19:39 +00:00
|
|
|
//nolint:revive
|
2023-08-21 09:41:28 +00:00
|
|
|
func (p *Plugin) run(ctx context.Context) error {
|
2023-08-14 19:19:39 +00:00
|
|
|
if err := p.Validate(); err != nil {
|
|
|
|
return fmt.Errorf("validation failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := p.Execute(); err != nil {
|
|
|
|
return fmt.Errorf("execution failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-11-27 13:33:39 +00:00
|
|
|
// Validate handles the settings validation of the plugin.
|
|
|
|
func (p *Plugin) Validate() error {
|
2022-12-02 21:21:35 +00:00
|
|
|
var err error
|
|
|
|
|
2024-05-06 06:52:25 +00:00
|
|
|
p.Settings.Repo.Autocorrect = "never"
|
|
|
|
p.Settings.Repo.RemoteName = "origin"
|
|
|
|
|
2024-05-06 18:29:57 +00:00
|
|
|
if p.Settings.Repo.WorkDir == "" {
|
|
|
|
p.Settings.Repo.WorkDir, err = os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get working directory: %w", err)
|
|
|
|
}
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
for _, actionStr := range p.Settings.Action.Value() {
|
|
|
|
action := Action(actionStr)
|
2022-11-29 09:40:42 +00:00
|
|
|
switch action {
|
2024-05-05 20:14:55 +00:00
|
|
|
case ActionClone:
|
2022-11-29 09:40:42 +00:00
|
|
|
continue
|
2024-05-05 20:14:55 +00:00
|
|
|
case ActionCommit:
|
2022-11-29 09:40:42 +00:00
|
|
|
continue
|
2024-05-05 20:14:55 +00:00
|
|
|
case ActionPush:
|
2023-08-14 19:19:39 +00:00
|
|
|
if p.Settings.SSHKey == "" && p.Settings.Netrc.Password == "" {
|
2023-02-08 09:16:10 +00:00
|
|
|
return ErrAuthSourceNotSet
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
2024-05-05 20:14:55 +00:00
|
|
|
case ActionPages:
|
2023-08-14 19:19:39 +00:00
|
|
|
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")
|
2022-12-02 21:21:35 +00:00
|
|
|
|
2023-08-14 19:19:39 +00:00
|
|
|
if _, err := os.Stat(p.Settings.Pages.Directory); os.IsNotExist(err) {
|
|
|
|
return fmt.Errorf("%w: '%s' not found", ErrPagesDirectoryNotExist, p.Settings.Pages.Directory)
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 19:19:39 +00:00
|
|
|
if info, _ := os.Stat(p.Settings.Pages.Directory); !info.IsDir() {
|
|
|
|
return fmt.Errorf("%w: '%s' not a directory", ErrPagesDirectoryNotValid, p.Settings.Pages.Directory)
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 19:19:39 +00:00
|
|
|
if p.Settings.SSHKey == "" && p.Settings.Netrc.Password == "" {
|
2023-02-08 09:16:10 +00:00
|
|
|
return ErrAuthSourceNotSet
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 19:19:39 +00:00
|
|
|
if p.Settings.Pages.Directory == "" {
|
2023-02-08 09:16:10 +00:00
|
|
|
return ErrPagesSourceNotSet
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 19:19:39 +00:00
|
|
|
if len(p.Settings.Action.Value()) > 1 {
|
2023-02-08 09:16:10 +00:00
|
|
|
return ErrPagesActionNotExclusive
|
2022-11-29 09:40:42 +00:00
|
|
|
}
|
|
|
|
default:
|
2024-05-05 20:14:55 +00:00
|
|
|
return fmt.Errorf("%w: %s", ErrActionUnknown, actionStr)
|
2022-11-29 09:40:42 +00:00
|
|
|
}
|
2022-11-27 13:33:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute provides the implementation of the plugin.
|
|
|
|
func (p *Plugin) Execute() error {
|
2024-05-06 06:52:25 +00:00
|
|
|
var err error
|
|
|
|
|
2024-05-06 18:29:57 +00:00
|
|
|
homeDir := util.GetUserHomeDir()
|
2024-05-05 20:14:55 +00:00
|
|
|
batchCmd := make([]*types.Cmd, 0)
|
2022-11-29 10:12:03 +00:00
|
|
|
gitEnv := []string{
|
|
|
|
"GIT_AUTHOR_NAME",
|
|
|
|
"GIT_AUTHOR_EMAIL",
|
|
|
|
"GIT_AUTHOR_DATE",
|
|
|
|
"GIT_COMMITTER_NAME",
|
|
|
|
"GIT_COMMITTER_EMAIL",
|
|
|
|
"GIT_COMMITTER_DATE",
|
|
|
|
}
|
2023-02-08 09:16:10 +00:00
|
|
|
|
2022-11-29 10:12:03 +00:00
|
|
|
for _, env := range gitEnv {
|
2022-11-29 09:40:42 +00:00
|
|
|
if err := os.Unsetenv(env); err != nil {
|
2024-05-05 20:14:55 +00:00
|
|
|
return fmt.Errorf("failed to unset git env vars '%s': %w", env, err)
|
2022-11-27 13:33:39 +00:00
|
|
|
}
|
2022-11-29 09:40:42 +00:00
|
|
|
}
|
2023-02-08 09:16:10 +00:00
|
|
|
|
2022-11-29 09:40:42 +00:00
|
|
|
if err := os.Setenv("GIT_TERMINAL_PROMPT", "0"); err != nil {
|
2024-05-05 20:14:55 +00:00
|
|
|
return fmt.Errorf("failed to git env var': %w", err)
|
2022-11-29 09:40:42 +00:00
|
|
|
}
|
2022-11-27 13:33:39 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
// Write SSH key and netrc file.
|
|
|
|
if p.Settings.SSHKey != "" {
|
2024-05-06 20:17:45 +00:00
|
|
|
batchCmd = append(batchCmd, p.Settings.Repo.ConfigSSHCommand(p.Settings.SSHKey))
|
2022-11-27 13:33:39 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
netrc := p.Settings.Netrc
|
2024-05-06 18:29:57 +00:00
|
|
|
if err := WriteNetrc(homeDir, netrc.Machine, netrc.Login, netrc.Password); err != nil {
|
2022-12-02 21:21:35 +00:00
|
|
|
return err
|
|
|
|
}
|
2023-02-08 09:16:10 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
// Handle repo initialization.
|
|
|
|
if err := os.MkdirAll(p.Settings.Repo.WorkDir, os.ModePerm); err != nil {
|
|
|
|
return fmt.Errorf("failed to create working directory: %w", err)
|
2022-11-27 13:33:39 +00:00
|
|
|
}
|
2024-05-06 20:43:56 +00:00
|
|
|
defer os.RemoveAll(p.Settings.Repo.WorkDir)
|
2023-02-08 09:16:10 +00:00
|
|
|
|
2024-05-06 06:52:25 +00:00
|
|
|
p.Settings.Repo.IsEmpty, err = file.IsDirEmpty(p.Settings.Repo.WorkDir)
|
2024-05-05 20:14:55 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to check working directory: %w", err)
|
2022-11-27 13:33:39 +00:00
|
|
|
}
|
2023-02-08 09:16:10 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
isDir, err := file.IsDir(filepath.Join(p.Settings.Repo.WorkDir, ".git"))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to check working directory: %w", err)
|
2022-11-27 13:33:39 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
if !isDir {
|
2024-05-06 18:29:57 +00:00
|
|
|
batchCmd = append(batchCmd, p.Settings.Repo.Init())
|
2022-11-27 13:33:39 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
// Handle repo configuration.
|
2024-05-06 18:29:57 +00:00
|
|
|
batchCmd = append(batchCmd, p.Settings.Repo.ConfigAutocorrect())
|
|
|
|
batchCmd = append(batchCmd, p.Settings.Repo.ConfigUserName())
|
|
|
|
batchCmd = append(batchCmd, p.Settings.Repo.ConfigUserEmail())
|
|
|
|
batchCmd = append(batchCmd, p.Settings.Repo.ConfigSSLVerify(p.Network.InsecureSkipVerify))
|
2024-05-05 20:14:55 +00:00
|
|
|
|
|
|
|
for _, actionStr := range p.Settings.Action.Value() {
|
|
|
|
action := Action(actionStr)
|
2022-11-27 13:33:39 +00:00
|
|
|
switch action {
|
2024-05-05 20:14:55 +00:00
|
|
|
case ActionClone:
|
|
|
|
cmds, err := p.handleClone()
|
|
|
|
if err != nil {
|
2022-11-27 13:33:39 +00:00
|
|
|
return err
|
|
|
|
}
|
2024-05-05 20:14:55 +00:00
|
|
|
|
|
|
|
batchCmd = append(batchCmd, cmds...)
|
|
|
|
case ActionCommit:
|
|
|
|
batchCmd = append(batchCmd, p.handleCommit()...)
|
|
|
|
case ActionPush:
|
|
|
|
batchCmd = append(batchCmd, p.handlePush()...)
|
|
|
|
case ActionPages:
|
|
|
|
cmds, err := p.handlePages()
|
|
|
|
if err != nil {
|
2022-12-02 21:21:35 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-11-27 13:33:39 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
batchCmd = append(batchCmd, cmds...)
|
|
|
|
}
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
for _, cmd := range batchCmd {
|
2024-05-07 09:57:18 +00:00
|
|
|
if cmd == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
if err := cmd.Run(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
return nil
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
// handleClone clones the remote repository into the configured working directory.
|
|
|
|
// If the working directory is not empty, it returns an error.
|
|
|
|
func (p *Plugin) handleClone() ([]*types.Cmd, error) {
|
|
|
|
var cmds []*types.Cmd
|
|
|
|
|
|
|
|
if !p.Settings.Repo.IsEmpty {
|
|
|
|
return cmds, fmt.Errorf("%w: %s exists and not empty", ErrGitCloneDestintionNotValid, p.Settings.Repo.WorkDir)
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 19:19:39 +00:00
|
|
|
if p.Settings.Repo.RemoteURL != "" {
|
2024-05-06 18:29:57 +00:00
|
|
|
cmds = append(cmds, p.Settings.Repo.RemoteAdd())
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-06 18:29:57 +00:00
|
|
|
cmds = append(cmds, p.Settings.Repo.FetchSource())
|
|
|
|
cmds = append(cmds, p.Settings.Repo.CheckoutHead())
|
2022-12-02 21:21:35 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
return cmds, nil
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// HandleCommit commits changes locally.
|
2024-05-05 20:14:55 +00:00
|
|
|
func (p *Plugin) handleCommit() []*types.Cmd {
|
|
|
|
var cmds []*types.Cmd
|
2022-12-02 21:21:35 +00:00
|
|
|
|
2024-05-06 18:29:57 +00:00
|
|
|
cmds = append(cmds, p.Settings.Repo.Add())
|
2024-05-06 20:43:56 +00:00
|
|
|
cmds = append(cmds, p.Settings.Repo.Commit())
|
2022-12-02 21:21:35 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
return cmds
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// HandlePush pushs changes to remote.
|
2024-05-05 20:14:55 +00:00
|
|
|
func (p *Plugin) handlePush() []*types.Cmd {
|
2024-05-06 18:29:57 +00:00
|
|
|
return []*types.Cmd{p.Settings.Repo.RemotePush()}
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// HandlePages syncs, commits and pushes the changes from the pages directory to the pages branch.
|
2024-05-05 20:14:55 +00:00
|
|
|
func (p *Plugin) handlePages() ([]*types.Cmd, error) {
|
|
|
|
var cmds []*types.Cmd
|
|
|
|
|
|
|
|
ccmd, err := p.handleClone()
|
|
|
|
if err != nil {
|
|
|
|
return cmds, err
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
cmds = append(cmds, ccmd...)
|
|
|
|
cmds = append(cmds,
|
|
|
|
SyncDirectories(
|
|
|
|
p.Settings.Pages.Exclude.Value(),
|
|
|
|
p.Settings.Pages.Delete,
|
|
|
|
p.Settings.Pages.Directory,
|
|
|
|
p.Settings.Repo.WorkDir,
|
|
|
|
),
|
|
|
|
)
|
2022-12-02 21:21:35 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
cmds = append(cmds, p.handleCommit()...)
|
|
|
|
cmds = append(cmds, p.handlePush()...)
|
2022-12-02 21:21:35 +00:00
|
|
|
|
2024-05-05 20:14:55 +00:00
|
|
|
return cmds, nil
|
2022-12-02 21:21:35 +00:00
|
|
|
}
|