Skip to content

Commit

Permalink
feat: Implement backend management CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
kerthical authored Dec 25, 2024
1 parent 8b16a98 commit 6ea1602
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 0 deletions.
52 changes: 52 additions & 0 deletions backend/cmd/ictscli/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package client

import (
"encoding/json"
"fmt"
"net/http"

adminv1connect "github.com/ictsc/ictsc-regalia/backend/pkg/proto/admin/v1/adminv1connect"
)

var (
teamClient adminv1connect.TeamServiceClient
baseURL string
useJSON bool
)

func InitClients(url string) {
baseURL = url
teamClient = adminv1connect.NewTeamServiceClient(
http.DefaultClient,
baseURL,
)
}

func GetBaseURL() string {
return baseURL
}

func GetTeamClient() adminv1connect.TeamServiceClient {
return teamClient
}

func SetJSONOutput(enabled bool) {
useJSON = enabled
}

func IsJSONOutput() bool {
return useJSON
}

func PrintJSON(data interface{}, fallback func()) {
if useJSON {
bytes, err := json.MarshalIndent(data, "", " ")
if err != nil {
fmt.Printf("Error marshaling JSON: %v\n", err)

Check failure on line 45 in backend/cmd/ictscli/client/client.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/client/client.go#L45

use of `fmt.Printf` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
Raw output
cmd/ictscli/client/client.go:45:4: use of `fmt.Printf` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
			fmt.Printf("Error marshaling JSON: %v\n", err)
			^
return
}
fmt.Println(string(bytes))

Check failure on line 48 in backend/cmd/ictscli/client/client.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/client/client.go#L48

use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
Raw output
cmd/ictscli/client/client.go:48:3: use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
		fmt.Println(string(bytes))
		^
} else if fallback != nil {
fallback()
}
}
36 changes: 36 additions & 0 deletions backend/cmd/ictscli/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cmd

import (
"os"

"github.com/ictsc/ictsc-regalia/backend/cmd/ictscli/client"
"github.com/ictsc/ictsc-regalia/backend/cmd/ictscli/cmd/team"
"github.com/spf13/cobra"
)

var (
baseURL string

Check failure on line 12 in backend/cmd/ictscli/cmd/root.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/root.go#L12

File is not `gofmt`-ed with `-s` (gofmt)
Raw output
cmd/ictscli/cmd/root.go:12: File is not `gofmt`-ed with `-s` (gofmt)
	baseURL  string
	useJSON  bool
useJSON bool
)

var rootCmd = &cobra.Command{
Use: "ictscli",
Short: "ICTSC Regalia CLI",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
client.InitClients(baseURL)
client.SetJSONOutput(useJSON)
},
}

func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}

func init() {
rootCmd.PersistentFlags().StringVar(&baseURL, "base", "http://localhost:8080", "Base URL of the backend server")
rootCmd.PersistentFlags().BoolVar(&useJSON, "json", false, "Output in JSON format")
rootCmd.AddCommand(team.TeamCmd)
}
57 changes: 57 additions & 0 deletions backend/cmd/ictscli/cmd/team/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package team

import (
"context"
"fmt"

"connectrpc.com/connect"
"github.com/ictsc/ictsc-regalia/backend/cmd/ictscli/client"
v1 "github.com/ictsc/ictsc-regalia/backend/pkg/proto/admin/v1"
"github.com/spf13/cobra"
)

var (
createCode int64
createName string
createOrganization string
)

var createCmd = &cobra.Command{
Use: "create",
Short: "Create a new team",
Long: `Create a new team with the specified code, name and organization.
Example: ictscli team create --code 1 --name "トラブルシューターズ" --organization "ICTSC"`,
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
req := connect.NewRequest(&v1.CreateTeamRequest{
Team: &v1.Team{
Code: createCode,
Name: createName,
Organization: createOrganization,
},
})

res, err := client.GetTeamClient().CreateTeam(ctx, req)
if err != nil {
fmt.Printf("Failed to create team: %v\n", err)

Check failure on line 36 in backend/cmd/ictscli/cmd/team/create.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/create.go#L36

use of `fmt.Printf` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
Raw output
cmd/ictscli/cmd/team/create.go:36:4: use of `fmt.Printf` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
			fmt.Printf("Failed to create team: %v\n", err)
			^
return
}

team := res.Msg.GetTeam()
client.PrintJSON(team, func() {
fmt.Printf("Successfully created team:\n")

Check failure on line 42 in backend/cmd/ictscli/cmd/team/create.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/create.go#L42

use of `fmt.Printf` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
Raw output
cmd/ictscli/cmd/team/create.go:42:4: use of `fmt.Printf` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
			fmt.Printf("Successfully created team:\n")
			^
fmt.Printf(" Code: %d\n", team.GetCode())
fmt.Printf(" Name: %s\n", team.GetName())
fmt.Printf(" Organization: %s\n", team.GetOrganization())
})
},
}

func init() {

Check failure on line 50 in backend/cmd/ictscli/cmd/team/create.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/create.go#L50

don't use `init` function (gochecknoinits)
Raw output
cmd/ictscli/cmd/team/create.go:50:1: don't use `init` function (gochecknoinits)
func init() {
^
createCmd.Flags().Int64Var(&createCode, "code", 0, "Team code (required)")
createCmd.Flags().StringVar(&createName, "name", "", "Team name (required)")
createCmd.Flags().StringVar(&createOrganization, "organization", "", "Team organization (required)")
createCmd.MarkFlagRequired("code")

Check failure on line 54 in backend/cmd/ictscli/cmd/team/create.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/create.go#L54

Error return value of `createCmd.MarkFlagRequired` is not checked (errcheck)
Raw output
cmd/ictscli/cmd/team/create.go:54:28: Error return value of `createCmd.MarkFlagRequired` is not checked (errcheck)
	createCmd.MarkFlagRequired("code")
	                          ^
createCmd.MarkFlagRequired("name")

Check failure on line 55 in backend/cmd/ictscli/cmd/team/create.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/create.go#L55

Error return value of `createCmd.MarkFlagRequired` is not checked (errcheck)
Raw output
cmd/ictscli/cmd/team/create.go:55:28: Error return value of `createCmd.MarkFlagRequired` is not checked (errcheck)
	createCmd.MarkFlagRequired("name")
	                          ^
createCmd.MarkFlagRequired("organization")

Check failure on line 56 in backend/cmd/ictscli/cmd/team/create.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/create.go#L56

Error return value of `createCmd.MarkFlagRequired` is not checked (errcheck)
Raw output
cmd/ictscli/cmd/team/create.go:56:28: Error return value of `createCmd.MarkFlagRequired` is not checked (errcheck)
	createCmd.MarkFlagRequired("organization")
	                          ^
}
45 changes: 45 additions & 0 deletions backend/cmd/ictscli/cmd/team/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package team

import (
"context"
"fmt"

"connectrpc.com/connect"
"github.com/ictsc/ictsc-regalia/backend/cmd/ictscli/client"
v1 "github.com/ictsc/ictsc-regalia/backend/pkg/proto/admin/v1"
"github.com/spf13/cobra"
)

var deleteCode int64

var deleteCmd = &cobra.Command{
Use: "delete",
Short: "Delete a team",
Long: `Delete a team by its code.
Example: ictscli team delete --code 1`,
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
req := connect.NewRequest(&v1.DeleteTeamRequest{
Code: deleteCode,
})

_, err := client.GetTeamClient().DeleteTeam(ctx, req)
if err != nil {
fmt.Printf("Failed to delete team: %v\n", err)
return
}

client.PrintJSON(map[string]interface{}{
"success": true,
"code": deleteCode,
"message": "Team deleted successfully",
}, func() {
fmt.Printf("Successfully deleted team with code: %d\n", deleteCode)
})
},
}

func init() {

Check failure on line 42 in backend/cmd/ictscli/cmd/team/delete.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/delete.go#L42

don't use `init` function (gochecknoinits)
Raw output
cmd/ictscli/cmd/team/delete.go:42:1: don't use `init` function (gochecknoinits)
func init() {
^
deleteCmd.Flags().Int64Var(&deleteCode, "code", 0, "Team code (required)")
deleteCmd.MarkFlagRequired("code")

Check failure on line 44 in backend/cmd/ictscli/cmd/team/delete.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/delete.go#L44

Error return value of `deleteCmd.MarkFlagRequired` is not checked (errcheck)
Raw output
cmd/ictscli/cmd/team/delete.go:44:28: Error return value of `deleteCmd.MarkFlagRequired` is not checked (errcheck)
	deleteCmd.MarkFlagRequired("code")
	                          ^
}
45 changes: 45 additions & 0 deletions backend/cmd/ictscli/cmd/team/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package team

import (
"context"
"fmt"

"connectrpc.com/connect"
"github.com/ictsc/ictsc-regalia/backend/cmd/ictscli/client"
v1 "github.com/ictsc/ictsc-regalia/backend/pkg/proto/admin/v1"
"github.com/spf13/cobra"
)

var getCode int64

var getCmd = &cobra.Command{
Use: "get",
Short: "Get a team by code",
Long: `Get detailed information about a team by its code.
Example: ictscli team get --code 1`,
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
req := connect.NewRequest(&v1.GetTeamRequest{
Code: getCode,
})

res, err := client.GetTeamClient().GetTeam(ctx, req)
if err != nil {
fmt.Printf("Failed to get team: %v\n", err)
return
}

team := res.Msg.GetTeam()
client.PrintJSON(team, func() {
fmt.Printf("Team details:\n")
fmt.Printf(" Code: %d\n", team.GetCode())
fmt.Printf(" Name: %s\n", team.GetName())
fmt.Printf(" Organization: %s\n", team.GetOrganization())
})
},
}

func init() {

Check failure on line 42 in backend/cmd/ictscli/cmd/team/get.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/get.go#L42

don't use `init` function (gochecknoinits)
Raw output
cmd/ictscli/cmd/team/get.go:42:1: don't use `init` function (gochecknoinits)
func init() {
^
getCmd.Flags().Int64Var(&getCode, "code", 0, "Team code (required)")
getCmd.MarkFlagRequired("code")

Check failure on line 44 in backend/cmd/ictscli/cmd/team/get.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/get.go#L44

Error return value of `getCmd.MarkFlagRequired` is not checked (errcheck)
Raw output
cmd/ictscli/cmd/team/get.go:44:25: Error return value of `getCmd.MarkFlagRequired` is not checked (errcheck)
	getCmd.MarkFlagRequired("code")
	                       ^
}
47 changes: 47 additions & 0 deletions backend/cmd/ictscli/cmd/team/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package team

import (
"context"
"fmt"

"connectrpc.com/connect"
"github.com/ictsc/ictsc-regalia/backend/cmd/ictscli/client"
v1 "github.com/ictsc/ictsc-regalia/backend/pkg/proto/admin/v1"
"github.com/spf13/cobra"
)

var listCmd = &cobra.Command{
Use: "list",
Short: "List all teams",
Long: `List all registered teams with their details.
Example: ictscli team list`,
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
req := connect.NewRequest(&v1.ListTeamsRequest{})

res, err := client.GetTeamClient().ListTeams(ctx, req)
if err != nil {
fmt.Printf("Failed to list teams: %v\n", err)
return
}

teams := res.Msg.GetTeams()
client.PrintJSON(teams, func() {
if len(teams) == 0 {
fmt.Println("No teams found")

Check failure on line 31 in backend/cmd/ictscli/cmd/team/list.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/list.go#L31

use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
Raw output
cmd/ictscli/cmd/team/list.go:31:5: use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
				fmt.Println("No teams found")
				^
return
}

fmt.Println("Teams:")

Check failure on line 35 in backend/cmd/ictscli/cmd/team/list.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/list.go#L35

use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
Raw output
cmd/ictscli/cmd/team/list.go:35:4: use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
			fmt.Println("Teams:")
			^
for _, team := range teams {
fmt.Printf(" Code: %d\n", team.GetCode())
fmt.Printf(" Name: %s\n", team.GetName())
fmt.Printf(" Organization: %s\n", team.GetOrganization())
fmt.Println()
}
})
},
}

func init() {
}
22 changes: 22 additions & 0 deletions backend/cmd/ictscli/cmd/team/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package team

import (
"github.com/spf13/cobra"
)

var TeamCmd = &cobra.Command{
Use: "team",
Short: "Manage teams",
Long: `Manage teams in the ICTSC Regalia system.
This command provides functionality to create, list, get, update, and delete teams.
Each team has a unique code, name, and organization.`,
}

func init() {
TeamCmd.AddCommand(createCmd)
TeamCmd.AddCommand(listCmd)
TeamCmd.AddCommand(getCmd)
TeamCmd.AddCommand(updateCmd)
TeamCmd.AddCommand(deleteCmd)
}
68 changes: 68 additions & 0 deletions backend/cmd/ictscli/cmd/team/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package team

import (
"context"
"fmt"

"connectrpc.com/connect"
"github.com/ictsc/ictsc-regalia/backend/cmd/ictscli/client"
v1 "github.com/ictsc/ictsc-regalia/backend/pkg/proto/admin/v1"
"github.com/spf13/cobra"
"google.golang.org/protobuf/types/known/fieldmaskpb"
)

var (
updateCode int64
updateName string
updateOrganization string
)

var updateCmd = &cobra.Command{
Use: "update",
Short: "Update a team",
Long: `Update a team's information. Only specified fields will be updated.
Example: ictscli team update --code 1 --name "新トラブルシューターズ"`,

Check failure on line 24 in backend/cmd/ictscli/cmd/team/update.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/update.go#L24

string literal contains rune in Han script (gosmopolitan)
Raw output
cmd/ictscli/cmd/team/update.go:24:47: string literal contains rune in Han script (gosmopolitan)
Example: ictscli team update --code 1 --name "新トラブルシューターズ"`,
                                              ^
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()

paths := []string{}
if cmd.Flags().Changed("name") {
paths = append(paths, "name")
}
if cmd.Flags().Changed("organization") {
paths = append(paths, "organization")
}

req := connect.NewRequest(&v1.UpdateTeamRequest{
Team: &v1.Team{
Code: updateCode,
Name: updateName,
Organization: updateOrganization,
},
UpdateMask: &fieldmaskpb.FieldMask{
Paths: paths,
},
})

res, err := client.GetTeamClient().UpdateTeam(ctx, req)
if err != nil {
fmt.Printf("Failed to update team: %v\n", err)
return
}

team := res.Msg.GetTeam()
client.PrintJSON(team, func() {
fmt.Printf("Successfully updated team:\n")
fmt.Printf(" Code: %d\n", team.GetCode())
fmt.Printf(" Name: %s\n", team.GetName())
fmt.Printf(" Organization: %s\n", team.GetOrganization())
})
},
}

func init() {
updateCmd.Flags().Int64Var(&updateCode, "code", 0, "Team code (required)")
updateCmd.Flags().StringVar(&updateName, "name", "", "New team name")
updateCmd.Flags().StringVar(&updateOrganization, "organization", "", "New team organization")
updateCmd.MarkFlagRequired("code")

Check failure on line 67 in backend/cmd/ictscli/cmd/team/update.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] backend/cmd/ictscli/cmd/team/update.go#L67

Error return value of `updateCmd.MarkFlagRequired` is not checked (errcheck)
Raw output
cmd/ictscli/cmd/team/update.go:67:28: Error return value of `updateCmd.MarkFlagRequired` is not checked (errcheck)
	updateCmd.MarkFlagRequired("code")
	                          ^
}
7 changes: 7 additions & 0 deletions backend/cmd/ictscli/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "github.com/ictsc/ictsc-regalia/backend/cmd/ictscli/cmd"

func main() {
cmd.Execute()
}
Loading

0 comments on commit 6ea1602

Please sign in to comment.