131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
package update
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
portainer "github.com/portainer/portainer/api"
|
|
"github.com/portainer/portainer/api/filesystem"
|
|
"github.com/portainer/portainer/api/git"
|
|
gittypes "github.com/portainer/portainer/api/git/types"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
// UpdateGitObject updates a git object based on its config
|
|
func UpdateGitObject(ctx context.Context, gitService portainer.GitService, objId string, gitConfig *gittypes.RepoConfig, enableVersionFolder bool, projectPath string) (bool, string, error) {
|
|
if gitConfig == nil {
|
|
return false, "", nil
|
|
}
|
|
|
|
log.Debug().
|
|
Str("url", gitConfig.URL).
|
|
Str("ref", gitConfig.ReferenceName).
|
|
Str("object", objId).
|
|
Msg("the object has a git config, try to poll from git repository")
|
|
|
|
username, password := git.GetCredentials(gitConfig.Authentication)
|
|
|
|
fetchCtx, cancel := context.WithTimeout(ctx, time.Minute)
|
|
newHash, err := gitService.LatestCommitID(
|
|
fetchCtx,
|
|
gitConfig.URL,
|
|
gitConfig.ReferenceName,
|
|
username,
|
|
password,
|
|
gitConfig.TLSSkipVerify,
|
|
)
|
|
cancel()
|
|
if err != nil {
|
|
if fetchCtx.Err() == context.DeadlineExceeded {
|
|
log.Error().Str("object", objId).Msg("git fetch timed out after 1 minute")
|
|
}
|
|
|
|
return false, "", errors.WithMessagef(err, "failed to fetch latest commit id of %v", objId)
|
|
}
|
|
|
|
hashChanged := !strings.EqualFold(newHash, gitConfig.ConfigHash)
|
|
|
|
if !hashChanged {
|
|
log.Debug().
|
|
Str("hash", newHash).
|
|
Str("url", gitConfig.URL).
|
|
Str("ref", gitConfig.ReferenceName).
|
|
Str("object", objId).
|
|
Msg("git repo is up to date")
|
|
|
|
return false, newHash, nil
|
|
}
|
|
|
|
toDir := projectPath
|
|
if enableVersionFolder {
|
|
toDir = filesystem.JoinPaths(projectPath, newHash)
|
|
}
|
|
|
|
cloneParams := &cloneRepositoryParameters{
|
|
url: gitConfig.URL,
|
|
ref: gitConfig.ReferenceName,
|
|
toDir: toDir,
|
|
tlsSkipVerify: gitConfig.TLSSkipVerify,
|
|
}
|
|
if gitConfig.Authentication != nil {
|
|
cloneParams.auth = &gitAuth{
|
|
username: username,
|
|
password: password,
|
|
}
|
|
}
|
|
|
|
if err := cloneGitRepository(ctx, gitService, cloneParams); err != nil {
|
|
if enableVersionFolder {
|
|
if removeErr := os.RemoveAll(toDir); removeErr != nil {
|
|
log.Warn().Err(removeErr).Str("dir", toDir).Msg("failed to remove partial clone directory")
|
|
}
|
|
}
|
|
return false, "", errors.WithMessagef(err, "failed to do a fresh clone of %v", objId)
|
|
}
|
|
|
|
log.Debug().
|
|
Str("hash", newHash).
|
|
Str("url", gitConfig.URL).
|
|
Str("ref", gitConfig.ReferenceName).
|
|
Str("object", objId).
|
|
Msg("git repo cloned updated")
|
|
|
|
return true, newHash, nil
|
|
}
|
|
|
|
type cloneRepositoryParameters struct {
|
|
url string
|
|
ref string
|
|
toDir string
|
|
auth *gitAuth
|
|
// tlsSkipVerify skips SSL verification when cloning the Git repository
|
|
tlsSkipVerify bool `example:"false"`
|
|
}
|
|
|
|
type gitAuth struct {
|
|
username string
|
|
password string
|
|
}
|
|
|
|
func cloneGitRepository(ctx context.Context, gitService portainer.GitService, cloneParams *cloneRepositoryParameters) error {
|
|
username, password := "", ""
|
|
if cloneParams.auth != nil {
|
|
username = cloneParams.auth.username
|
|
password = cloneParams.auth.password
|
|
}
|
|
|
|
return gitService.CloneRepository(
|
|
ctx,
|
|
cloneParams.toDir,
|
|
cloneParams.url,
|
|
cloneParams.ref,
|
|
username,
|
|
password,
|
|
cloneParams.tlsSkipVerify,
|
|
)
|
|
}
|