| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- package cmd
- import (
- "context"
- "encoding/json"
- "fmt"
- "os"
- "strings"
- "gogs.dmsc.dev/arp/arp_cli/client"
- "gogs.dmsc.dev/arp/arp_cli/config"
- "github.com/AlecAivazis/survey/v2"
- "github.com/olekukonko/tablewriter"
- "github.com/urfave/cli/v3"
- )
- // ServiceCommand returns the service command
- func ServiceCommand() *cli.Command {
- return &cli.Command{
- Name: "service",
- Usage: "Manage services",
- Description: `Manage ARP services. Services are entities that agents coordinate work around.
- Services can have participants (users) and contain tasks. Use this command to
- create, list, update, and delete services.`,
- Commands: []*cli.Command{
- {
- Name: "list",
- Aliases: []string{"ls"},
- Usage: "List all services",
- Flags: []cli.Flag{
- &cli.BoolFlag{
- Name: "json",
- Aliases: []string{"j"},
- Usage: "Output as JSON",
- },
- },
- Action: serviceList,
- },
- {
- Name: "get",
- Usage: "Get a service by ID",
- Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "id",
- Aliases: []string{"i"},
- Usage: "Service ID",
- Required: true,
- },
- &cli.BoolFlag{
- Name: "json",
- Aliases: []string{"j"},
- Usage: "Output as JSON",
- },
- },
- Action: serviceGet,
- },
- {
- Name: "create",
- Usage: "Create a new service",
- Action: serviceCreate,
- Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "name",
- Aliases: []string{"n"},
- Usage: "Service name",
- },
- &cli.StringFlag{
- Name: "description",
- Aliases: []string{"d"},
- Usage: "Service description",
- },
- &cli.StringFlag{
- Name: "created-by",
- Aliases: []string{"c"},
- Usage: "Creator user ID",
- },
- &cli.StringSliceFlag{
- Name: "participants",
- Aliases: []string{"p"},
- Usage: "Participant user IDs",
- },
- },
- },
- {
- Name: "update",
- Usage: "Update a service",
- Action: serviceUpdate,
- Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "id",
- Aliases: []string{"i"},
- Usage: "Service ID",
- Required: true,
- },
- &cli.StringFlag{
- Name: "name",
- Aliases: []string{"n"},
- Usage: "Service name",
- },
- &cli.StringFlag{
- Name: "description",
- Aliases: []string{"d"},
- Usage: "Service description",
- },
- &cli.StringSliceFlag{
- Name: "participants",
- Aliases: []string{"p"},
- Usage: "Participant user IDs",
- },
- },
- },
- {
- Name: "delete",
- Usage: "Delete a service",
- Action: serviceDelete,
- Flags: []cli.Flag{
- &cli.StringFlag{
- Name: "id",
- Aliases: []string{"i"},
- Usage: "Service ID",
- Required: true,
- },
- &cli.BoolFlag{
- Name: "yes",
- Aliases: []string{"y"},
- Usage: "Skip confirmation",
- },
- },
- },
- },
- }
- }
- type Service struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Description string `json:"description"`
- CreatedByID string `json:"createdById"`
- CreatedBy struct {
- ID string `json:"id"`
- Email string `json:"email"`
- } `json:"createdBy"`
- Participants []struct {
- ID string `json:"id"`
- Email string `json:"email"`
- } `json:"participants"`
- CreatedAt string `json:"createdAt"`
- UpdatedAt string `json:"updatedAt"`
- }
- func serviceList(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- query := "query Services { services { id name description createdBy { id email } participants { id email } createdAt updatedAt } }"
- resp, err := c.Query(query, nil)
- if err != nil {
- return err
- }
- var result struct {
- Services []Service `json:"services"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if cmd.Bool("json") {
- enc := json.NewEncoder(os.Stdout)
- enc.SetIndent("", " ")
- return enc.Encode(result.Services)
- }
- if len(result.Services) == 0 {
- fmt.Println("No services found.")
- return nil
- }
- table := tablewriter.NewWriter(os.Stdout)
- table.Header([]string{"ID", "Name", "Description", "Created By", "Participants", "Created At"})
-
- for _, s := range result.Services {
- participants := fmt.Sprintf("%d", len(s.Participants))
- table.Append([]string{s.ID, s.Name, s.Description, s.CreatedBy.Email, participants, s.CreatedAt})
- }
- table.Render()
- return nil
- }
- func serviceGet(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- id := cmd.String("id")
- query := "query Service($id: ID!) { service(id: $id) { id name description createdBy { id email } participants { id email } createdAt updatedAt } }"
- resp, err := c.Query(query, map[string]interface{}{"id": id})
- if err != nil {
- return err
- }
- var result struct {
- Service *Service `json:"service"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if result.Service == nil {
- return fmt.Errorf("service not found")
- }
- if cmd.Bool("json") {
- enc := json.NewEncoder(os.Stdout)
- enc.SetIndent("", " ")
- return enc.Encode(result.Service)
- }
- s := result.Service
- fmt.Printf("ID: %s\n", s.ID)
- fmt.Printf("Name: %s\n", s.Name)
- fmt.Printf("Description: %s\n", s.Description)
- fmt.Printf("Created By: %s\n", s.CreatedBy.Email)
- fmt.Printf("Participants:\n")
- for _, p := range s.Participants {
- fmt.Printf(" - %s (%s)\n", p.Email, p.ID)
- }
- fmt.Printf("Created At: %s\n", s.CreatedAt)
- fmt.Printf("Updated At: %s\n", s.UpdatedAt)
- return nil
- }
- func serviceCreate(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- name := cmd.String("name")
- description := cmd.String("description")
- createdBy := cmd.String("created-by")
- participants := cmd.StringSlice("participants")
- if name == "" {
- prompt := &survey.Input{Message: "Service name:"}
- if err := survey.AskOne(prompt, &name, survey.WithValidator(survey.Required)); err != nil {
- return err
- }
- }
- if description == "" {
- prompt := &survey.Input{Message: "Description (optional):"}
- survey.AskOne(prompt, &description)
- }
- if createdBy == "" {
- prompt := &survey.Input{Message: "Creator user ID:"}
- if err := survey.AskOne(prompt, &createdBy, survey.WithValidator(survey.Required)); err != nil {
- return err
- }
- }
- if len(participants) == 0 {
- var participantsStr string
- prompt := &survey.Input{Message: "Participant user IDs (comma-separated, optional):"}
- if err := survey.AskOne(prompt, &participantsStr); err != nil {
- return err
- }
- if participantsStr != "" {
- for _, p := range strings.Split(participantsStr, ",") {
- participants = append(participants, strings.TrimSpace(p))
- }
- }
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- mutation := `mutation CreateService($input: NewService!) { createService(input: $input) { id name description createdBy { id email } participants { id email } createdAt updatedAt } }`
- input := map[string]interface{}{
- "name": name,
- "description": description,
- "createdById": createdBy,
- "participants": participants,
- }
- resp, err := c.Mutation(mutation, map[string]interface{}{"input": input})
- if err != nil {
- return err
- }
- var result struct {
- CreateService *Service `json:"createService"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if result.CreateService == nil {
- return fmt.Errorf("failed to create service")
- }
- fmt.Printf("Service created successfully!\n")
- fmt.Printf("ID: %s\n", result.CreateService.ID)
- fmt.Printf("Name: %s\n", result.CreateService.Name)
- return nil
- }
- func serviceUpdate(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- id := cmd.String("id")
- name := cmd.String("name")
- description := cmd.String("description")
- participants := cmd.StringSlice("participants")
- // Check if any updates are provided
- if name == "" && description == "" && len(participants) == 0 {
- fmt.Println("No updates provided. Use flags to specify what to update.")
- return nil
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- // Build the input dynamically
- input := make(map[string]interface{})
- if name != "" {
- input["name"] = name
- }
- if description != "" {
- input["description"] = description
- }
- if len(participants) > 0 {
- input["participants"] = participants
- }
- mutation := `mutation UpdateService($id: ID!, $input: UpdateServiceInput!) { updateService(id: $id, input: $input) { id name description createdBy { id email } participants { id email } createdAt updatedAt } }`
- resp, err := c.Mutation(mutation, map[string]interface{}{"id": id, "input": input})
- if err != nil {
- return err
- }
- var result struct {
- UpdateService *Service `json:"updateService"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if result.UpdateService == nil {
- return fmt.Errorf("service not found")
- }
- fmt.Printf("Service updated successfully!\n")
- fmt.Printf("ID: %s\n", result.UpdateService.ID)
- fmt.Printf("Name: %s\n", result.UpdateService.Name)
- return nil
- }
- func serviceDelete(ctx context.Context, cmd *cli.Command) error {
- cfg, err := config.Load()
- if err != nil {
- return err
- }
- if err := RequireAuth(cfg); err != nil {
- return err
- }
- id := cmd.String("id")
- skipConfirm := cmd.Bool("yes")
- if !skipConfirm {
- confirm := false
- prompt := &survey.Confirm{
- Message: fmt.Sprintf("Are you sure you want to delete service %s?", id),
- Default: false,
- }
- if err := survey.AskOne(prompt, &confirm); err != nil {
- return err
- }
- if !confirm {
- fmt.Println("Deletion cancelled.")
- return nil
- }
- }
- c := client.New(cfg.ServerURL)
- c.SetToken(cfg.Token)
- mutation := `mutation DeleteService($id: ID!) { deleteService(id: $id) }`
- resp, err := c.Mutation(mutation, map[string]interface{}{"id": id})
- if err != nil {
- return err
- }
- var result struct {
- DeleteService bool `json:"deleteService"`
- }
- if err := json.Unmarshal(resp.Data, &result); err != nil {
- return err
- }
- if result.DeleteService {
- fmt.Printf("Service %s deleted successfully.\n", id)
- } else {
- fmt.Printf("Failed to delete service %s.\n", id)
- }
- return nil
- }
|