Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement backend management CLI #894

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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() {
^
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

初期化順序がわかりにくくなるので init は使わないでほしいです。func createCmd()を定義するなどがよさそう

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
Loading