package git import ( "fmt" "github.com/pkg/errors" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/filesystem" gittypes "github.com/portainer/portainer/api/git/types" "github.com/rs/zerolog/log" ) var ( ErrInvalidGitCredential = errors.New("Invalid git credential") ) type CloneOptions struct { ProjectPath string URL string ReferenceName string Username string Password string // TLSSkipVerify skips SSL verification when cloning the Git repository TLSSkipVerify bool `example:"false"` } func CloneWithBackup(gitService portainer.GitService, fileService portainer.FileService, options CloneOptions) (clean func(), err error) { backupProjectPath := fmt.Sprintf("%s-old", options.ProjectPath) cleanUp := false cleanFn := func() { if !cleanUp { return } err = fileService.RemoveDirectory(backupProjectPath) if err != nil { log.Warn().Err(err).Msg("unable to remove git repository directory") } } err = filesystem.MoveDirectory(options.ProjectPath, backupProjectPath) if err != nil { return cleanFn, errors.WithMessage(err, "Unable to move git repository directory") } cleanUp = true err = gitService.CloneRepository(options.ProjectPath, options.URL, options.ReferenceName, options.Username, options.Password, options.TLSSkipVerify) if err != nil { cleanUp = false restoreError := filesystem.MoveDirectory(backupProjectPath, options.ProjectPath) if restoreError != nil { log.Warn().Err(restoreError).Msg("failed restoring backup folder") } if errors.Is(err, gittypes.ErrAuthenticationFailure) { return cleanFn, errors.WithMessage(err, ErrInvalidGitCredential.Error()) } return cleanFn, errors.WithMessage(err, "Unable to clone git repository") } return cleanFn, nil }