diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3b10bf0..ce63e1e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -31,6 +31,34 @@ jobs: path: build/packages/ if-no-files-found: error + publish_pages: + needs: build + permissions: + pages: write + id-token: write + #if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Download packages + uses: actions/download-artifact@v3 + with: + name: packages + path: build/packages/ + - name: Generate commands + run: | + tar -xzvf build/packages/uipathcli-linux-amd64.tar.gz + ./uipath commands > documentation/commands.json + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + path: 'documentation' + - name: Deploy to GitHub Pages + uses: actions/deploy-pages@v2 + release: needs: build if: github.ref == 'refs/heads/main' diff --git a/commandline/command_builder.go b/commandline/command_builder.go index fcb85af..456ea40 100644 --- a/commandline/command_builder.go +++ b/commandline/command_builder.go @@ -682,6 +682,23 @@ func (b CommandBuilder) createConfigSetCommand() *cli.Command { } func (b CommandBuilder) loadDefinitions(args []string, version string) ([]parser.Definition, error) { + if len(args) > 1 && args[1] == "commands" { + all, err := b.DefinitionProvider.Index(version) + if err != nil { + return nil, err + } + definitions := []parser.Definition{} + for _, d := range all { + definition, err := b.DefinitionProvider.Load(d.Name, version) + if err != nil { + return nil, err + } + if definition != nil { + definitions = append(definitions, *definition) + } + } + return definitions, nil + } if len(args) <= 1 || strings.HasPrefix(args[1], "--") { return b.DefinitionProvider.Index(version) } @@ -699,6 +716,27 @@ func (b CommandBuilder) loadAutocompleteDefinitions(args []string, version strin return b.loadDefinitions(args, version) } +func (b CommandBuilder) createDisplayCommands(definitions []parser.Definition) *cli.Command { + return &cli.Command{ + Name: "commands", + Description: "Display available commands", + Flags: []cli.Flag{ + b.HelpFlag(), + }, + Hidden: true, + HideHelp: true, + Action: func(context *cli.Context) error { + handler := newDisplayCommandsHandler() + output, err := handler.Display(definitions) + if err != nil { + return err + } + fmt.Fprintln(b.StdOut, output) + return nil + }, + } +} + func (b CommandBuilder) createServiceCommands(definitions []parser.Definition) []*cli.Command { commands := []*cli.Command{} for _, e := range definitions { @@ -740,7 +778,8 @@ func (b CommandBuilder) Create(args []string) ([]*cli.Command, error) { servicesCommands := b.createServiceCommands(definitions) autocompleteCommand := b.createAutoCompleteCommand(version) configCommand := b.createConfigCommand() - commands := append(servicesCommands, autocompleteCommand, configCommand) + displayCommands := b.createDisplayCommands(definitions) + commands := append(servicesCommands, autocompleteCommand, configCommand, displayCommands) return commands, nil } diff --git a/commandline/definition_file_store.go b/commandline/definition_file_store.go index e12425a..9235145 100644 --- a/commandline/definition_file_store.go +++ b/commandline/definition_file_store.go @@ -56,7 +56,6 @@ func (s *DefinitionFileStore) Read(name string, version string) (*DefinitionData return nil, err } definition := NewDefinitionData(name, version, data) - s.definitions = append(s.definitions, *definition) return definition, err } } diff --git a/commandline/display_commands_handler.go b/commandline/display_commands_handler.go new file mode 100644 index 0000000..6c55408 --- /dev/null +++ b/commandline/display_commands_handler.go @@ -0,0 +1,130 @@ +package commandline + +import ( + "encoding/json" + "sort" + + "github.com/UiPath/uipathcli/parser" +) + +// displayCommandsHandler shows all the available commands +type displayCommandsHandler struct { +} + +type parameterJson struct { + Name string `json:"name"` + Type string `json:"type"` + Description string `json:"description"` + Required bool `json:"required"` + AllowedValues []interface{} `json:"allowedValues"` + DefaultValue interface{} `json:"defaultValue"` +} + +type commandJson struct { + Name string `json:"name"` + Description string `json:"description"` + Parameters []parameterJson `json:"parameters"` + Subcommands []commandJson `json:"subcommands"` +} + +func (h displayCommandsHandler) Display(definitions []parser.Definition) (string, error) { + result := commandJson{ + Name: "uipath", + Description: "Command line interface to simplify, script and automate API calls for UiPath services", + Subcommands: h.convertDefinitionsToCommands(definitions), + } + bytes, err := json.MarshalIndent(result, "", " ") + if err != nil { + return "", err + } + return string(bytes), nil +} + +func (h displayCommandsHandler) convertDefinitionsToCommands(definitions []parser.Definition) []commandJson { + commands := []commandJson{} + for _, d := range definitions { + command := h.convertDefinitionToCommands(d) + commands = append(commands, command) + } + return commands +} + +func (h displayCommandsHandler) convertDefinitionToCommands(definition parser.Definition) commandJson { + categories := map[string]commandJson{} + + for _, op := range definition.Operations { + if op.Category == nil { + command := h.convertOperationToCommand(op) + categories[command.Name] = command + } else { + h.createOrUpdateCategory(op, categories) + } + } + + commands := []commandJson{} + for _, command := range categories { + commands = append(commands, command) + } + + h.sort(commands) + for _, command := range commands { + h.sort(command.Subcommands) + } + return commandJson{ + Name: definition.Name, + Subcommands: commands, + } +} + +func (h displayCommandsHandler) createOrUpdateCategory(operation parser.Operation, categories map[string]commandJson) { + command, found := categories[operation.Category.Name] + if !found { + command = h.createCategoryCommand(operation) + } + command.Subcommands = append(command.Subcommands, h.convertOperationToCommand(operation)) + categories[operation.Category.Name] = command +} + +func (h displayCommandsHandler) createCategoryCommand(operation parser.Operation) commandJson { + return commandJson{ + Name: operation.Category.Name, + Description: operation.Category.Description, + } +} + +func (h displayCommandsHandler) convertOperationToCommand(operation parser.Operation) commandJson { + return commandJson{ + Name: operation.Name, + Description: operation.Description, + Parameters: h.convertParametersToCommandParameters(operation.Parameters), + } +} + +func (h displayCommandsHandler) convertParametersToCommandParameters(parameters []parser.Parameter) []parameterJson { + result := []parameterJson{} + for _, p := range parameters { + result = append(result, h.convertParameterToCommandParameter(p)) + } + return result +} + +func (h displayCommandsHandler) convertParameterToCommandParameter(parameter parser.Parameter) parameterJson { + return parameterJson{ + Name: parameter.Name, + Description: parameter.Description, + Type: parameter.Type, + Required: parameter.Required, + AllowedValues: parameter.AllowedValues, + DefaultValue: parameter.DefaultValue, + } +} + +func (h displayCommandsHandler) sort(commands []commandJson) { + sort.Slice(commands, func(i, j int) bool { + return commands[i].Name < commands[j].Name + }) +} + +func newDisplayCommandsHandler() *displayCommandsHandler { + return &displayCommandsHandler{} +} diff --git a/documentation/css/main.css b/documentation/css/main.css new file mode 100644 index 0000000..5be052e --- /dev/null +++ b/documentation/css/main.css @@ -0,0 +1,145 @@ +* { + color: #273139; + font-family: noto-sans, "Noto Sans JP", "Noto Sans KR", "Noto Sans SC", "Noto Sans TC", "Noto Sans", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,sans-serif; +} + +body { + margin: 0; + padding: 0; +} + +h1 { + font-size: 26px; +} + +h2 { + font-size: 20px; + border-bottom: 1px solid rgb(164, 177, 184); + width: 90%; +} + +a { + color: #0067df; + text-decoration: none; + font-weight: 600; +} + +.main { + margin: 20px; +} + +.header { + height: 48px; + border-bottom: 1px solid rgb(207, 216, 221); + display: flex; + flex-direction: row; +} + +.header-icon { + padding-top: 6px; + padding-left: 8px; + line-height: 48px; + vertical-align: middle; +} + +.header-text { + padding-left: 15px; + font-size: 16px; + font-weight: 600; + line-height: 48px; + vertical-align: middle; +} + +.breadcrumb +{ + color: #526069; + font-size: 14px; + font-weight: 600; + display: inline-block; +} + +.breadcrumb ol { + padding-left: 0; + list-style: none; +} + +.breadcrumb li { + float: left; +} + +.breadcrumb li:after +{ + content: '/'; + padding-left: 8px; + padding-right: 8px; + display: inline; +} + +.breadcrumb li:last-child +{ + font-weight: 400; +} + +.breadcrumb li:last-child:after +{ + content: ''; +} + +.footer { + margin-top: 20px; + height: 100px; + background: rgb(29, 29, 30); + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.footer-icon { + padding-top: 8px; + padding-left: 8px; + line-height: 100px; + vertical-align: middle; +} + +.footer-text { + padding-right: 8px; + color: rgb(89, 90, 92); + line-height: 100px; + vertical-align: middle; +} + +.usage { + padding: 5px; + background-color: #f7f7f7; + border-radius: 4px; + border: 1px solid #e1e1e8; + font-family: monospace; +} + +.parameters { + padding-left: 0; + list-style: none; +} + +.parameter { + margin: 20px; +} + +.parameter-name { + padding: 2px; + background-color: #f7f7f7; + border-radius: 4px; + border: 1px solid #e1e1e8; + font-family: monospace; +} + +.parameter-description { + margin-top: 10px; + margin-bottom: 10px; + display: inline-block; + width: 100%; +} + +.parameter-allowed-values ul { + list-style-type: square; +} \ No newline at end of file diff --git a/documentation/favicon.ico b/documentation/favicon.ico new file mode 100644 index 0000000..13c1d6d Binary files /dev/null and b/documentation/favicon.ico differ diff --git a/documentation/index.html b/documentation/index.html new file mode 100644 index 0000000..b28c212 --- /dev/null +++ b/documentation/index.html @@ -0,0 +1,34 @@ + + +
+ +