mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(stack-creation): add the ability to specify git credentials (#1722)
* feat(stack-creation): add the ability to specify git credentials * docs(api): update Swagger
This commit is contained in:
parent
50ece68f35
commit
adf1ba7b47
7 changed files with 106 additions and 45 deletions
|
@ -1,6 +1,9 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4"
|
||||
)
|
||||
|
||||
|
@ -14,12 +17,23 @@ func NewService(dataStorePath string) (*Service, error) {
|
|||
return service, nil
|
||||
}
|
||||
|
||||
// CloneRepository clones a git repository using the specified URL in the specified
|
||||
// ClonePublicRepository clones a public git repository using the specified URL in the specified
|
||||
// destination folder.
|
||||
func (service *Service) CloneRepository(url, destination string) error {
|
||||
_, err := git.PlainClone(destination, false, &git.CloneOptions{
|
||||
URL: url,
|
||||
})
|
||||
func (service *Service) ClonePublicRepository(repositoryURL, destination string) error {
|
||||
return cloneRepository(repositoryURL, destination)
|
||||
}
|
||||
|
||||
// ClonePrivateRepositoryWithBasicAuth clones a private git repository using the specified URL in the specified
|
||||
// destination folder. It will use the specified username and password for basic HTTP authentication.
|
||||
func (service *Service) ClonePrivateRepositoryWithBasicAuth(repositoryURL, destination, username, password string) error {
|
||||
credentials := username + ":" + url.PathEscape(password)
|
||||
repositoryURL = strings.Replace(repositoryURL, "://", "://"+credentials+"@", 1)
|
||||
return cloneRepository(repositoryURL, destination)
|
||||
}
|
||||
|
||||
func cloneRepository(repositoryURL, destination string) error {
|
||||
_, err := git.PlainClone(destination, false, &git.CloneOptions{
|
||||
URL: repositoryURL,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -70,12 +70,15 @@ func NewStackHandler(bouncer *security.RequestBouncer) *StackHandler {
|
|||
|
||||
type (
|
||||
postStacksRequest struct {
|
||||
Name string `valid:"required"`
|
||||
SwarmID string `valid:"required"`
|
||||
StackFileContent string `valid:""`
|
||||
GitRepository string `valid:""`
|
||||
PathInRepository string `valid:""`
|
||||
Env []portainer.Pair `valid:""`
|
||||
Name string `valid:"required"`
|
||||
SwarmID string `valid:"required"`
|
||||
StackFileContent string `valid:""`
|
||||
RepositoryURL string `valid:""`
|
||||
RepositoryAuthentication bool `valid:""`
|
||||
RepositoryUsername string `valid:""`
|
||||
RepositoryPassword string `valid:""`
|
||||
ComposeFilePathInRepository string `valid:""`
|
||||
Env []portainer.Pair `valid:""`
|
||||
}
|
||||
postStacksResponse struct {
|
||||
ID string `json:"Id"`
|
||||
|
@ -263,24 +266,20 @@ func (handler *StackHandler) handlePostStacksRepositoryMethod(w http.ResponseWri
|
|||
}
|
||||
|
||||
stackName := req.Name
|
||||
if stackName == "" {
|
||||
httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
swarmID := req.SwarmID
|
||||
if swarmID == "" {
|
||||
|
||||
if stackName == "" || swarmID == "" || req.RepositoryURL == "" {
|
||||
httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
if req.GitRepository == "" {
|
||||
if req.RepositoryAuthentication && (req.RepositoryUsername == "" || req.RepositoryPassword == "") {
|
||||
httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
if req.PathInRepository == "" {
|
||||
req.PathInRepository = filesystem.ComposeFileDefaultName
|
||||
if req.ComposeFilePathInRepository == "" {
|
||||
req.ComposeFilePathInRepository = filesystem.ComposeFileDefaultName
|
||||
}
|
||||
|
||||
stacks, err := handler.StackService.Stacks()
|
||||
|
@ -300,7 +299,7 @@ func (handler *StackHandler) handlePostStacksRepositoryMethod(w http.ResponseWri
|
|||
ID: portainer.StackID(stackName + "_" + swarmID),
|
||||
Name: stackName,
|
||||
SwarmID: swarmID,
|
||||
EntryPoint: req.PathInRepository,
|
||||
EntryPoint: req.ComposeFilePathInRepository,
|
||||
Env: req.Env,
|
||||
}
|
||||
|
||||
|
@ -314,7 +313,11 @@ func (handler *StackHandler) handlePostStacksRepositoryMethod(w http.ResponseWri
|
|||
return
|
||||
}
|
||||
|
||||
err = handler.GitService.CloneRepository(req.GitRepository, projectPath)
|
||||
if req.RepositoryAuthentication {
|
||||
err = handler.GitService.ClonePrivateRepositoryWithBasicAuth(req.RepositoryURL, projectPath, req.RepositoryUsername, req.RepositoryPassword)
|
||||
} else {
|
||||
err = handler.GitService.ClonePublicRepository(req.RepositoryURL, projectPath)
|
||||
}
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
|
|
|
@ -375,7 +375,8 @@ type (
|
|||
|
||||
// GitService represents a service for managing Git.
|
||||
GitService interface {
|
||||
CloneRepository(url, destination string) error
|
||||
ClonePublicRepository(repositoryURL, destination string) error
|
||||
ClonePrivateRepositoryWithBasicAuth(repositoryURL, destination, username, password string) error
|
||||
}
|
||||
|
||||
// EndpointWatcher represents a service to synchronize the endpoints via an external source.
|
||||
|
|
|
@ -2904,14 +2904,26 @@ definitions:
|
|||
type: "string"
|
||||
example: "version: 3\n services:\n web:\n image:nginx"
|
||||
description: "Content of the Stack file. Required when using the 'string' deployment method."
|
||||
GitRepository:
|
||||
RepositoryURL:
|
||||
type: "string"
|
||||
example: "https://github.com/openfaas/faas"
|
||||
description: "URL of a public Git repository hosting the Stack file. Required when using the 'repository' deployment method."
|
||||
PathInRepository:
|
||||
description: "URL of a Git repository hosting the Stack file. Required when using the 'repository' deployment method."
|
||||
ComposeFilePathInRepository:
|
||||
type: "string"
|
||||
example: "docker-compose.yml"
|
||||
description: "Path to the Stack file inside the Git repository. Required when using the 'repository' deployment method."
|
||||
RepositoryAuthentication:
|
||||
type: "boolean"
|
||||
example: true
|
||||
description: "Use basic authentication to clone the Git repository."
|
||||
RepositoryUsername:
|
||||
type: "string"
|
||||
example: "myGitUsername"
|
||||
description: "Username used in basic authentication. Required when RepositoryAuthentication is true."
|
||||
RepositoryPassword:
|
||||
type: "string"
|
||||
example: "myGitPassword"
|
||||
description: "Password used in basic authentication. Required when RepositoryAuthentication is true."
|
||||
Env:
|
||||
type: "array"
|
||||
description: "A list of environment variables used during stack deployment"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue