Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support event token response of Project.Clone #31

Merged
merged 1 commit into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion about_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dtrack

import (
"context"
"fmt"
"github.com/google/uuid"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
Expand Down Expand Up @@ -31,15 +32,21 @@ func TestAboutService_Get(t *testing.T) {
}

type testContainerOptions struct {
Version string
APIPermissions []string
}

func setUpContainer(t *testing.T, options testContainerOptions) *Client {
ctx := context.Background()

version := "latest"
if options.Version != "" {
version = options.Version
}

container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "dependencytrack/apiserver:latest",
Image: fmt.Sprintf("dependencytrack/apiserver:%s", version),
Env: map[string]string{
"JAVA_OPTIONS": "-Xmx1g",
"SYSTEM_REQUIREMENT_CHECK_ENABLED": "false",
Expand Down
7 changes: 4 additions & 3 deletions bom.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/google/uuid"
"net/http"
"net/url"
"strconv"
"strings"
)

Expand All @@ -21,7 +22,7 @@ type BOMUploadRequest struct {
ParentUUID *uuid.UUID `json:"parentUUID,omitempty"` // Since v4.8.0
ParentName string `json:"parentName,omitempty"` // Since v4.8.0
ParentVersion string `json:"parentVersion,omitempty"` // Since v4.8.0
IsLatest bool `json:"isLatestProjectVersion,omitempty"` // Since v4.12.0
IsLatest *bool `json:"isLatestProjectVersion,omitempty"` // Since v4.12.0
AutoCreate bool `json:"autoCreate"`
BOM string `json:"bom"`
}
Expand Down Expand Up @@ -121,8 +122,8 @@ func (bs BOMService) PostBom(ctx context.Context, uploadReq BOMUploadRequest) (t
}
params["projectTags"] = append(params["projectTags"], strings.Join(tagNames, ","))
}
if uploadReq.IsLatest {
params["isLatest"] = append(params["isLatest"], "true")
if uploadReq.IsLatest != nil {
params["isLatest"] = append(params["isLatest"], strconv.FormatBool(*uploadReq.IsLatest))
}
if uploadReq.ParentUUID != nil {
params["parentUUID"] = append(params["parentUUID"], uploadReq.ParentUUID.String())
Expand Down
10 changes: 6 additions & 4 deletions bom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestBOMService_Upload(t *testing.T) {
{Name: "foo"},
{Name: "bar"},
},
IsLatest: true,
IsLatest: OptionalBoolOf(true),
AutoCreate: true,
BOM: base64.StdEncoding.EncodeToString([]byte(`
{
Expand All @@ -39,7 +39,8 @@ func TestBOMService_Upload(t *testing.T) {
require.NoError(t, err)
require.Contains(t, project.Tags, Tag{Name: "foo"})
require.Contains(t, project.Tags, Tag{Name: "bar"})
require.True(t, project.IsLatest)
require.NotNil(t, project.IsLatest)
require.True(t, *project.IsLatest)
}

func TestBOMService_PostBom(t *testing.T) {
Expand All @@ -58,7 +59,7 @@ func TestBOMService_PostBom(t *testing.T) {
{Name: "foo"},
{Name: "bar"},
},
IsLatest: true,
IsLatest: OptionalBoolOf(true),
AutoCreate: true,
BOM: `
{
Expand All @@ -74,5 +75,6 @@ func TestBOMService_PostBom(t *testing.T) {
require.NoError(t, err)
require.Contains(t, project.Tags, Tag{Name: "foo"})
require.Contains(t, project.Tags, Tag{Name: "bar"})
require.True(t, project.IsLatest)
require.NotNil(t, project.IsLatest)
require.True(t, *project.IsLatest)
}
2 changes: 1 addition & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (c Client) isServerVersionAtLeast(targetVersion string) bool {
// and doesn't support "-SNAPSHOT" suffixes.
targetVersionNormalized := fmt.Sprintf("v%s", targetVersion)
actualVersionNormalized := fmt.Sprintf("v%s", strings.TrimSuffix(c.about.Version, "-SNAPSHOT"))
return semver.Compare(targetVersionNormalized, actualVersionNormalized) >= 0
return semver.Compare(targetVersionNormalized, actualVersionNormalized) <= 0
}

func (c Client) assertServerVersionAtLeast(targetVersion string) error {
Expand Down
4 changes: 4 additions & 0 deletions event.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ type EventService struct {

type EventToken string

type EventTokenResponse struct {
Token EventToken `json:"token"`
}

type eventProcessingResponse struct {
Processing bool `json:"processing"`
}
Expand Down
32 changes: 22 additions & 10 deletions project.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Project struct {
Properties []ProjectProperty `json:"properties,omitempty"`
Tags []Tag `json:"tags,omitempty"`
Active bool `json:"active"`
IsLatest bool `json:"isLatest"` // Since v4.12.0
IsLatest *bool `json:"isLatest,omitempty"` // Since v4.12.0
Metrics ProjectMetrics `json:"metrics"`
ParentRef *ParentRef `json:"parent,omitempty"`
LastBOMImport int `json:"lastBomImport"`
Expand Down Expand Up @@ -160,21 +160,33 @@ func (ps ProjectService) GetAllByTag(ctx context.Context, tag string, excludeIna
}

type ProjectCloneRequest struct {
ProjectUUID uuid.UUID `json:"project"`
Version string `json:"version"`
IncludeAuditHistory bool `json:"includeAuditHistory"`
IncludeComponents bool `json:"includeComponents"`
IncludeProperties bool `json:"includeProperties"`
IncludeServices bool `json:"includeServices"`
IncludeTags bool `json:"includeTags"`
ProjectUUID uuid.UUID `json:"project"`
Version string `json:"version"`
IncludeACL bool `json:"includeACL"`
IncludeAuditHistory bool `json:"includeAuditHistory"`
IncludeComponents bool `json:"includeComponents"`
IncludePolicyViolations *bool `json:"includePolicyViolations,omitempty"` // Since v4.11.0
IncludeProperties bool `json:"includeProperties"`
IncludeServices bool `json:"includeServices"`
IncludeTags bool `json:"includeTags"`
MakeCloneLatest *bool `json:"makeCloneLatest,omitempty"` // Since v4.12.0
}

func (ps ProjectService) Clone(ctx context.Context, cloneReq ProjectCloneRequest) (err error) {
// Clone triggers a cloning operation.
// An EventToken is only returned for server versions 4.11.0 and newer.
func (ps ProjectService) Clone(ctx context.Context, cloneReq ProjectCloneRequest) (token EventToken, err error) {
req, err := ps.client.newRequest(ctx, http.MethodPut, "/api/v1/project/clone", withBody(cloneReq))
if err != nil {
return
}

_, err = ps.client.doRequest(req, nil)
if ps.client.isServerVersionAtLeast("4.11.0") {
var tokenResponse EventTokenResponse
_, err = ps.client.doRequest(req, &tokenResponse)
token = tokenResponse.Token
} else {
_, err = ps.client.doRequest(req, nil)
}

return
}
50 changes: 50 additions & 0 deletions project_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dtrack

import (
"context"
"github.com/stretchr/testify/require"
"testing"
)

func TestProjectService_Clone(t *testing.T) {
client := setUpContainer(t, testContainerOptions{
APIPermissions: []string{
PermissionPortfolioManagement,
},
})

project, err := client.Project.Create(context.Background(), Project{
Name: "acme-app",
Version: "1.0.0",
})
require.NoError(t, err)

token, err := client.Project.Clone(context.Background(), ProjectCloneRequest{
ProjectUUID: project.UUID,
Version: "2.0.0",
})
require.NoError(t, err)
require.NotEmpty(t, token)
}

func TestProjectService_Clone_v4_10(t *testing.T) {
client := setUpContainer(t, testContainerOptions{
Version: "4.10.1",
APIPermissions: []string{
PermissionPortfolioManagement,
},
})

project, err := client.Project.Create(context.Background(), Project{
Name: "acme-app",
Version: "1.0.0",
})
require.NoError(t, err)

token, err := client.Project.Clone(context.Background(), ProjectCloneRequest{
ProjectUUID: project.UUID,
Version: "2.0.0",
})
require.NoError(t, err)
require.Empty(t, token)
}
8 changes: 8 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,11 @@ func ForEach[T any](pageFetchFunc func(po PageOptions) (Page[T], error), handler

return
}

func OptionalBoolOf(value bool) *bool {
return &value
}

func OptionalBool() *bool {
return nil
}
10 changes: 10 additions & 0 deletions util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dtrack

import (
"errors"
"github.com/stretchr/testify/require"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -103,3 +104,12 @@ func TestForEach_HandlerFuncErr(t *testing.T) {
t.Errorf("expected error from handlerFunc but got nil")
}
}

func TestOptionalBoolOf(t *testing.T) {
require.True(t, *OptionalBoolOf(true))
require.False(t, *OptionalBoolOf(false))
}

func TestOptionalBool(t *testing.T) {
require.Nil(t, OptionalBool())
}
Loading