Skip to content

Commit

Permalink
Implement advanced requirements for state manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
Naatan committed Jul 17, 2024
1 parent 01e2aee commit e5149f0
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 72 deletions.
12 changes: 4 additions & 8 deletions internal/locale/locales/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ field_localcheckouts:
other: Local Checkouts
field_platforms:
other: Platforms
field_value:
other: Value
err_conflicting_branch_while_checkedout:
other: |
Cannot activate branch [NOTICE]{{.V0}}[/RESET]. Branch [NOTICE]{{.V1}}[/RESET] is already checked out.
Expand Down Expand Up @@ -1557,12 +1559,6 @@ err_main_jwt:
State Tool could not obtain an authentication token from its internal service.
Please try again or contact support if this issue persists.
Error received: {{.V0}}
err_runtime_needs_refresh:
other: Your runtime needs to be updated, please run '[ACTIONABLE]state refresh[/RESET]' and then try again.
err_pull_no_common_parent:
other: |
The local commit ID [NOTICE]{{.V0}}[/RESET] and latest remote commit ID [NOTICE]{{.V1}}[/RESET] have no common parent.
To review your project history run '[ACTIONABLE]state history[/RESET]'.
warn_package_list_runtime:
warn_additional_requirements:
other: |
[WARNING]WARNING:[/RESET] Could not initialize runtime. Resolved version information will not be available. Run '[ACTIONABLE]state refresh[/RESET]' for more information.
[WARNING]WARNING:[/RESET] This project has additional build criteria that cannot be managed through the State Tool, please edit your [ACTIONABLE]buildscript.as[/RESET] file manually to modify these:
15 changes: 7 additions & 8 deletions internal/output/plain.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const (
OmitEmpty PlainOpts = "omitEmpty"
// HideDash hides the dash in table output
HideDash PlainOpts = "hideDash"
// OmitKey hides the current struct key from output, its value is still printed
OmitKey PlainOpts = "omitKey"
)

// Plain is our plain outputer, it uses reflect to marshal the data.
Expand Down Expand Up @@ -195,14 +197,6 @@ func sprintStruct(value interface{}) (string, error) {
return sprintTable(true, false, slice)
}

if funk.Contains(field.opts, string(HideDash)) {
slice, err := asSlice(field.value)
if err != nil {
return "", err
}
return sprintTable(false, true, slice)
}

stringValue, err := sprint(field.value, field.opts)
if err != nil {
return "", err
Expand All @@ -211,6 +205,11 @@ func sprintStruct(value interface{}) (string, error) {
continue
}

if funk.Contains(field.opts, string(OmitKey)) {
result = append(result, stringValue)
continue
}

if isStruct(field.value) || isSlice(field.value) {
stringValue = "\n" + stringValue
}
Expand Down
46 changes: 27 additions & 19 deletions internal/runners/manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ import (
"github.com/ActiveState/cli/internal/errs"
"github.com/ActiveState/cli/internal/locale"
"github.com/ActiveState/cli/internal/output"
buildscript_runbit "github.com/ActiveState/cli/internal/runbits/buildscript"
"github.com/ActiveState/cli/internal/runbits/rationalize"
"github.com/ActiveState/cli/pkg/buildplan"
"github.com/ActiveState/cli/pkg/localcommit"
"github.com/ActiveState/cli/pkg/platform/api/buildplanner/types"
"github.com/ActiveState/cli/pkg/buildscript"
"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/platform/model/buildplanner"
"github.com/ActiveState/cli/pkg/platform/runtime"
"github.com/ActiveState/cli/pkg/platform/runtime/target"
"github.com/ActiveState/cli/pkg/project"
Expand Down Expand Up @@ -76,7 +75,12 @@ func (m *Manifest) Run() (rerr error) {
return errs.Wrap(err, "Could not fetch vulnerabilities")
}

m.out.Print(newRequirements(reqs, bpReqs, vulns))
reqOut := newRequirements(reqs, bpReqs, vulns)
if m.out.Type().IsStructured() {
m.out.Print(reqOut)
} else {
reqOut.Print(m.out)
}

if len(vulns) > 0 {
m.out.Notice(locale.Tl("manifest_vulnerabilities_info", "\nFor CVE info run '[ACTIONABLE]state security[/RESET]'"))
Expand All @@ -85,14 +89,8 @@ func (m *Manifest) Run() (rerr error) {
return nil
}

func (m *Manifest) fetchRequirements() ([]types.Requirement, error) {
commitID, err := localcommit.Get(m.project.Dir())
if err != nil {
return nil, errs.Wrap(err, "Could not get commit ID")
}

bp := buildplanner.NewBuildPlannerModel(m.auth)
script, err := bp.GetBuildScript(commitID.String())
func (m *Manifest) fetchRequirements() ([]buildscript.Requirement, error) {
script, err := buildscript_runbit.ScriptFromProject(m.project)
if err != nil {
return nil, errs.Wrap(err, "Could not get remote build expr and time")
}
Expand Down Expand Up @@ -128,12 +126,16 @@ func (m *Manifest) fetchBuildplanRequirements() (buildplan.Ingredients, error) {
return bp.RequestedIngredients(), nil
}

func (m *Manifest) fetchVulnerabilities(reqs []types.Requirement) (vulnerabilities, error) {
func (m *Manifest) fetchVulnerabilities(reqs []buildscript.Requirement) (vulnerabilities, error) {
vulns := make(vulnerabilities)

if !m.auth.Authenticated() {
for _, req := range reqs {
vulns.addVulnerability(req.Name, req.Namespace, &requirementVulnerabilities{
r, ok := req.(buildscript.DependencyRequirement)
if !ok {
continue
}
vulns.add(r.Name, r.Namespace, &requirementVulnerabilities{
authenticated: false,
})
}
Expand All @@ -143,13 +145,19 @@ func (m *Manifest) fetchVulnerabilities(reqs []types.Requirement) (vulnerabiliti
var ingredients []*request.Ingredient
for _, req := range reqs {
var version string
if req.VersionRequirement != nil {
version = model.BuildPlannerVersionConstraintsToString(req.VersionRequirement)
r, ok := req.(buildscript.DependencyRequirement)
if !ok {
// We can't report vulnerabilities on revisions because they don't supply a namespace.
// https://activestatef.atlassian.net/browse/PB-5165
continue
}
if r.VersionRequirement != nil {
version = model.BuildPlannerVersionConstraintsToString(r.VersionRequirement)
}

ingredients = append(ingredients, &request.Ingredient{
Name: req.Name,
Namespace: req.Namespace,
Name: r.Name,
Namespace: r.Namespace,
Version: version,
})
}
Expand All @@ -160,7 +168,7 @@ func (m *Manifest) fetchVulnerabilities(reqs []types.Requirement) (vulnerabiliti
}

for _, vuln := range ingredientVulnerabilities {
vulns.addVulnerability(vuln.Name, vuln.PrimaryNamespace, &requirementVulnerabilities{
vulns.add(vuln.Name, vuln.PrimaryNamespace, &requirementVulnerabilities{
Count: vuln.Vulnerabilities.Count(),
authenticated: true,
})
Expand Down
55 changes: 41 additions & 14 deletions internal/runners/manifest/requirements.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"github.com/ActiveState/cli/internal/locale"
"github.com/ActiveState/cli/internal/output"
"github.com/ActiveState/cli/pkg/buildplan"
"github.com/ActiveState/cli/pkg/platform/api/buildplanner/types"
"github.com/ActiveState/cli/pkg/buildscript"
platformModel "github.com/ActiveState/cli/pkg/platform/model"
)

Expand All @@ -16,24 +16,39 @@ type requirement struct {
}

type requirements struct {
Requirements []*requirement `json:"requirements"`
Requirements []requirement `json:"requirements"`
UnknownRequirements []buildscript.UnknownRequirement `json:"unknown_requirements,omitempty"`
}

func newRequirements(reqs []types.Requirement, bpReqs buildplan.Ingredients, vulns vulnerabilities) requirements {
var result []*requirement
func newRequirements(reqs []buildscript.Requirement, bpReqs buildplan.Ingredients, vulns vulnerabilities) requirements {
var knownReqs []requirement
var unknownReqs []buildscript.UnknownRequirement
for _, req := range reqs {
result = append(result, &requirement{
Name: req.Name,
Namespace: processNamespace(req.Namespace),
ResolvedVersion: resolveVersion(req, bpReqs),
Vulnerabilities: vulns.getVulnerability(req.Name, req.Namespace),
})
switch r := req.(type) {
case buildscript.DependencyRequirement:
knownReqs = append(knownReqs, requirement{
Name: r.Name,
Namespace: processNamespace(r.Namespace),
ResolvedVersion: resolveVersion(r.Requirement, bpReqs),
Vulnerabilities: vulns.get(r.Name, r.Namespace),
})
case buildscript.RevisionRequirement:
knownReqs = append(knownReqs, requirement{
Name: r.Name,
ResolvedVersion: &resolvedVersion{Requested: r.RevisionID.String()},
})
case buildscript.UnknownRequirement:
unknownReqs = append(unknownReqs, r)
}
}

return requirements{Requirements: result}
return requirements{
Requirements: knownReqs,
UnknownRequirements: unknownReqs,
}
}

func (o requirements) MarshalOutput(_ output.Format) interface{} {
func (o requirements) Print(out output.Outputer) {
type requirementOutput struct {
Name string `locale:"manifest_name,Name"`
Version string `locale:"manifest_version,Version"`
Expand All @@ -57,11 +72,23 @@ func (o requirements) MarshalOutput(_ output.Format) interface{} {
requirementsOutput = append(requirementsOutput, requirementOutput)
}

return struct {
Requirements []*requirementOutput `locale:"," opts:"hideDash"`
out.Print(struct {
Requirements []*requirementOutput `locale:"," opts:"hideDash,omitKey"`
}{
Requirements: requirementsOutput,
})

if len(o.UnknownRequirements) > 0 {
out.Notice("")
out.Notice(locale.Tt("warn_additional_requirements"))
out.Notice("")
out.Print(struct {
Requirements []buildscript.UnknownRequirement `locale:"," opts:"hideDash,omitKey"`
}{
Requirements: o.UnknownRequirements,
})
}

}

func (o requirements) MarshalStructured(f output.Format) interface{} {
Expand Down
4 changes: 2 additions & 2 deletions internal/runners/manifest/vulnerabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ func (v *requirementVulnerabilities) String() string {

type vulnerabilities map[string]*requirementVulnerabilities

func (v vulnerabilities) getVulnerability(name, namespace string) *requirementVulnerabilities {
func (v vulnerabilities) get(name, namespace string) *requirementVulnerabilities {
return v[fmt.Sprintf("%s/%s", namespace, name)]
}

func (v vulnerabilities) addVulnerability(name, namespace string, vulns *requirementVulnerabilities) {
func (v vulnerabilities) add(name, namespace string, vulns *requirementVulnerabilities) {
v[fmt.Sprintf("%s/%s", namespace, name)] = vulns
}
23 changes: 15 additions & 8 deletions pkg/buildscript/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
mainKey = "main"

reqFuncName = "Req"
revFuncName = "Revision"
eqFuncName = "Eq"
neFuncName = "Ne"
gtFuncName = "Gt"
Expand Down Expand Up @@ -53,7 +54,7 @@ func assignmentString(a *Assignment) string {
return fmt.Sprintf("%s = %s", a.Key, valueString(a.Value))
}

func indent(s string) string {
func indentByTab(s string) string {
return fmt.Sprintf("\t%s", strings.ReplaceAll(s, "\n", "\n\t"))
}

Expand All @@ -66,7 +67,7 @@ func valueString(v *Value) string {
buf := bytes.Buffer{}
buf.WriteString("[\n")
for i, item := range *v.List {
buf.WriteString(indent(valueString(item)))
buf.WriteString(indentByTab(valueString(item)))
if i+1 < len(*v.List) {
buf.WriteString(",")
}
Expand All @@ -91,7 +92,7 @@ func valueString(v *Value) string {
buf := bytes.Buffer{}
buf.WriteString("{\n")
for i, pair := range *v.Object {
buf.WriteString(indent(assignmentString(pair)))
buf.WriteString(indentByTab(assignmentString(pair)))
if i+1 < len(*v.Object) {
buf.WriteString(",")
}
Expand Down Expand Up @@ -121,7 +122,7 @@ func funcCallString(f *FuncCall) string {
var (
newline = "\n"
comma = ","
indent = indent
indent = indentByTab
)

if funk.Contains(inlineFunctions, f.Name) {
Expand All @@ -135,16 +136,22 @@ func funcCallString(f *FuncCall) string {
buf := bytes.Buffer{}
buf.WriteString(fmt.Sprintf("%s(%s", f.Name, newline))

for i, argument := range f.Arguments {
buf.WriteString(argsToString(f.Arguments, newline, comma, indent))

buf.WriteString(")")
return buf.String()
}

func argsToString(args []*Value, newline, comma string, indent func(string) string) string {
buf := bytes.Buffer{}
for i, argument := range args {
buf.WriteString(indent(valueString(argument)))

if i+1 < len(f.Arguments) {
if i+1 < len(args) {
buf.WriteString(comma)
}

buf.WriteString(newline)
}

buf.WriteString(")")
return buf.String()
}
1 change: 1 addition & 0 deletions pkg/buildscript/marshal_buildexpression.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
requirementNamespaceKey = "namespace"
requirementVersionRequirementsKey = "version_requirements"
requirementVersionKey = "version"
requirementRevisionIDKey = "revision_id"
requirementComparatorKey = "comparator"
)

Expand Down
Loading

0 comments on commit e5149f0

Please sign in to comment.