Przeglądaj źródła

Start endpoint implementation for update and create release with tags

jnfrati 4 lat temu
rodzic
commit
bdc720f214

+ 28 - 0
api/server/handlers/release/create.go

@@ -117,6 +117,14 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
+	if request.Tags != nil {
+		tmpRelease, err := LinkTagsToRelease(c.Config(), request.Tags, release)
+
+		if err == nil {
+			release = tmpRelease
+		}
+	}
+
 	if request.GithubActionConfig != nil {
 		_, _, err := createGitAction(
 			c.Config(),
@@ -403,3 +411,23 @@ func getGARunner(
 		Version:                "v0.1.0",
 	}, nil
 }
+
+// Gets a list of tags to be added into a release and then returns the updated release
+func LinkTagsToRelease(config *config.Config, tags []string, release *models.Release) (*models.Release, error) {
+	var err error
+	for i := 0; i < len(tags); i++ {
+		err = config.Repo.Tag().CreateOrLinkTag(tags[i], release)
+
+		if err != nil {
+			break
+		}
+	}
+
+	fmt.Println("LINK TAGS TO RELEASE ERROR", err)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return config.Repo.Release().ReadRelease(release.ClusterID, release.Name, release.Namespace)
+}

+ 5 - 0
api/server/handlers/release/get.go

@@ -49,6 +49,11 @@ func (c *ReleaseGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		res.ID = release.ID
 		res.WebhookToken = release.WebhookToken
 
+		for i := 0; i < len(release.Tags); i++ {
+			tag := release.Tags[i]
+			res.PorterRelease.Tags = append(res.PorterRelease.Tags, tag.Name)
+		}
+
 		if release.GitActionConfig != nil {
 			res.GitActionConfig = release.GitActionConfig.ToGitActionConfigType()
 		}

+ 64 - 0
api/server/handlers/release/update_tags.go

@@ -0,0 +1,64 @@
+package release
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/authz"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/server/shared/requestutils"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type UpdateReleaseTagsHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewUpdateReleaseTagsHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *UpdateReleaseTagsHandler {
+	return &UpdateReleaseTagsHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *UpdateReleaseTagsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	name, _ := requestutils.GetURLParamString(r, types.URLParamReleaseName)
+	namespace, _ := requestutils.GetURLParamString(r, types.URLParamNamespace)
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+	fmt.Println("FIRST CHECKPOINT")
+	request := &types.PatchUpdateReleaseTags{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+	fmt.Println("SECOND CHECKPOINT")
+	fmt.Println(cluster.ID)
+	fmt.Println(name)
+	fmt.Println(namespace)
+	release, err := c.Config().Repo.Release().ReadRelease(cluster.ID, name, namespace)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	fmt.Println("THIRD CHECKPOINT")
+	release, err = LinkTagsToRelease(c.Config(), request.Tags, release)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+	fmt.Println("FOURTH CHECKPOINT")
+	w.WriteHeader(http.StatusCreated)
+	c.WriteResult(w, r, release)
+}

+ 32 - 0
api/server/router/release.go

@@ -782,5 +782,37 @@ func getReleaseRoutes(
 		Router:   r,
 	})
 
+	// PATCH /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/releases/{name}/{version}/update_tags ->
+	// release.NewGetLatestJobRunHandler
+	updateReleaseTagsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbUpdate,
+			Method: types.HTTPVerbPatch,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/update_tags",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+				types.NamespaceScope,
+				types.ReleaseScope,
+			},
+		},
+	)
+
+	updateReleaseTagsHandler := release.NewUpdateReleaseTagsHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: updateReleaseTagsEndpoint,
+		Handler:  updateReleaseTagsHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 6 - 0
api/types/release.go

@@ -21,6 +21,7 @@ type PorterRelease struct {
 	GitActionConfig *GitActionConfig `json:"git_action_config,omitempty"`
 	ImageRepoURI    string           `json:"image_repo_uri"`
 	BuildConfig     *BuildConfig     `json:"build_config,omitempty"`
+	Tags            []string         `json:"tags,omitempty"`
 }
 
 type GetReleaseResponse Release
@@ -47,6 +48,7 @@ type CreateReleaseRequest struct {
 	ImageURL           string                        `json:"image_url" form:"required"`
 	GithubActionConfig *CreateGitActionConfigRequest `json:"github_action_config,omitempty"`
 	BuildConfig        *CreateBuildConfigRequest     `json:"build_config,omitempty"`
+	Tags               []string                      `json:"tags,omitempty"`
 }
 
 type CreateAddonRequest struct {
@@ -136,3 +138,7 @@ type DNSRecord struct {
 }
 
 type GetReleaseAllPodsResponse []v1.Pod
+
+type PatchUpdateReleaseTags struct {
+	Tags []string `json:"tags"`
+}

+ 41 - 0
internal/repository/gorm/tag.go

@@ -1,13 +1,24 @@
 package gorm
 
 import (
+	"crypto/rand"
+	"encoding/hex"
 	"fmt"
+	"strings"
 
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/repository"
 	"gorm.io/gorm"
 )
 
+func randomHex(n int) (string, error) {
+	bytes := make([]byte, n)
+	if _, err := rand.Read(bytes); err != nil {
+		return "", err
+	}
+	return hex.EncodeToString(bytes), nil
+}
+
 // AllowlistRepository uses gorm.DB for querying the database
 type TagRepository struct {
 	db *gorm.DB
@@ -32,6 +43,36 @@ func (repo *TagRepository) CreateTag(tag *models.Tag) (*models.Tag, error) {
 	return tag, nil
 }
 
+func (repo *TagRepository) CreateOrLinkTag(tagName string, release *models.Release) error {
+	project_id := release.ProjectID
+
+	existingTag, _ := repo.ReadTagByNameAndProjectId(tagName, project_id)
+
+	if existingTag != nil {
+		return repo.AddTagToRelease(release, existingTag)
+	}
+
+	randomColor, err := randomHex(3)
+
+	if err != nil {
+		randomColor = "ffffff"
+	}
+
+	newTag := &models.Tag{
+		Name:      tagName,
+		ProjectID: project_id,
+		Color:     strings.Join([]string{"#", randomColor}, ""),
+	}
+
+	newTag, err = repo.CreateTag(newTag)
+
+	if err != nil {
+		return err
+	}
+
+	return repo.AddTagToRelease(release, newTag)
+}
+
 func (repo *TagRepository) ReadTagByNameAndProjectId(tagName string, projectId uint) (*models.Tag, error) {
 	tag := &models.Tag{}
 

+ 1 - 0
internal/repository/tag.go

@@ -6,6 +6,7 @@ import "github.com/porter-dev/porter/internal/models"
 // GitRepo model
 type TagRepository interface {
 	CreateTag(tag *models.Tag) (*models.Tag, error)
+	CreateOrLinkTag(tagName string, release *models.Release) error
 	ReadTagByNameAndProjectId(tagName string, projectID uint) (*models.Tag, error)
 	ListTagsByProjectId(projectId uint) ([]*models.Tag, error)
 	UpdateTag(tag *models.Tag) (*models.Tag, error)