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

UiPath / uipathcli / 12410563606

19 Dec 2024 10:10AM UTC coverage: 89.869% (+0.1%) from 89.735%
12410563606

push

github

thschmitt
Simplify parameter handling in plugins

71 of 75 new or added lines in 5 files covered. (94.67%)

37 existing lines in 5 files now uncovered.

4879 of 5429 relevant lines covered (89.87%)

1.01 hits per line

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

80.75
/plugin/studio/package_pack_command.go
1
package studio
2

3
import (
4
        "bufio"
5
        "bytes"
6
        "encoding/json"
7
        "errors"
8
        "fmt"
9
        "io"
10
        "os"
11
        "path/filepath"
12
        "strings"
13
        "sync"
14
        "time"
15

16
        "github.com/UiPath/uipathcli/log"
17
        "github.com/UiPath/uipathcli/output"
18
        "github.com/UiPath/uipathcli/plugin"
19
        "github.com/UiPath/uipathcli/utils"
20
)
21

22
const defaultProjectJson = "project.json"
23

24
// The PackagePackCommand packs a project into a single NuGet package
25
type PackagePackCommand struct {
26
        Exec utils.ExecProcess
27
}
28

29
func (c PackagePackCommand) Command() plugin.Command {
1✔
30
        return *plugin.NewCommand("studio").
1✔
31
                WithCategory("package", "Package", "UiPath Studio package-related actions").
1✔
32
                WithOperation("pack", "Package Project", "Packs a project into a single package").
1✔
33
                WithParameter("source", plugin.ParameterTypeString, "Path to a project.json file or a folder containing project.json file", true).
1✔
34
                WithParameter("destination", plugin.ParameterTypeString, "The output folder", true).
1✔
35
                WithParameter("package-version", plugin.ParameterTypeString, "The package version", false).
1✔
36
                WithParameter("auto-version", plugin.ParameterTypeBoolean, "Auto-generate package version", false).
1✔
37
                WithParameter("output-type", plugin.ParameterTypeString, "Force the output to a specific type", false).
1✔
38
                WithParameter("split-output", plugin.ParameterTypeBoolean, "Enables the output split to runtime and design libraries", false).
1✔
39
                WithParameter("release-notes", plugin.ParameterTypeString, "Add release notes", false)
1✔
40
}
1✔
41

42
func (c PackagePackCommand) Execute(context plugin.ExecutionContext, writer output.OutputWriter, logger log.Logger) error {
1✔
43
        source, err := c.getSource(context)
1✔
44
        if err != nil {
2✔
45
                return err
1✔
46
        }
1✔
47
        destination, err := c.getDestination(context)
1✔
48
        if err != nil {
1✔
49
                return err
×
50
        }
×
51
        packageVersion := c.getParameter("package-version", context.Parameters)
1✔
52
        autoVersion := c.getBoolParameter("auto-version", context.Parameters)
1✔
53
        outputType := c.getParameter("output-type", context.Parameters)
1✔
54
        splitOutput := c.getBoolParameter("split-output", context.Parameters)
1✔
55
        releaseNotes := c.getParameter("release-notes", context.Parameters)
1✔
56
        params := newPackagePackParams(source, destination, packageVersion, autoVersion, outputType, splitOutput, releaseNotes)
1✔
57

1✔
58
        result, err := c.execute(*params, context.Debug, logger)
1✔
59
        if err != nil {
1✔
60
                return err
×
61
        }
×
62

63
        json, err := json.Marshal(result)
1✔
64
        if err != nil {
1✔
65
                return fmt.Errorf("pack command failed: %v", err)
×
66
        }
×
67
        return writer.WriteResponse(*output.NewResponseInfo(200, "200 OK", "HTTP/1.1", map[string][]string{}, bytes.NewReader(json)))
1✔
68
}
69

70
func (c PackagePackCommand) execute(params packagePackParams, debug bool, logger log.Logger) (*packagePackResult, error) {
1✔
71
        if !debug {
2✔
72
                bar := c.newPackagingProgressBar(logger)
1✔
73
                defer close(bar)
1✔
74
        }
1✔
75

76
        args := []string{"package", "pack", params.Source, "--output", params.Destination}
1✔
77
        if params.PackageVersion != "" {
1✔
78
                args = append(args, "--version", params.PackageVersion)
×
79
        }
×
80
        if params.AutoVersion {
1✔
81
                args = append(args, "--autoVersion")
×
82
        }
×
83
        if params.OutputType != "" {
1✔
84
                args = append(args, "--outputType", params.OutputType)
×
85
        }
×
86
        if params.SplitOutput {
1✔
87
                args = append(args, "--splitOutput")
×
88
        }
×
89
        if params.ReleaseNotes != "" {
1✔
90
                args = append(args, "--releaseNotes", params.ReleaseNotes)
×
91
        }
×
92

93
        uipcli := newUipcli(c.Exec, logger)
1✔
94
        cmd, err := uipcli.Execute(args...)
1✔
95
        if err != nil {
1✔
96
                return nil, err
×
97
        }
×
98
        stdout, err := cmd.StdoutPipe()
1✔
99
        if err != nil {
1✔
100
                return nil, fmt.Errorf("Could not run pack command: %v", err)
×
101
        }
×
102
        defer stdout.Close()
1✔
103
        stderr, err := cmd.StderrPipe()
1✔
104
        if err != nil {
1✔
105
                return nil, fmt.Errorf("Could not run pack command: %v", err)
×
106
        }
×
107
        defer stderr.Close()
1✔
108
        err = cmd.Start()
1✔
109
        if err != nil {
1✔
110
                return nil, fmt.Errorf("Could not run pack command: %v", err)
×
111
        }
×
112

113
        stderrOutputBuilder := new(strings.Builder)
1✔
114
        stderrReader := io.TeeReader(stderr, stderrOutputBuilder)
1✔
115

1✔
116
        var wg sync.WaitGroup
1✔
117
        wg.Add(3)
1✔
118
        go c.readOutput(stdout, logger, &wg)
1✔
119
        go c.readOutput(stderrReader, logger, &wg)
1✔
120
        go c.wait(cmd, &wg)
1✔
121
        wg.Wait()
1✔
122

1✔
123
        projectJson, err := c.readProjectJson(params.Source)
1✔
124
        if err != nil {
1✔
125
                return nil, err
×
126
        }
×
127

128
        exitCode := cmd.ExitCode()
1✔
129
        var result *packagePackResult
1✔
130
        if exitCode == 0 {
2✔
131
                nupkgFile := c.findNupkg(params.Destination)
1✔
132
                version := c.extractVersion(nupkgFile)
1✔
133
                result = newSucceededPackagePackResult(
1✔
134
                        filepath.Join(params.Destination, nupkgFile),
1✔
135
                        projectJson.Name,
1✔
136
                        projectJson.Description,
1✔
137
                        projectJson.ProjectId,
1✔
138
                        version)
1✔
139
        } else {
2✔
140
                result = newFailedPackagePackResult(
1✔
141
                        stderrOutputBuilder.String(),
1✔
142
                        &projectJson.Name,
1✔
143
                        &projectJson.Description,
1✔
144
                        &projectJson.ProjectId)
1✔
145
        }
1✔
146
        return result, nil
1✔
147
}
148

149
func (c PackagePackCommand) findNupkg(destination string) string {
1✔
150
        newestFile := ""
1✔
151
        newestTime := time.Time{}
1✔
152

1✔
153
        files, _ := os.ReadDir(destination)
1✔
154
        for _, file := range files {
2✔
155
                extension := filepath.Ext(file.Name())
1✔
156
                if strings.EqualFold(extension, ".nupkg") {
2✔
157
                        fileInfo, _ := file.Info()
1✔
158
                        time := fileInfo.ModTime()
1✔
159
                        if time.After(newestTime) {
2✔
160
                                newestTime = time
1✔
161
                                newestFile = file.Name()
1✔
162
                        }
1✔
163
                }
164
        }
165
        return newestFile
1✔
166
}
167

168
func (c PackagePackCommand) extractVersion(nupkgFile string) string {
1✔
169
        parts := strings.Split(nupkgFile, ".")
1✔
170
        len := len(parts)
1✔
171
        if len < 4 {
1✔
172
                return ""
×
173
        }
×
174
        return fmt.Sprintf("%s.%s.%s", parts[len-4], parts[len-3], parts[len-2])
1✔
175
}
176

177
func (c PackagePackCommand) wait(cmd utils.ExecCmd, wg *sync.WaitGroup) {
1✔
178
        defer wg.Done()
1✔
179
        _ = cmd.Wait()
1✔
180
}
1✔
181

182
func (c PackagePackCommand) newPackagingProgressBar(logger log.Logger) chan struct{} {
1✔
183
        progressBar := utils.NewProgressBar(logger)
1✔
184
        ticker := time.NewTicker(10 * time.Millisecond)
1✔
185
        cancel := make(chan struct{})
1✔
186
        go func() {
2✔
187
                for {
2✔
188
                        select {
1✔
189
                        case <-ticker.C:
1✔
190
                                progressBar.Tick("packaging...  ")
1✔
191
                        case <-cancel:
1✔
192
                                ticker.Stop()
1✔
193
                                progressBar.Remove()
1✔
194
                                return
1✔
195
                        }
196
                }
197
        }()
198
        return cancel
1✔
199
}
200

201
func (c PackagePackCommand) getSource(context plugin.ExecutionContext) (string, error) {
1✔
202
        source := c.getParameter("source", context.Parameters)
1✔
203
        if source == "" {
1✔
204
                return "", errors.New("source is not set")
×
205
        }
×
206
        source, _ = filepath.Abs(source)
1✔
207
        fileInfo, err := os.Stat(source)
1✔
208
        if err != nil {
2✔
209
                return "", fmt.Errorf("%s not found", defaultProjectJson)
1✔
210
        }
1✔
211
        if fileInfo.IsDir() {
2✔
212
                source = filepath.Join(source, defaultProjectJson)
1✔
213
        }
1✔
214
        return source, nil
1✔
215
}
216

217
func (c PackagePackCommand) readProjectJson(path string) (projectJson, error) {
1✔
218
        file, err := os.Open(path)
1✔
219
        if err != nil {
1✔
220
                return projectJson{}, fmt.Errorf("Error reading %s file: %v", defaultProjectJson, err)
×
221
        }
×
222
        defer file.Close()
1✔
223
        byteValue, err := io.ReadAll(file)
1✔
224
        if err != nil {
1✔
225
                return projectJson{}, fmt.Errorf("Error reading %s file: %v", defaultProjectJson, err)
×
226
        }
×
227

228
        var project projectJson
1✔
229
        err = json.Unmarshal(byteValue, &project)
1✔
230
        if err != nil {
1✔
231
                return projectJson{}, fmt.Errorf("Error parsing %s file: %v", defaultProjectJson, err)
×
232
        }
×
233
        return project, nil
1✔
234
}
235

236
func (c PackagePackCommand) getDestination(context plugin.ExecutionContext) (string, error) {
1✔
237
        destination := c.getParameter("destination", context.Parameters)
1✔
238
        if destination == "" {
1✔
239
                return "", errors.New("destination is not set")
×
240
        }
×
241
        destination, _ = filepath.Abs(destination)
1✔
242
        return destination, nil
1✔
243
}
244

245
func (c PackagePackCommand) readOutput(output io.Reader, logger log.Logger, wg *sync.WaitGroup) {
1✔
246
        defer wg.Done()
1✔
247
        scanner := bufio.NewScanner(output)
1✔
248
        scanner.Split(bufio.ScanRunes)
1✔
249
        for scanner.Scan() {
2✔
250
                logger.Log(scanner.Text())
1✔
251
        }
1✔
252
}
253

254
func (c PackagePackCommand) getParameter(name string, parameters []plugin.ExecutionParameter) string {
1✔
255
        result := ""
1✔
256
        for _, p := range parameters {
2✔
257
                if p.Name == name {
2✔
258
                        if data, ok := p.Value.(string); ok {
2✔
259
                                result = data
1✔
260
                                break
1✔
261
                        }
262
                }
263
        }
264
        return result
1✔
265
}
266

267
func (c PackagePackCommand) getBoolParameter(name string, parameters []plugin.ExecutionParameter) bool {
1✔
268
        result := false
1✔
269
        for _, p := range parameters {
2✔
270
                if p.Name == name {
1✔
UNCOV
271
                        if data, ok := p.Value.(bool); ok {
×
NEW
272
                                result = data
×
NEW
273
                                break
×
274
                        }
275
                }
276
        }
277
        return result
1✔
278
}
279

280
func NewPackagePackCommand() *PackagePackCommand {
1✔
281
        return &PackagePackCommand{utils.NewExecProcess()}
1✔
282
}
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