diff --git a/configs/config.yaml.example b/configs/config.yaml.example index 8fc71a5a9..80325dcd2 100644 --- a/configs/config.yaml.example +++ b/configs/config.yaml.example @@ -147,6 +147,7 @@ clients: rbac: 1m subscription_check: 1h roadmap: 24h + content_counts: 10m feature_service: server: #https://feature.stage.api.redhat.com/features client_cert: diff --git a/go.mod b/go.mod index 91c2730f2..e210283a0 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.25.8 require ( github.com/ProtonMail/go-crypto v1.4.1 github.com/content-services/lecho/v3 v3.5.2 - github.com/content-services/tang v0.0.29 + github.com/content-services/tang v0.0.30 github.com/content-services/yummy v1.0.19 github.com/getkin/kin-openapi v0.135.0 github.com/go-openapi/spec v0.22.2 // indirect diff --git a/go.sum b/go.sum index 9ddbd740f..0766946ad 100644 --- a/go.sum +++ b/go.sum @@ -80,8 +80,8 @@ github.com/content-services/caliri/release/v4 v4.8.1 h1:ttaBJkDrjxt89Efgzws0P5jq github.com/content-services/caliri/release/v4 v4.8.1/go.mod h1:lFbop4Wy5Z7tLmj5XoMqMep1rOEz1Od4VG9Z7cq+Xs0= github.com/content-services/lecho/v3 v3.5.2 h1:lNGYoG/6RnPtnGtWkKSUwO2Huw6lxDrW1Ogz1Ct2jT0= github.com/content-services/lecho/v3 v3.5.2/go.mod h1:hALn6ZuFGV3AIYlkhZDU1C5JoWM4TeIx//VO2xt8oZA= -github.com/content-services/tang v0.0.29 h1:+RpzxOFlIbAgts7Ii0rIiNMI0Lnj9FePfmuoUS37lt8= -github.com/content-services/tang v0.0.29/go.mod h1:Z969TdEJaoRHxhpZ89Gi25RFVj1dBjEiFzhsGppyz8g= +github.com/content-services/tang v0.0.30 h1:t/d6tYTKaq5nU0Qc9v4VW79OrJO2i8oxWSt4JGn1hLM= +github.com/content-services/tang v0.0.30/go.mod h1:Z969TdEJaoRHxhpZ89Gi25RFVj1dBjEiFzhsGppyz8g= github.com/content-services/yummy v1.0.19 h1:gVevHg/GeIUk4lnjafZWdHRr/zWQES4KiYZebpjSzdM= github.com/content-services/yummy v1.0.19/go.mod h1:qpXbSMEJvQ1hs59Tn2tA2MAApvht867BUUUETntvO6U= github.com/content-services/zest/release/v2026 v2026.7.1783082453 h1:mZ8LExJlcMcoIUCv7eW+qQwZ9in18byKtuA99WWG0+M= diff --git a/pkg/handler/packages.go b/pkg/handler/packages.go index d7a0e5b21..5b4585c92 100644 --- a/pkg/handler/packages.go +++ b/pkg/handler/packages.go @@ -266,24 +266,26 @@ func (ph *PackageHandler) listMavenPackageVersions(c echo.Context) error { return ph.repositoryHrefErrorResponse(err) } - tangResp, err := ph.TangClient.MavenBuildList(ctx, repositoryHref, groupID, name, "", tangy.PageOptions{}) + tangResp, err := ph.TangClient.MavenVersionsList(ctx, repositoryHref, groupID, name, "", tangy.PageOptions{}) if err != nil { return ce.NewErrorResponse(http.StatusInternalServerError, "Error retrieving package versions", err.Error()) } versions := make([]api.MavenPackageDetailResponse, len(tangResp.Results)) for i, item := range tangResp.Results { + builds := make([]api.ReleaseInfo, len(item.Builds)) + for j, b := range item.Builds { + builds[j] = api.ReleaseInfo{ + Version: b.Version, + Release: b.Release, + CreatedAt: b.CreatedAt, + } + } versions[i] = api.MavenPackageDetailResponse{ Group: groupID, Name: name, Version: item.Version, - Builds: []api.ReleaseInfo{ - { - Version: item.Version, - Release: item.Release, - CreatedAt: item.CreatedAt, - }, - }, + Builds: builds, } } @@ -349,7 +351,7 @@ func (ph *PackageHandler) getMavenPackageDetail(c echo.Context) error { } pageData := ParsePagination(c) - tangResp, err := ph.TangClient.MavenBuildList(ctx, repositoryHref, groupID, name, version, tangy.PageOptions{ + tangResp, err := ph.TangClient.MavenVersionsList(ctx, repositoryHref, groupID, name, version, tangy.PageOptions{ Offset: pageData.Offset, Limit: pageData.Limit, }) @@ -357,14 +359,19 @@ func (ph *PackageHandler) getMavenPackageDetail(c echo.Context) error { return ce.NewErrorResponse(http.StatusInternalServerError, "Error retrieving package builds", err.Error()) } - builds := make([]api.ReleaseInfo, len(tangResp.Results)) - for i, item := range tangResp.Results { - builds[i] = api.ReleaseInfo{ - Version: item.Version, - Release: item.Release, - CreatedAt: item.CreatedAt, + var builds []api.ReleaseInfo + if len(tangResp.Results) > 0 { + for _, b := range tangResp.Results[0].Builds { + builds = append(builds, api.ReleaseInfo{ + Version: b.Version, + Release: b.Release, + CreatedAt: b.CreatedAt, + }) } } + if builds == nil { + builds = []api.ReleaseInfo{} + } response := api.MavenPackageDetailResponse{ Group: groupID, diff --git a/pkg/handler/packages_test.go b/pkg/handler/packages_test.go index c888a8262..e838360f9 100644 --- a/pkg/handler/packages_test.go +++ b/pkg/handler/packages_test.go @@ -213,21 +213,31 @@ func (suite *PackagesSuite) TestListMavenPackageVersionsSuccess() { dist := zest.DistributionResponse{} dist.SetRepository(repositoryHref) - buildListResp := tangy.MavenBuildListResponse{ - Results: []tangy.MavenBuildListItem{ + versionsResp := tangy.MavenVersionsResponse{ + Results: []tangy.MavenVersionsItem{ { GroupID: groupID, ArtifactID: packageName, Version: "3.16.0", - Release: "rhlw-4000", - CreatedAt: "2024-02-01T14:20:00Z", + Builds: []tangy.MavenBuildInfo{ + { + Version: "3.16.0", + Release: "rhlw-4000", + CreatedAt: "2024-02-01T14:20:00Z", + }, + }, }, { GroupID: groupID, ArtifactID: packageName, Version: "3.15.0", - Release: "rhlw-3001", - CreatedAt: "2024-01-15T10:30:00Z", + Builds: []tangy.MavenBuildInfo{ + { + Version: "3.15.0", + Release: "rhlw-3001", + CreatedAt: "2024-01-15T10:30:00Z", + }, + }, }, }, Total: 2, @@ -241,7 +251,7 @@ func (suite *PackagesSuite) TestListMavenPackageVersionsSuccess() { suite.reg.Domain.On("FetchOrCreateDomain", test.MockCtx(), orgID).Return(domainName, nil) suite.pulpClient.On("WithDomain", domainName).Return(suite.pulpClient) suite.pulpClient.On("ResolveRepositoryFromBasePath", test.MockCtx(), basePath).Return(&repositoryHref, nil) - suite.tangClient.On("MavenBuildList", test.MockCtx(), repositoryHref, groupID, packageName, "", tangy.PageOptions{}).Return(buildListResp, nil) + suite.tangClient.On("MavenVersionsList", test.MockCtx(), repositoryHref, groupID, packageName, "", tangy.PageOptions{}).Return(versionsResp, nil) suite.reg.MavenPackages.On("Fetch", test.MockCtx(), groupID, packageName).Return(&models.MavenPackage{ Name: packageName, Summary: utils.Ptr("A reactive library."), @@ -341,7 +351,7 @@ func (suite *PackagesSuite) TestListMavenPackageVersionsTangError() { suite.reg.Domain.On("FetchOrCreateDomain", test.MockCtx(), orgID).Return(domainName, nil) suite.pulpClient.On("WithDomain", domainName).Return(suite.pulpClient) suite.pulpClient.On("ResolveRepositoryFromBasePath", test.MockCtx(), basePath).Return(&repositoryHref, nil) - suite.tangClient.On("MavenBuildList", test.MockCtx(), repositoryHref, groupID, packageName, "", tangy.PageOptions{}).Return(tangy.MavenBuildListResponse{}, fmt.Errorf("failed to fetch versions")) + suite.tangClient.On("MavenVersionsList", test.MockCtx(), repositoryHref, groupID, packageName, "", tangy.PageOptions{}).Return(tangy.MavenVersionsResponse{}, fmt.Errorf("failed to fetch versions")) path := fmt.Sprintf("%s/repositories/%s/maven_packages/%s/%s", api.FullRootPath(), repoUUID, groupID, packageName) req := httptest.NewRequest(http.MethodGet, path, nil) @@ -370,8 +380,8 @@ func (suite *PackagesSuite) TestListMavenPackageVersionsEmpty() { dist := zest.DistributionResponse{} dist.SetRepository(repositoryHref) - buildListResp := tangy.MavenBuildListResponse{ - Results: []tangy.MavenBuildListItem{}, + versionsResp := tangy.MavenVersionsResponse{ + Results: []tangy.MavenVersionsItem{}, Total: 0, Limit: 500, Offset: 0, @@ -383,7 +393,7 @@ func (suite *PackagesSuite) TestListMavenPackageVersionsEmpty() { suite.reg.Domain.On("FetchOrCreateDomain", test.MockCtx(), orgID).Return(domainName, nil) suite.pulpClient.On("WithDomain", domainName).Return(suite.pulpClient) suite.pulpClient.On("ResolveRepositoryFromBasePath", test.MockCtx(), basePath).Return(&repositoryHref, nil) - suite.tangClient.On("MavenBuildList", test.MockCtx(), repositoryHref, groupID, packageName, "", tangy.PageOptions{}).Return(buildListResp, nil) + suite.tangClient.On("MavenVersionsList", test.MockCtx(), repositoryHref, groupID, packageName, "", tangy.PageOptions{}).Return(versionsResp, nil) path := fmt.Sprintf("%s/repositories/%s/maven_packages/%s/%s", api.FullRootPath(), repoUUID, groupID, packageName) req := httptest.NewRequest(http.MethodGet, path, nil) @@ -680,24 +690,27 @@ func (suite *PackagesSuite) TestGetPackageDetailSuccess() { dist := zest.DistributionResponse{} dist.SetRepository(repositoryHref) - buildListResp := tangy.MavenBuildListResponse{ - Results: []tangy.MavenBuildListItem{ + versionsResp := tangy.MavenVersionsResponse{ + Results: []tangy.MavenVersionsItem{ { GroupID: groupID, ArtifactID: packageName, - Version: "3.15.0", - Release: "rhlw-3001", - CreatedAt: "2024-01-15T10:30:00Z", - }, - { - GroupID: groupID, - ArtifactID: packageName, - Version: "3.16.0", - Release: "rhlw-4000", - CreatedAt: "2024-02-01T14:20:00Z", + Version: packageVersion, + Builds: []tangy.MavenBuildInfo{ + { + Version: "3.15.0", + Release: "rhlw-3001", + CreatedAt: "2024-01-15T10:30:00Z", + }, + { + Version: "3.16.0", + Release: "rhlw-4000", + CreatedAt: "2024-02-01T14:20:00Z", + }, + }, }, }, - Total: 2, + Total: 1, Limit: 100, Offset: 0, } @@ -708,7 +721,7 @@ func (suite *PackagesSuite) TestGetPackageDetailSuccess() { suite.reg.Domain.On("FetchOrCreateDomain", test.MockCtx(), orgID).Return(domainName, nil) suite.pulpClient.On("WithDomain", domainName).Return(suite.pulpClient) suite.pulpClient.On("ResolveRepositoryFromBasePath", test.MockCtx(), basePath).Return(&repositoryHref, nil) - suite.tangClient.On("MavenBuildList", test.MockCtx(), repositoryHref, groupID, packageName, packageVersion, tangy.PageOptions{Offset: 0, Limit: 100}).Return(buildListResp, nil) + suite.tangClient.On("MavenVersionsList", test.MockCtx(), repositoryHref, groupID, packageName, packageVersion, tangy.PageOptions{Offset: 0, Limit: 100}).Return(versionsResp, nil) suite.reg.MavenPackages.On("Fetch", test.MockCtx(), groupID, packageName).Return(nil, nil) suite.reg.MavenPackages.On("Create", test.MockCtx(), mock.Anything).Return(nil).Maybe() @@ -754,13 +767,18 @@ func (suite *PackagesSuite) TestGetPackageDetailReturnsCachedMetadata() { dist := zest.DistributionResponse{} dist.SetRepository(repositoryHref) - buildListResp := tangy.MavenBuildListResponse{ - Results: []tangy.MavenBuildListItem{ + versionsResp := tangy.MavenVersionsResponse{ + Results: []tangy.MavenVersionsItem{ { GroupID: groupID, ArtifactID: packageName, Version: packageVersion, - CreatedAt: "2024-01-15T10:30:00Z", + Builds: []tangy.MavenBuildInfo{ + { + Version: packageVersion, + CreatedAt: "2024-01-15T10:30:00Z", + }, + }, }, }, Total: 1, @@ -774,7 +792,7 @@ func (suite *PackagesSuite) TestGetPackageDetailReturnsCachedMetadata() { suite.reg.Domain.On("FetchOrCreateDomain", test.MockCtx(), orgID).Return(domainName, nil) suite.pulpClient.On("WithDomain", domainName).Return(suite.pulpClient) suite.pulpClient.On("ResolveRepositoryFromBasePath", test.MockCtx(), basePath).Return(&repositoryHref, nil) - suite.tangClient.On("MavenBuildList", test.MockCtx(), repositoryHref, groupID, packageName, packageVersion, tangy.PageOptions{Offset: 0, Limit: 100}).Return(buildListResp, nil) + suite.tangClient.On("MavenVersionsList", test.MockCtx(), repositoryHref, groupID, packageName, packageVersion, tangy.PageOptions{Offset: 0, Limit: 100}).Return(versionsResp, nil) suite.reg.MavenPackages.On("Fetch", test.MockCtx(), groupID, packageName).Return(&models.MavenPackage{ GroupID: groupID, Name: packageName, @@ -824,8 +842,8 @@ func (suite *PackagesSuite) TestGetPackageDetailMetadataFetchError() { dist := zest.DistributionResponse{} dist.SetRepository(repositoryHref) - buildListResp := tangy.MavenBuildListResponse{ - Results: []tangy.MavenBuildListItem{}, + versionsResp := tangy.MavenVersionsResponse{ + Results: []tangy.MavenVersionsItem{}, Total: 0, Limit: 100, Offset: 0, @@ -837,7 +855,7 @@ func (suite *PackagesSuite) TestGetPackageDetailMetadataFetchError() { suite.reg.Domain.On("FetchOrCreateDomain", test.MockCtx(), orgID).Return(domainName, nil) suite.pulpClient.On("WithDomain", domainName).Return(suite.pulpClient) suite.pulpClient.On("ResolveRepositoryFromBasePath", test.MockCtx(), basePath).Return(&repositoryHref, nil) - suite.tangClient.On("MavenBuildList", test.MockCtx(), repositoryHref, groupID, packageName, packageVersion, tangy.PageOptions{Offset: 0, Limit: 100}).Return(buildListResp, nil) + suite.tangClient.On("MavenVersionsList", test.MockCtx(), repositoryHref, groupID, packageName, packageVersion, tangy.PageOptions{Offset: 0, Limit: 100}).Return(versionsResp, nil) suite.reg.MavenPackages.On("Fetch", test.MockCtx(), groupID, packageName).Return(nil, fmt.Errorf("database unavailable")) path := fmt.Sprintf("%s/repositories/%s/maven_packages/%s/%s/%s?limit=100&offset=0", api.FullRootPath(), repoUUID, groupID, packageName, packageVersion) @@ -915,7 +933,7 @@ func (suite *PackagesSuite) TestGetPackageDetailTangBuildListError() { suite.reg.Domain.On("FetchOrCreateDomain", test.MockCtx(), orgID).Return(domainName, nil) suite.pulpClient.On("WithDomain", domainName).Return(suite.pulpClient) suite.pulpClient.On("ResolveRepositoryFromBasePath", test.MockCtx(), basePath).Return(&repositoryHref, nil) - suite.tangClient.On("MavenBuildList", test.MockCtx(), repositoryHref, groupID, packageName, "3.15.0", tangy.PageOptions{Offset: 0, Limit: 100}).Return(tangy.MavenBuildListResponse{}, fmt.Errorf("failed to fetch builds")) + suite.tangClient.On("MavenVersionsList", test.MockCtx(), repositoryHref, groupID, packageName, "3.15.0", tangy.PageOptions{Offset: 0, Limit: 100}).Return(tangy.MavenVersionsResponse{}, fmt.Errorf("failed to fetch builds")) path := fmt.Sprintf("%s/repositories/%s/maven_packages/%s/%s/%s?limit=100&offset=0", api.FullRootPath(), repoUUID, groupID, packageName, "3.15.0") req := httptest.NewRequest(http.MethodGet, path, nil) @@ -945,8 +963,8 @@ func (suite *PackagesSuite) TestGetPackageDetailEmptyBuilds() { dist := zest.DistributionResponse{} dist.SetRepository(repositoryHref) - buildListResp := tangy.MavenBuildListResponse{ - Results: []tangy.MavenBuildListItem{}, + versionsResp := tangy.MavenVersionsResponse{ + Results: []tangy.MavenVersionsItem{}, Total: 0, Limit: 100, Offset: 0, @@ -958,7 +976,7 @@ func (suite *PackagesSuite) TestGetPackageDetailEmptyBuilds() { suite.reg.Domain.On("FetchOrCreateDomain", test.MockCtx(), orgID).Return(domainName, nil) suite.pulpClient.On("WithDomain", domainName).Return(suite.pulpClient) suite.pulpClient.On("ResolveRepositoryFromBasePath", test.MockCtx(), basePath).Return(&repositoryHref, nil) - suite.tangClient.On("MavenBuildList", test.MockCtx(), repositoryHref, groupID, packageName, packageVersion, tangy.PageOptions{Offset: 0, Limit: 100}).Return(buildListResp, nil) + suite.tangClient.On("MavenVersionsList", test.MockCtx(), repositoryHref, groupID, packageName, packageVersion, tangy.PageOptions{Offset: 0, Limit: 100}).Return(versionsResp, nil) suite.reg.MavenPackages.On("Fetch", test.MockCtx(), groupID, packageName).Return(nil, nil) suite.reg.MavenPackages.On("Create", test.MockCtx(), mock.Anything).Return(nil).Maybe() diff --git a/scripts/create_maven_repo.sh b/scripts/create_maven_repo.sh index 7ef7a91ff..2ebd30230 100755 --- a/scripts/create_maven_repo.sh +++ b/scripts/create_maven_repo.sh @@ -1,16 +1,24 @@ #!/bin/bash # -# Creates a Maven repository in Pulp backed by Maven Central, then imports it -# into the application as a lightwell repository. +# Creates Maven repositories in Pulp and imports them into the application as +# lightwell repositories. # -# Intended for local development against the Pulp instance started via docker-compose. +# By default, creates two repositories backed by static fixture data that +# mirrors the real lightwell structure: +# - maven-upstream (base_path: java/validated) +# - maven-releases (base_path: java/remediated) +# +# With --seed-from-maven-central, creates a single repository backed by Maven +# Central with a unique suffix. This mode produces more data but is less +# representative of real data. Multiple repos can be created this way. +# +# Intended for local development against the Pulp instance started via +# docker-compose. # # Usage: -# ./scripts/create_maven_repo.sh [--domain DOMAIN] [--remote-url URL] +# ./scripts/create_maven_repo.sh [--domain DOMAIN] +# ./scripts/create_maven_repo.sh --seed-from-maven-central [--remote-url URL] # -# Defaults: -# DOMAIN = lightwell -# REMOTE_URL = https://repo.maven.apache.org/maven2/ set -euo pipefail @@ -29,15 +37,21 @@ SUFFIX="$(date +%s)" REPO_DIR="$(cd "$(dirname "$0")/.."; pwd)" LIGHTWELL_JSON="${REPO_DIR}/pkg/external_repos/lightwell_repos.json" +SEED_FROM_MAVEN_CENTRAL=false + diff +FIXTURE_UPSTREAM_URL="https://content-services.github.io/fixtures/maven/maven-upstream/" +FIXTURE_RELEASES_URL="https://content-services.github.io/fixtures/maven/maven-releases/" + # --------------------------------------------------------------------------- # Parse flags # --------------------------------------------------------------------------- while [[ $# -gt 0 ]]; do case "$1" in - --domain) DOMAIN="$2"; shift 2 ;; - --remote-url) REMOTE_URL="$2"; shift 2 ;; - *) echo "Unknown option: $1" >&2; exit 1 ;; + --domain) DOMAIN="$2"; shift 2 ;; + --remote-url) REMOTE_URL="$2"; shift 2 ;; + --seed-from-maven-central) SEED_FROM_MAVEN_CENTRAL=true; shift ;; + *) echo "Unknown option: $1" >&2; exit 1 ;; esac done @@ -119,6 +133,74 @@ wait_for_task() { exit 1 } +# Creates a Maven remote, repository, and distribution in Pulp. +# create_pulp_repo