• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

UiPath / uipathcli / 14386736320

10 Apr 2025 05:30PM UTC coverage: 90.345% (-0.2%) from 90.504%
14386736320

Pull #169

github

thschmitt
Add restore command for UiPath Studio projects

Add `uipath studio package restore` command to restore package
dependencies of the UiPath Studio Project.

Supported arguments:

- `--source <path-to-studio-project>`
  The path to the UiPath Studio Project
  (defaults to the current working directory)

- `--destination <target-package-folder>`
  Target folder for the dependency packages
  (defaults to `packages/` in the current working directory)

Implements https://github.com/UiPath/uipathcli/issues/159
Pull Request #169: Add restore command for UiPath Studio projects

116 of 140 new or added lines in 4 files covered. (82.86%)

6101 of 6753 relevant lines covered (90.35%)

1.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.85
/plugin/studio/package_restore_command.go
1
package studio
2

3
import (
4
        "bytes"
5
        "encoding/json"
6
        "fmt"
7
        "os"
8
        "path/filepath"
9
        "strings"
10
        "time"
11

12
        "github.com/UiPath/uipathcli/log"
13
        "github.com/UiPath/uipathcli/output"
14
        "github.com/UiPath/uipathcli/plugin"
15
        "github.com/UiPath/uipathcli/utils/process"
16
        "github.com/UiPath/uipathcli/utils/visualization"
17
)
18

19
// The PackageRestoreCommand restores the packages of the project
20
type PackageRestoreCommand struct {
21
        Exec process.ExecProcess
22
}
23

24
func (c PackageRestoreCommand) Command() plugin.Command {
1✔
25
        return *plugin.NewCommand("studio").
1✔
26
                WithCategory("package", "Package", "UiPath Studio package-related actions").
1✔
27
                WithOperation("restore", "Package Project", "Restores the packages of the project").
1✔
28
                WithParameter("source", plugin.ParameterTypeString, "Path to a project.json file or a folder containing project.json file (default: .)", false).
1✔
29
                WithParameter("destination", plugin.ParameterTypeString, "The output folder (default ./packages)", false)
1✔
30
}
1✔
31

32
func (c PackageRestoreCommand) Execute(ctx plugin.ExecutionContext, writer output.OutputWriter, logger log.Logger) error {
1✔
33
        source, err := c.getSource(ctx)
1✔
34
        if err != nil {
2✔
35
                return err
1✔
36
        }
1✔
37
        destination := c.getDestination(ctx)
1✔
38

1✔
39
        params := newPackageRestoreParams(
1✔
40
                ctx.Organization,
1✔
41
                ctx.Tenant,
1✔
42
                ctx.BaseUri,
1✔
43
                ctx.Auth.Token,
1✔
44
                source,
1✔
45
                destination)
1✔
46

1✔
47
        result, err := c.execute(*params, ctx.Debug, logger)
1✔
48
        if err != nil {
1✔
NEW
49
                return err
×
NEW
50
        }
×
51

52
        json, err := json.Marshal(result)
1✔
53
        if err != nil {
1✔
NEW
54
                return fmt.Errorf("restore command failed: %v", err)
×
NEW
55
        }
×
56
        return writer.WriteResponse(*output.NewResponseInfo(200, "200 OK", "HTTP/1.1", map[string][]string{}, bytes.NewReader(json)))
1✔
57
}
58

59
func (c PackageRestoreCommand) execute(params packageRestoreParams, debug bool, logger log.Logger) (*packageRestoreResult, error) {
1✔
60
        projectReader := newStudioProjectReader(params.Source)
1✔
61
        project, err := projectReader.ReadMetadata()
1✔
62
        if err != nil {
1✔
NEW
63
                return nil, err
×
NEW
64
        }
×
65
        supported, err := project.TargetFramework.IsSupported()
1✔
66
        if !supported {
1✔
NEW
67
                return nil, err
×
NEW
68
        }
×
69

70
        uipcli := newUipcli(c.Exec, logger)
1✔
71
        err = uipcli.Initialize(project.TargetFramework)
1✔
72
        if err != nil {
1✔
NEW
73
                return nil, err
×
NEW
74
        }
×
75

76
        if !debug {
2✔
77
                bar := c.newProgressBar(logger)
1✔
78
                defer close(bar)
1✔
79
        }
1✔
80
        args := c.prepareRestoreArguments(params)
1✔
81
        exitCode, stdErr, err := uipcli.ExecuteAndWait(args...)
1✔
82
        if err != nil {
1✔
NEW
83
                return nil, err
×
NEW
84
        }
×
85

86
        var result *packageRestoreResult
1✔
87
        if exitCode == 0 {
2✔
88
                if err != nil {
1✔
NEW
89
                        return nil, err
×
NEW
90
                }
×
91
                result = newSucceededPackageRestoreResult(
1✔
92
                        params.Destination,
1✔
93
                        project.Name,
1✔
94
                        project.Description,
1✔
95
                        project.ProjectId)
1✔
NEW
96
        } else {
×
NEW
97
                result = newFailedPackageRestoreResult(
×
NEW
98
                        stdErr,
×
NEW
99
                        &project.Name,
×
NEW
100
                        &project.Description,
×
NEW
101
                        &project.ProjectId)
×
NEW
102
        }
×
103
        return result, nil
1✔
104
}
105

106
func (c PackageRestoreCommand) prepareRestoreArguments(params packageRestoreParams) []string {
1✔
107
        source, _ := strings.CutSuffix(params.Source, defaultProjectJson)
1✔
108
        args := []string{"package", "restore", source, "--restoreFolder", params.Destination}
1✔
109
        if params.AuthToken != nil && params.Organization != "" {
2✔
110
                args = append(args, "--libraryOrchestratorUrl", params.BaseUri.String())
1✔
111
                args = append(args, "--libraryOrchestratorAuthToken", params.AuthToken.Value)
1✔
112
                args = append(args, "--libraryOrchestratorAccountName", params.Organization)
1✔
113
                if params.Tenant != "" {
2✔
114
                        args = append(args, "--libraryOrchestratorTenant", params.Tenant)
1✔
115
                }
1✔
116
        }
117
        return args
1✔
118
}
119

120
func (c PackageRestoreCommand) newProgressBar(logger log.Logger) chan struct{} {
1✔
121
        progressBar := visualization.NewProgressBar(logger)
1✔
122
        ticker := time.NewTicker(10 * time.Millisecond)
1✔
123
        cancel := make(chan struct{})
1✔
124
        var percent float64 = 0
1✔
125
        go func() {
2✔
126
                for {
2✔
127
                        select {
1✔
128
                        case <-ticker.C:
1✔
129
                                progressBar.UpdatePercentage("restoring...  ", percent)
1✔
130
                                percent = percent + 1
1✔
131
                                if percent > 100 {
2✔
132
                                        percent = 0
1✔
133
                                }
1✔
134
                        case <-cancel:
1✔
135
                                ticker.Stop()
1✔
136
                                progressBar.Remove()
1✔
137
                                return
1✔
138
                        }
139
                }
140
        }()
141
        return cancel
1✔
142
}
143

144
func (c PackageRestoreCommand) getSource(ctx plugin.ExecutionContext) (string, error) {
1✔
145
        source := c.getParameter("source", ".", ctx.Parameters)
1✔
146
        source, _ = filepath.Abs(source)
1✔
147
        fileInfo, err := os.Stat(source)
1✔
148
        if err != nil {
2✔
149
                return "", fmt.Errorf("%s not found", defaultProjectJson)
1✔
150
        }
1✔
151
        if fileInfo.IsDir() {
2✔
152
                source = filepath.Join(source, defaultProjectJson)
1✔
153
        }
1✔
154
        return source, nil
1✔
155
}
156

157
func (c PackageRestoreCommand) getDestination(ctx plugin.ExecutionContext) string {
1✔
158
        destination := c.getParameter("destination", "./packages/", ctx.Parameters)
1✔
159
        destination, _ = filepath.Abs(destination)
1✔
160
        return destination
1✔
161
}
1✔
162

163
func (c PackageRestoreCommand) getParameter(name string, defaultValue string, parameters []plugin.ExecutionParameter) string {
1✔
164
        result := defaultValue
1✔
165
        for _, p := range parameters {
2✔
166
                if p.Name == name {
2✔
167
                        if data, ok := p.Value.(string); ok {
2✔
168
                                result = data
1✔
169
                                break
1✔
170
                        }
171
                }
172
        }
173
        return result
1✔
174
}
175

176
func NewPackageRestoreCommand() *PackageRestoreCommand {
1✔
177
        return &PackageRestoreCommand{process.NewExecProcess()}
1✔
178
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc