-
Notifications
You must be signed in to change notification settings - Fork 1
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/client/client.go#L45
Raw output
|
||
return | ||
} | ||
fmt.Println(string(bytes)) | ||
Check failure on line 48 in backend/cmd/ictscli/client/client.go GitHub Actions / golangci[golangci] backend/cmd/ictscli/client/client.go#L48
Raw output
|
||
} else if fallback != nil { | ||
fallback() | ||
} | ||
} |
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/root.go#L12
Raw output
|
||
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) | ||
} |
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/create.go#L36
Raw output
|
||
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/create.go#L42
Raw output
|
||
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/create.go#L50
Raw output
|
||
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/create.go#L54
Raw output
|
||
createCmd.MarkFlagRequired("name") | ||
Check failure on line 55 in backend/cmd/ictscli/cmd/team/create.go GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/create.go#L55
Raw output
|
||
createCmd.MarkFlagRequired("organization") | ||
Check failure on line 56 in backend/cmd/ictscli/cmd/team/create.go GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/create.go#L56
Raw output
|
||
} |
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/delete.go#L42
Raw output
|
||
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/delete.go#L44
Raw output
|
||
} |
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/get.go#L42
Raw output
|
||
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/get.go#L44
Raw output
|
||
} |
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/list.go#L31
Raw output
|
||
return | ||
} | ||
|
||
fmt.Println("Teams:") | ||
Check failure on line 35 in backend/cmd/ictscli/cmd/team/list.go GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/list.go#L35
Raw output
|
||
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() { | ||
} |
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) | ||
} |
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/update.go#L24
Raw output
|
||
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 GitHub Actions / golangci[golangci] backend/cmd/ictscli/cmd/team/update.go#L67
Raw output
|
||
} |
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() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
初期化順序がわかりにくくなるので
init
は使わないでほしいです。func createCmd()
を定義するなどがよさそう