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

Use new hasura-inventory endpoint for package search. #3478

Draft
wants to merge 6 commits into
base: version/0-47-0-RC1
Choose a base branch
from
Draft
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
10 changes: 5 additions & 5 deletions internal/runbits/runtime/requirements/requirements.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,12 +608,12 @@ func resolvePkgAndNamespace(prompt prompt.Prompter, packageName string, nsType m
choices := []string{}
values := map[string][]string{}
for _, i := range ingredients {
language := model.LanguageFromNamespace(*i.Ingredient.PrimaryNamespace)
language := model.LanguageFromNamespace(i.Namespace.Namespace)

// Generate ingredient choices to present to the user
name := fmt.Sprintf("%s (%s)", *i.Ingredient.Name, language)
name := fmt.Sprintf("%s (%s)", i.Name, language)
choices = append(choices, name)
values[name] = []string{*i.Ingredient.Name, language}
values[name] = []string{i.Name, language}
}

if len(choices) == 0 {
Expand Down Expand Up @@ -644,7 +644,7 @@ func resolvePkgAndNamespace(prompt prompt.Prompter, packageName string, nsType m
}

func getSuggestions(ns model.Namespace, name string, auth *authentication.Auth) ([]string, error) {
results, err := model.SearchIngredients(ns.String(), name, false, nil, auth)
results, err := model.SearchIngredientsLatest(ns.String(), name, false, true, nil, auth)
if err != nil {
return []string{}, locale.WrapError(err, "package_ingredient_err_search", "Failed to resolve ingredient named: {{.V0}}", name)
}
Expand All @@ -656,7 +656,7 @@ func getSuggestions(ns model.Namespace, name string, auth *authentication.Auth)

suggestions := make([]string, 0, maxResults+1)
for _, result := range results {
suggestions = append(suggestions, fmt.Sprintf(" - %s", *result.Ingredient.Name))
suggestions = append(suggestions, fmt.Sprintf(" - %s", result.Name))
}

return suggestions, nil
Expand Down
72 changes: 23 additions & 49 deletions internal/runners/packages/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ import (
"github.com/ActiveState/cli/internal/output"
"github.com/ActiveState/cli/internal/rtutils/ptr"
"github.com/ActiveState/cli/internal/runbits/commits_runbit"
"github.com/ActiveState/cli/pkg/platform/api/inventory/inventory_models"
hsInventoryModel "github.com/ActiveState/cli/pkg/platform/api/hasura_inventory/model"
"github.com/ActiveState/cli/pkg/platform/api/vulnerabilities/request"
"github.com/ActiveState/cli/pkg/platform/authentication"
"github.com/ActiveState/cli/pkg/platform/model"
"github.com/ActiveState/cli/pkg/project"
"github.com/go-openapi/strfmt"
)

// InfoRunParams tracks the info required for running Info.
Expand Down Expand Up @@ -90,16 +89,18 @@ func (i *Info) Run(params InfoRunParams, nstype model.NamespaceType) error {
}

pkg := packages[0]
ingredientVersion := pkg.LatestVersion
ingredientVersion := pkg.Versions[0] // latest version

if params.Package.Version != "" {
ingredientVersion, err = specificIngredientVersion(pkg.Ingredient.IngredientID, params.Package.Version, i.auth)
if err != nil {
return locale.WrapExternalError(err, "info_err_version_not_found", "Could not find version {{.V0}} for package {{.V1}}", params.Package.Version, params.Package.Name)
for _, v := range pkg.Versions {
if v.Version == params.Package.Version {
ingredientVersion = v
break
}
}
}

authors, err := model.FetchAuthors(pkg.Ingredient.IngredientID, ingredientVersion.IngredientVersionID, i.auth)
authors, err := model.FetchAuthors(&pkg.IngredientID, &ingredientVersion.IngredientVersionID, i.auth)
if err != nil {
return locale.WrapError(err, "package_err_cannot_obtain_authors_info", "Cannot obtain authors info")
}
Expand All @@ -109,8 +110,8 @@ func (i *Info) Run(params InfoRunParams, nstype model.NamespaceType) error {
vulnerabilityIngredients := make([]*request.Ingredient, len(pkg.Versions))
for i, p := range pkg.Versions {
vulnerabilityIngredients[i] = &request.Ingredient{
Name: *pkg.Ingredient.Name,
Namespace: *pkg.Ingredient.PrimaryNamespace,
Name: pkg.Name,
Namespace: pkg.Namespace.Namespace,
Version: p.Version,
}
}
Expand All @@ -122,8 +123,8 @@ func (i *Info) Run(params InfoRunParams, nstype model.NamespaceType) error {
}

i.out.Print(&infoOutput{i.out, structuredOutput{
pkg.Ingredient,
ingredientVersion,
pkg.SearchIngredient,
&ingredientVersion,
authors,
pkg.Versions,
vulns,
Expand All @@ -132,21 +133,6 @@ func (i *Info) Run(params InfoRunParams, nstype model.NamespaceType) error {
return nil
}

func specificIngredientVersion(ingredientID *strfmt.UUID, version string, auth *authentication.Auth) (*inventory_models.IngredientVersion, error) {
ingredientVersions, err := model.FetchIngredientVersions(ingredientID, auth)
if err != nil {
return nil, locale.WrapError(err, "info_err_cannot_obtain_version", "Could not retrieve ingredient version information")
}

for _, iv := range ingredientVersions {
if iv.Version != nil && *iv.Version == version {
return iv, nil
}
}

return nil, locale.NewInputError("err_no_ingredient_version_found", "No ingredient version found")
}

// PkgDetailsTable describes package details.
type PkgDetailsTable struct {
Description string `opts:"omitEmpty" locale:"package_description,[HEADING]Description[/RESET]" json:"description"`
Expand All @@ -171,25 +157,13 @@ func newInfoResult(so structuredOutput) *infoResult {
PkgDetailsTable: &PkgDetailsTable{},
}

if so.Ingredient.Name != nil {
res.name = *so.Ingredient.Name
}

if so.IngredientVersion.Version != nil {
res.version = *so.IngredientVersion.Version
}

if so.Ingredient.Description != nil {
res.PkgDetailsTable.Description = *so.Ingredient.Description
}

if so.Ingredient.Website != "" {
res.PkgDetailsTable.Website = so.Ingredient.Website.String()
}

if so.IngredientVersion.LicenseExpression != nil {
res.PkgDetailsTable.License = fmt.Sprintf("[CYAN]%s[/RESET]", *so.IngredientVersion.LicenseExpression)
res.name = so.Ingredient.Name
res.version = so.IngredientVersion.Version
res.PkgDetailsTable.Description = so.Ingredient.Description
if so.Ingredient.Website != nil {
res.PkgDetailsTable.Website = *so.Ingredient.Website
}
res.PkgDetailsTable.License = fmt.Sprintf("[CYAN]%s[/RESET]", so.IngredientVersion.LicenseExpression)

for _, version := range so.Versions {
res.plainVersions = append(res.plainVersions, version.Version)
Expand Down Expand Up @@ -286,11 +260,11 @@ func newInfoResult(so structuredOutput) *infoResult {
}

type structuredOutput struct {
Ingredient *inventory_models.Ingredient `json:"ingredient"`
IngredientVersion *inventory_models.IngredientVersion `json:"ingredient_version"`
Authors model.Authors `json:"authors"`
Versions []*inventory_models.SearchIngredientsResponseVersion `json:"versions"`
Vulnerabilities []*model.VulnerabilityIngredient `json:"vulnerabilities,omitempty"`
Ingredient *hsInventoryModel.SearchIngredient `json:"ingredient"`
IngredientVersion *hsInventoryModel.IngredientVersion `json:"ingredient_version"`
Authors model.Authors `json:"authors"`
Versions []hsInventoryModel.IngredientVersion `json:"versions"`
Vulnerabilities []*model.VulnerabilityIngredient `json:"vulnerabilities,omitempty"`
}

type infoOutput struct {
Expand Down
6 changes: 3 additions & 3 deletions internal/runners/packages/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (s *Search) Run(params SearchRunParams, nstype model.NamespaceType) error {
if params.ExactTerm {
packages, err = model.SearchIngredientsLatestStrict(ns.String(), params.Ingredient.Name, true, true, &ts, s.auth)
} else {
packages, err = model.SearchIngredientsLatest(ns.String(), params.Ingredient.Name, true, &ts, s.auth)
packages, err = model.SearchIngredientsLatest(ns.String(), params.Ingredient.Name, true, false, &ts, s.auth)
}
if err != nil {
return locale.WrapError(err, "package_err_cannot_obtain_search_results")
Expand Down Expand Up @@ -142,8 +142,8 @@ func (s *Search) getVulns(packages []*model.IngredientAndVersion) ([]*model.Vuln
var ingredients []*request.Ingredient
for _, pkg := range packages {
ingredients = append(ingredients, &request.Ingredient{
Name: *pkg.Ingredient.Name,
Namespace: *pkg.Ingredient.PrimaryNamespace,
Name: pkg.Name,
Namespace: pkg.Namespace.Namespace,
Version: pkg.Version,
})
}
Expand Down
14 changes: 7 additions & 7 deletions internal/runners/packages/searchresult.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ func createSearchResults(packages []*model.IngredientAndVersion, vulns []*model.
var packageNames []string
for _, pkg := range packages {
result := &searchResult{}
result.Name = ptr.From(pkg.Ingredient.Name, "")
result.Description = ptr.From(pkg.Ingredient.Description, "")
result.Website = pkg.Ingredient.Website.String()
result.License = ptr.From(pkg.LatestVersion.LicenseExpression, "")
result.Name = pkg.Name
result.Description = pkg.Description
result.Website = ptr.From(pkg.Website, "")
result.License = pkg.Versions[0].LicenseExpression // latest version

var versions []string
for _, v := range pkg.Versions {
Expand All @@ -44,8 +44,8 @@ func createSearchResults(packages []*model.IngredientAndVersion, vulns []*model.

var ingredientVulns *model.VulnerabilityIngredient
for _, v := range vulns {
if strings.EqualFold(v.Name, *pkg.Ingredient.Name) &&
strings.EqualFold(v.PrimaryNamespace, *pkg.Ingredient.PrimaryNamespace) &&
if strings.EqualFold(v.Name, pkg.Name) &&
strings.EqualFold(v.PrimaryNamespace, pkg.Namespace.Namespace) &&
strings.EqualFold(v.Version, pkg.Version) {
ingredientVulns = v
break
Expand All @@ -56,7 +56,7 @@ func createSearchResults(packages []*model.IngredientAndVersion, vulns []*model.
result.Vulnerabilities = ingredientVulns.Vulnerabilities.Count()
}

packageNames = append(packageNames, *pkg.Ingredient.Name)
packageNames = append(packageNames, pkg.Name)
results = append(results, result)
}

Expand Down
20 changes: 18 additions & 2 deletions internal/runners/publish/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,25 @@ func (r *Runner) Run(params *Params) error {
if err != nil && !errors.As(err, &errSearch404) { // 404 means either the ingredient or the namespace was not found, which is fine
return locale.WrapError(err, "err_uploadingredient_search", "Could not search for ingredient")
}

if len(ingredients) > 0 {
i := ingredients[0].LatestVersion
ingredient = &ParentIngredient{*i.IngredientID, *i.IngredientVersionID, *i.Version, i.Dependencies}
i := ingredients[0]

// Attempt to find the ingredient's dependencies.
var dependencies []inventory_models.Dependency
ingredientVersions, err := model.FetchIngredientVersions(&i.IngredientID, r.auth)
if err != nil {
return locale.WrapError(err, "err_uploadingredient_fetch_versions", "Could not retrieve ingredient version information")
}
for _, iv := range ingredientVersions {
if iv.Version != nil && *iv.Version == i.Version {
dependencies = iv.Dependencies
break
}
}

ingredientVersionID := i.Versions[0].IngredientVersionID // latest version
ingredient = &ParentIngredient{i.IngredientID, ingredientVersionID, i.Version, dependencies}
if params.Version == "" {
isRevision = true
}
Expand Down
24 changes: 24 additions & 0 deletions pkg/platform/api/hasura_inventory/model/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,27 @@ type LastIngredientRevisionTime struct {
type LatestRevisionResponse struct {
RevisionTimes []LastIngredientRevisionTime `json:"last_ingredient_revision_time"`
}

type Namespace struct {
Namespace string `json:"namespace"`
}

type IngredientVersion struct {
Version string `json:"version"`
IngredientVersionID strfmt.UUID `json:"ingredient_version_id"`
LicenseExpression string `json:"license_expression"`
}

type SearchIngredient struct {
Name string `json:"name"`
NormalizedName string `json:"normalized_name"`
Namespace Namespace `json:"namespace"`
IngredientID strfmt.UUID `json:"ingredient_id"`
Description string `json:"description"`
Website *string `json:"website"`
Versions []IngredientVersion `json:"versions"`
}

type SearchIngredientsResponse struct {
SearchIngredients []SearchIngredient `json:"search_ingredients"`
}
53 changes: 53 additions & 0 deletions pkg/platform/api/hasura_inventory/request/search_ingredients.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package request

import (
"fmt"
"strings"
"time"
)

func SearchIngredients(namespaces []string, name string, exact bool, time time.Time, limit, offset int) *searchIngredients {
return &searchIngredients{map[string]interface{}{
"namespaces": fmt.Sprintf("{%s}", strings.Join(namespaces, ",")), // API requires enclosure in {}
"name": name,
"exact": exact,
"time": time,
"limit": limit,
"offset": offset,
}}
}

type searchIngredients struct {
vars map[string]interface{}
}

func (s *searchIngredients) Query() string {
return `
query ($namespaces: _non_empty_citext, $name: non_empty_citext, $exact: Boolean!, $time: timestamptz!, $limit: Int!, $offset: Int!) {
search_ingredients(
args: {namespaces: $namespaces, name_: $name, exact: $exact, timestamp_: $time, limit_: $limit, offset_: $offset}
) {
name
normalized_name
namespace {
namespace
}
ingredient_id
description
website
versions(order_by:{sortable_version:desc}) {
version
ingredient_version_id
license_expression
}
}
}`
}

func (s *searchIngredients) Vars() (map[string]interface{}, error) {
return s.vars, nil
}

func (s *searchIngredients) SetOffset(offset int) {
s.vars["offset"] = offset
}
Loading
Loading