Add --format command line option
This change adds a --format command line option to the GARM cli. This option accepts either json or table as a value. Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
parent
cf231c9d8d
commit
63000113ee
13 changed files with 127 additions and 0 deletions
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
apiClientController "github.com/cloudbase/garm/client/controller"
|
apiClientController "github.com/cloudbase/garm/client/controller"
|
||||||
apiClientControllerInfo "github.com/cloudbase/garm/client/controller_info"
|
apiClientControllerInfo "github.com/cloudbase/garm/client/controller_info"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -164,6 +165,10 @@ func renderControllerInfoTable(info params.ControllerInfo) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatInfo(info params.ControllerInfo) error {
|
func formatInfo(info params.ControllerInfo) error {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(info)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
fmt.Println(renderControllerInfoTable(info))
|
fmt.Println(renderControllerInfoTable(info))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
|
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -200,6 +201,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatEnterprises(enterprises []params.Enterprise) {
|
func formatEnterprises(enterprises []params.Enterprise) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(enterprises)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"ID", "Name", "Endpoint", "Credentials name", "Pool Balancer Type", "Pool mgr running"}
|
header := table.Row{"ID", "Name", "Endpoint", "Credentials name", "Pool Balancer Type", "Pool mgr running"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
@ -211,6 +216,10 @@ func formatEnterprises(enterprises []params.Enterprise) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatOneEnterprise(enterprise params.Enterprise) {
|
func formatOneEnterprise(enterprise params.Enterprise) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(enterprise)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
||||||
header := table.Row{"Field", "Value"}
|
header := table.Row{"Field", "Value"}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
apiClientCreds "github.com/cloudbase/garm/client/credentials"
|
apiClientCreds "github.com/cloudbase/garm/client/credentials"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -342,6 +343,10 @@ func parseCredentialsUpdateParams() (params.UpdateGithubCredentialsParams, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatGithubCredentials(creds []params.GithubCredentials) {
|
func formatGithubCredentials(creds []params.GithubCredentials) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(creds)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"ID", "Name", "Description", "Base URL", "API URL", "Upload URL", "Type"}
|
header := table.Row{"ID", "Name", "Description", "Base URL", "API URL", "Upload URL", "Type"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
@ -353,6 +358,10 @@ func formatGithubCredentials(creds []params.GithubCredentials) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatOneGithubCredential(cred params.GithubCredentials) {
|
func formatOneGithubCredential(cred params.GithubCredentials) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(cred)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"Field", "Value"}
|
header := table.Row{"Field", "Value"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
apiClientEndpoints "github.com/cloudbase/garm/client/endpoints"
|
apiClientEndpoints "github.com/cloudbase/garm/client/endpoints"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -250,6 +251,10 @@ func parseCreateParams() (params.CreateGithubEndpointParams, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatEndpoints(endpoints params.GithubEndpoints) {
|
func formatEndpoints(endpoints params.GithubEndpoints) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(endpoints)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"Name", "Base URL", "Description"}
|
header := table.Row{"Name", "Base URL", "Description"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
@ -261,6 +266,10 @@ func formatEndpoints(endpoints params.GithubEndpoints) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatOneEndpoint(endpoint params.GithubEndpoint) {
|
func formatOneEndpoint(endpoint params.GithubEndpoint) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(endpoint)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"Field", "Value"}
|
header := table.Row{"Field", "Value"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
apiClientJobs "github.com/cloudbase/garm/client/jobs"
|
apiClientJobs "github.com/cloudbase/garm/client/jobs"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -57,6 +58,10 @@ var jobsListCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatJobs(jobs []params.Job) {
|
func formatJobs(jobs []params.Job) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(jobs)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"ID", "Name", "Status", "Conclusion", "Runner Name", "Repository", "Requested Labels", "Locked by"}
|
header := table.Row{"ID", "Name", "Status", "Conclusion", "Runner Name", "Repository", "Requested Labels", "Locked by"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/cloudbase/garm-provider-common/util"
|
"github.com/cloudbase/garm-provider-common/util"
|
||||||
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -340,6 +341,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatOrganizations(orgs []params.Organization) {
|
func formatOrganizations(orgs []params.Organization) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(orgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"ID", "Name", "Endpoint", "Credentials name", "Pool Balancer Type", "Pool mgr running"}
|
header := table.Row{"ID", "Name", "Endpoint", "Credentials name", "Pool Balancer Type", "Pool mgr running"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
@ -351,6 +356,10 @@ func formatOrganizations(orgs []params.Organization) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatOneOrganization(org params.Organization) {
|
func formatOneOrganization(org params.Organization) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(org)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
||||||
header := table.Row{"Field", "Value"}
|
header := table.Row{"Field", "Value"}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
||||||
apiClientPools "github.com/cloudbase/garm/client/pools"
|
apiClientPools "github.com/cloudbase/garm/client/pools"
|
||||||
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -466,6 +467,10 @@ func asRawMessage(data []byte) (json.RawMessage, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatPools(pools []params.Pool) {
|
func formatPools(pools []params.Pool) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(pools)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"ID", "Image", "Flavor", "Tags", "Belongs to", "Level", "Enabled", "Runner Prefix", "Priority"}
|
header := table.Row{"ID", "Image", "Flavor", "Tags", "Belongs to", "Level", "Enabled", "Runner Prefix", "Priority"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
@ -496,6 +501,10 @@ func formatPools(pools []params.Pool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatOnePool(pool params.Pool) {
|
func formatOnePool(pool params.Pool) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(pool)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatProfiles(profiles []config.Manager) {
|
func formatProfiles(profiles []config.Manager) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(profiles)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"Name", "Base URL"}
|
header := table.Row{"Name", "Base URL"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
apiClientProviders "github.com/cloudbase/garm/client/providers"
|
apiClientProviders "github.com/cloudbase/garm/client/providers"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -64,6 +65,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatProviders(providers []params.Provider) {
|
func formatProviders(providers []params.Provider) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(providers)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"Name", "Description", "Type"}
|
header := table.Row{"Name", "Description", "Type"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/cloudbase/garm-provider-common/util"
|
"github.com/cloudbase/garm-provider-common/util"
|
||||||
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -346,6 +347,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatRepositories(repos []params.Repository) {
|
func formatRepositories(repos []params.Repository) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(repos)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"ID", "Owner", "Name", "Endpoint", "Credentials name", "Pool Balancer Type", "Pool mgr running"}
|
header := table.Row{"ID", "Owner", "Name", "Endpoint", "Credentials name", "Pool Balancer Type", "Pool mgr running"}
|
||||||
t.AppendHeader(header)
|
t.AppendHeader(header)
|
||||||
|
|
@ -357,6 +362,10 @@ func formatRepositories(repos []params.Repository) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatOneRepository(repo params.Repository) {
|
func formatOneRepository(repo params.Repository) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(repo)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
rowConfigAutoMerge := table.RowConfig{AutoMerge: true}
|
||||||
header := table.Row{"Field", "Value"}
|
header := table.Row{"Field", "Value"}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -25,6 +26,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
apiClient "github.com/cloudbase/garm/client"
|
apiClient "github.com/cloudbase/garm/client"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/cmd/garm-cli/config"
|
"github.com/cloudbase/garm/cmd/garm-cli/config"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
@ -37,6 +39,7 @@ var (
|
||||||
needsInit bool
|
needsInit bool
|
||||||
debug bool
|
debug bool
|
||||||
poolBalancerType string
|
poolBalancerType string
|
||||||
|
outputFormat common.OutputFormat
|
||||||
errNeedsInitError = fmt.Errorf("please log into a garm installation first")
|
errNeedsInitError = fmt.Errorf("please log into a garm installation first")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -51,6 +54,11 @@ var rootCmd = &cobra.Command{
|
||||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||||
func Execute() {
|
func Execute() {
|
||||||
rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "Enable debug on all API calls")
|
rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "Enable debug on all API calls")
|
||||||
|
rootCmd.PersistentFlags().VarP(&outputFormat, "format", "f", "Output format (table, json)")
|
||||||
|
if outputFormat.String() == "" {
|
||||||
|
outputFormat = common.OutputFormatTable
|
||||||
|
}
|
||||||
|
|
||||||
cobra.OnInitialize(initConfig)
|
cobra.OnInitialize(initConfig)
|
||||||
|
|
||||||
err := rootCmd.Execute()
|
err := rootCmd.Execute()
|
||||||
|
|
@ -113,3 +121,12 @@ func formatOneHookInfo(hook params.HookInfo) {
|
||||||
})
|
})
|
||||||
fmt.Println(t.Render())
|
fmt.Println(t.Render())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printAsJSON(value interface{}) {
|
||||||
|
asJs, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to marshal value to json: %s", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println(string(asJs))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
apiClientInstances "github.com/cloudbase/garm/client/instances"
|
apiClientInstances "github.com/cloudbase/garm/client/instances"
|
||||||
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
||||||
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
||||||
|
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||||
"github.com/cloudbase/garm/params"
|
"github.com/cloudbase/garm/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -222,6 +223,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatInstances(param []params.Instance, detailed bool) {
|
func formatInstances(param []params.Instance, detailed bool) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(param)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
header := table.Row{"Nr", "Name", "Status", "Runner Status", "Pool ID"}
|
header := table.Row{"Nr", "Name", "Status", "Runner Status", "Pool ID"}
|
||||||
if detailed {
|
if detailed {
|
||||||
|
|
@ -242,6 +247,10 @@ func formatInstances(param []params.Instance, detailed bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatSingleInstance(instance params.Instance) {
|
func formatSingleInstance(instance params.Instance) {
|
||||||
|
if outputFormat == common.OutputFormatJSON {
|
||||||
|
printAsJSON(instance)
|
||||||
|
return
|
||||||
|
}
|
||||||
t := table.NewWriter()
|
t := table.NewWriter()
|
||||||
|
|
||||||
header := table.Row{"Field", "Value"}
|
header := table.Row{"Field", "Value"}
|
||||||
|
|
|
||||||
28
cmd/garm-cli/common/cobra.go
Normal file
28
cmd/garm-cli/common/cobra.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type OutputFormat string
|
||||||
|
|
||||||
|
const (
|
||||||
|
OutputFormatTable OutputFormat = "table"
|
||||||
|
OutputFormatJSON OutputFormat = "json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o OutputFormat) String() string {
|
||||||
|
return string(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OutputFormat) Set(value string) error {
|
||||||
|
switch value {
|
||||||
|
case "table", "json":
|
||||||
|
*o = OutputFormat(value)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("allowed formats are: json, table")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OutputFormat) Type() string {
|
||||||
|
return "string"
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue