Skip to content

Commit

Permalink
Merge pull request #3497 from ActiveState/DX-3056
Browse files Browse the repository at this point in the history
Add `state export deptree` commands
  • Loading branch information
Naatan authored Sep 24, 2024
2 parents 44d3237 + 34c0421 commit 404ace9
Show file tree
Hide file tree
Showing 8 changed files with 446 additions and 9 deletions.
7 changes: 7 additions & 0 deletions cmd/state/internal/cmdtree/cmdtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ func New(prime *primer.Values, args ...string) *CmdTree {
newOpenCommand(prime),
)

deptree := newExportDepTreeCommand(prime)
deptree.AddChildren(
newExportDepTreeArtifactsCommand(prime),
newExportDepTreeIngredientsCommand(prime),
)

exportCmd := newExportCommand(prime)
exportCmd.AddChildren(
newJWTCommand(prime),
Expand All @@ -49,6 +55,7 @@ func New(prime *primer.Values, args ...string) *CmdTree {
newExportLogCommand(prime),
newExportRuntimeCommand(prime),
newExportBuildPlanCommand(prime),
deptree,
)

platformsCmd := newPlatformsCommand(prime)
Expand Down
104 changes: 104 additions & 0 deletions cmd/state/internal/cmdtree/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/ActiveState/cli/internal/primer"
"github.com/ActiveState/cli/internal/runners/export"
"github.com/ActiveState/cli/internal/runners/export/config"
"github.com/ActiveState/cli/internal/runners/export/deptree"
"github.com/ActiveState/cli/internal/runners/export/docs"
"github.com/ActiveState/cli/internal/runners/export/ghactions"
"github.com/ActiveState/cli/pkg/project"
Expand Down Expand Up @@ -266,3 +267,106 @@ func newExportBuildPlanCommand(prime *primer.Values) *captain.Command {

return cmd
}

func newExportDepTreeCommand(prime *primer.Values) *captain.Command {
cmd := captain.NewCommand(
"deptree",
locale.Tl("export_dep_tree_title", "Export Dependency Tree"),
locale.Tl("export_dep_tree_description", "Export the dependency tree for your project"),
prime,
[]*captain.Flag{},
[]*captain.Argument{},
func(ccmd *captain.Command, _ []string) error {
prime.Output().Print(ccmd.Help())
return nil
},
)
cmd.SetHidden(true) // For development purposes only at the moment
cmd.SetUnstable(true)
return cmd
}

func newExportDepTreeArtifactsCommand(prime *primer.Values) *captain.Command {
params := deptree.ArtifactParams{Namespace: &project.Namespaced{}}
runner := deptree.NewByArtifacts(prime)
cmd := captain.NewCommand(
"artifacts",
locale.Tl("export_dep_tree_title", "Export Dependency Tree"),
locale.Tl("export_dep_tree_description", "Export the dependency tree for your project"),
prime,
[]*captain.Flag{
{
Name: "namespace",
Description: locale.Tl("export_dep_tree_flags_namespace_description", "The namespace of the project to inspect dependencies for"),
Value: params.Namespace,
},
{
Name: "commit",
Description: locale.Tl("export_dep_tree_flags_commit_description", "The commit ID to inspect dependencies for"),
Value: &params.CommitID,
},
{
Name: "req",
Description: locale.Tl("export_dep_tree_flag_req_description", "Requirement name to filter for"),
Value: &params.Req,
},
{
Name: "platform",
Description: locale.Tl("export_dep_tree_flag_platform_description", "Platform ID to filter for (defaults to host platform)"),
Value: &params.PlatformID,
},
{
Name: "limit",
Description: locale.Tl("export_dep_tree_flag_limit_description", "Limit the recursion level"),
Value: &params.LevelLimit,
},
},
[]*captain.Argument{},
func(ccmd *captain.Command, _ []string) error {
return runner.Run(params)
},
)
cmd.SetHidden(true) // For development purposes only at the moment
cmd.SetUnstable(true)
return cmd
}

func newExportDepTreeIngredientsCommand(prime *primer.Values) *captain.Command {
params := deptree.IngredientParams{Namespace: &project.Namespaced{}}
runner := deptree.NewByIngredients(prime)
cmd := captain.NewCommand(
"ingredients",
locale.Tl("export_dep_tree_title", "Export Dependency Tree"),
locale.Tl("export_dep_tree_description", "Export the dependency tree for your project"),
prime,
[]*captain.Flag{
{
Name: "namespace",
Description: locale.Tl("export_dep_tree_flags_namespace_description", "The namespace of the project to inspect dependencies for"),
Value: params.Namespace,
},
{
Name: "commit",
Description: locale.Tl("export_dep_tree_flags_commit_description", "The commit ID to inspect dependencies for"),
Value: &params.CommitID,
},
{
Name: "req",
Description: locale.Tl("export_dep_tree_flag_req_description", "Requirement name to filter for"),
Value: &params.Req,
},
{
Name: "limit",
Description: locale.Tl("export_dep_tree_flag_limit_description", "Limit the recursion level"),
Value: &params.LevelLimit,
},
},
[]*captain.Argument{},
func(ccmd *captain.Command, _ []string) error {
return runner.Run(params)
},
)
cmd.SetHidden(true) // For development purposes only at the moment
cmd.SetUnstable(true)
return cmd
}
142 changes: 142 additions & 0 deletions internal/runners/export/deptree/artifacts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package deptree

import (
"fmt"
"strings"

"github.com/ActiveState/cli/internal/errs"
"github.com/ActiveState/cli/internal/logging"
"github.com/ActiveState/cli/internal/primer"
"github.com/ActiveState/cli/internal/runbits/rationalize"
"github.com/ActiveState/cli/internal/sliceutils"
"github.com/ActiveState/cli/pkg/buildplan"
"github.com/ActiveState/cli/pkg/platform/model"
"github.com/ActiveState/cli/pkg/platform/model/buildplanner"
"github.com/ActiveState/cli/pkg/project"
"github.com/ActiveState/cli/pkg/sysinfo"
"github.com/go-openapi/strfmt"
)

type primeable interface {
primer.Auther
primer.Outputer
primer.Configurer
primer.Projecter
primer.Analyticer
primer.SvcModeler
}

type ArtifactParams struct {
Namespace *project.Namespaced
CommitID string
Req string
PlatformID string
LevelLimit int
}

type DeptreeByArtifacts struct {
prime primeable
}

func NewByArtifacts(prime primeable) *DeptreeByArtifacts {
return &DeptreeByArtifacts{
prime: prime,
}
}

func (d *DeptreeByArtifacts) Run(params ArtifactParams) error {
logging.Debug("Execute DepTree")

out := d.prime.Output()
proj := d.prime.Project()
if proj == nil {
return rationalize.ErrNoProject
}

ns, err := resolveNamespace(params.Namespace, params.CommitID, d.prime)
if err != nil {
return errs.Wrap(err, "Could not resolve namespace")
}

bpm := buildplanner.NewBuildPlannerModel(d.prime.Auth())
commit, err := bpm.FetchCommit(*ns.CommitID, ns.Owner, ns.Project, nil)
if err != nil {
return errs.Wrap(err, "Could not get remote build expr and time for provided commit")
}

bp := commit.BuildPlan()

platformID := strfmt.UUID(params.PlatformID)
if platformID == "" {
platformID, err = model.FilterCurrentPlatform(sysinfo.OS().String(), bp.Platforms(), "")
if err != nil {
return errs.Wrap(err, "Could not get platform ID")
}
}

levelLimit := params.LevelLimit
if levelLimit == 0 {
levelLimit = 10
}

ingredients := bp.RequestedIngredients()
for _, ingredient := range ingredients {
if params.Req != "" && ingredient.Name != params.Req {
continue
}
out.Print(fmt.Sprintf("• [ACTIONABLE]%s/%s[/RESET] ([DISABLED]%s[/RESET])", ingredient.Namespace, ingredient.Name, ingredient.IngredientID))
d.printArtifacts(
nil,
ingredient.Artifacts.Filter(
buildplan.FilterPlatformArtifacts(platformID),
),
platformID,
1,
levelLimit,
)
}

return nil
}

func (d *DeptreeByArtifacts) printArtifacts(
parents []*buildplan.Artifact,
as buildplan.Artifacts,
platformID strfmt.UUID,
level int,
levelLimit int) {
indent := strings.Repeat(" ", level)
if level == levelLimit {
d.prime.Output().Print(indent + indentValue + "[ORANGE]Recursion limit reached[/RESET]")
return
}
count := 0
for _, a := range as {
if len(sliceutils.Filter(parents, func(p *buildplan.Artifact) bool { return p.ArtifactID == a.ArtifactID })) != 0 {
d.prime.Output().Print(fmt.Sprintf("%s • Recurse to [CYAN]%s[/RESET] ([DISABLED]%s[/RESET])", indent, a.DisplayName, a.ArtifactID))
continue
}
depTypes := []string{}
if a.IsRuntimeDependency {
depTypes = append(depTypes, "[GREEN]Runtime[/RESET]")
}
if a.IsBuildtimeDependency {
depTypes = append(depTypes, "[ORANGE]Buildtime[/RESET]")
}
mime := ""
if !buildplanner.IsStateToolArtifact(a.MimeType) {
mime = fmt.Sprintf(" ([DISABLED]%s[/RESET])", a.MimeType)
}
count = count + 1
d.prime.Output().Print(fmt.Sprintf("%s%d. [CYAN]%s[/RESET] [%s] ([DISABLED]%s[/RESET]) %s", indent, count, a.DisplayName, strings.Join(depTypes, "|"), a.ArtifactID, mime))
d.printArtifacts(
append(parents, a),
a.Dependencies(false, nil).Filter(
buildplan.FilterPlatformArtifacts(platformID),
),
platformID,
level+1,
levelLimit,
)
}
}
56 changes: 56 additions & 0 deletions internal/runners/export/deptree/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package deptree

import (
"github.com/ActiveState/cli/internal/constants"
"github.com/ActiveState/cli/internal/errs"
"github.com/ActiveState/cli/internal/locale"
"github.com/ActiveState/cli/internal/runbits/rationalize"
"github.com/ActiveState/cli/pkg/localcommit"
"github.com/ActiveState/cli/pkg/platform/model"
"github.com/ActiveState/cli/pkg/project"
"github.com/go-openapi/strfmt"
)

func resolveNamespace(inputNs *project.Namespaced, inputCommitID string, prime primeable) (*project.Namespaced, error) {
out := prime.Output()
proj := prime.Project()
if proj == nil {
return nil, rationalize.ErrNoProject
}

ns := inputNs
dir := "https://" + constants.PlatformURL + "/" + ns.String()
if !ns.IsValid() {
ns = proj.Namespace()
dir = proj.Dir()
}

commitID := strfmt.UUID(inputCommitID)
if commitID == "" {
if inputNs.IsValid() {
p, err := model.FetchProjectByName(ns.Owner, ns.Project, prime.Auth())
if err != nil {
return nil, errs.Wrap(err, "Unable to get project")
}
branch, err := model.DefaultBranchForProject(p)
if err != nil {
return nil, errs.Wrap(err, "Could not grab branch for project")
}
if branch.CommitID == nil {
return nil, errs.New("branch has not commit")
}
ns.CommitID = branch.CommitID
} else {
var err error
commitID, err = localcommit.Get(proj.Dir())
if err != nil {
return nil, errs.Wrap(err, "Unable to get local commit ID")
}
ns.CommitID = &commitID
}
}

out.Notice(locale.Tr("operating_message", ns.String(), dir))

return ns, nil
}
Loading

0 comments on commit 404ace9

Please sign in to comment.