mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 13:29:41 +02:00
feat(templates): allow managing git based templates [EE-2600] (#7855)
Co-authored-by: itsconquest <william.conquest@portainer.io> Co-authored-by: oscarzhou <oscar.zhou@portainer.io> Co-authored-by: Chaim Lev-Ari <chiptus@users.noreply.github.com>
This commit is contained in:
parent
30a2bb0495
commit
c650868fe9
32 changed files with 944 additions and 101 deletions
89
api/http/handler/gitops/git_repo_file_preview.go
Normal file
89
api/http/handler/gitops/git_repo_file_preview.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package gitops
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
"github.com/portainer/libhttp/response"
|
||||
gittypes "github.com/portainer/portainer/api/git/types"
|
||||
)
|
||||
|
||||
type fileResponse struct {
|
||||
FileContent string
|
||||
}
|
||||
|
||||
type repositoryFilePreviewPayload struct {
|
||||
Repository string `json:"repository" example:"https://github.com/openfaas/faas" validate:"required"`
|
||||
Reference string `json:"reference" example:"refs/heads/master"`
|
||||
Username string `json:"username" example:"myGitUsername"`
|
||||
Password string `json:"password" example:"myGitPassword"`
|
||||
// Path to file whose content will be read
|
||||
TargetFile string `json:"targetFile" example:"docker-compose.yml"`
|
||||
// TLSSkipVerify skips SSL verification when cloning the Git repository
|
||||
TLSSkipVerify bool `example:"false"`
|
||||
}
|
||||
|
||||
func (payload *repositoryFilePreviewPayload) Validate(r *http.Request) error {
|
||||
if govalidator.IsNull(payload.Repository) || !govalidator.IsURL(payload.Repository) {
|
||||
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
||||
}
|
||||
|
||||
if govalidator.IsNull(payload.Reference) {
|
||||
payload.Reference = "refs/heads/main"
|
||||
}
|
||||
|
||||
if govalidator.IsNull(payload.TargetFile) {
|
||||
return errors.New("Invalid target filename.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// @id GitOperationRepoFilePreview
|
||||
// @summary preview the content of target file in the git repository
|
||||
// @description Retrieve the compose file content based on git repository configuration
|
||||
// @description **Access policy**: authenticated
|
||||
// @tags gitops
|
||||
// @security ApiKeyAuth
|
||||
// @security jwt
|
||||
// @produce json
|
||||
// @param body body repositoryFilePreviewPayload true "Template details"
|
||||
// @success 200 {object} fileResponse "Success"
|
||||
// @failure 400 "Invalid request"
|
||||
// @failure 500 "Server error"
|
||||
// @router /gitops/repo/file/preview [post]
|
||||
func (handler *Handler) gitOperationRepoFilePreview(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||
var payload repositoryFilePreviewPayload
|
||||
err := request.DecodeAndValidateJSONPayload(r, &payload)
|
||||
if err != nil {
|
||||
return httperror.BadRequest("Invalid request payload", err)
|
||||
}
|
||||
|
||||
projectPath, err := handler.fileService.GetTemporaryPath()
|
||||
if err != nil {
|
||||
return httperror.InternalServerError("Unable to create temporary folder", err)
|
||||
}
|
||||
|
||||
err = handler.gitService.CloneRepository(projectPath, payload.Repository, payload.Reference, payload.Username, payload.Password, payload.TLSSkipVerify)
|
||||
if err != nil {
|
||||
if err == gittypes.ErrAuthenticationFailure {
|
||||
return httperror.BadRequest("Invalid git credential", err)
|
||||
}
|
||||
|
||||
newErr := fmt.Errorf("unable to clone git repository: %w", err)
|
||||
return httperror.InternalServerError(newErr.Error(), newErr)
|
||||
}
|
||||
|
||||
defer handler.fileService.RemoveDirectory(projectPath)
|
||||
|
||||
fileContent, err := handler.fileService.GetFileContent(projectPath, payload.TargetFile)
|
||||
if err != nil {
|
||||
return httperror.InternalServerError("Unable to retrieve custom template file from disk", err)
|
||||
}
|
||||
|
||||
return response.JSON(w, &fileResponse{FileContent: string(fileContent)})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue