mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
chore: use workspace name as arg in coder workspaces create
(#1007)
This commit is contained in:
@ -26,13 +26,14 @@ func templateCreate() *cobra.Command {
|
|||||||
provisioner string
|
provisioner string
|
||||||
)
|
)
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "create <directory> [name]",
|
Use: "create [name]",
|
||||||
Short: "Create a template from the current directory",
|
Short: "Create a template from the current directory",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
client, err := createClient(cmd)
|
client, err := createClient(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
organization, err := currentOrganization(cmd, client)
|
organization, err := currentOrganization(cmd, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -44,6 +45,7 @@ func templateCreate() *cobra.Command {
|
|||||||
} else {
|
} else {
|
||||||
templateName = args[0]
|
templateName = args[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.TemplateByName(cmd.Context(), organization.ID, templateName)
|
_, err = client.TemplateByName(cmd.Context(), organization.ID, templateName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return xerrors.Errorf("A template already exists named %q!", templateName)
|
return xerrors.Errorf("A template already exists named %q!", templateName)
|
||||||
@ -113,7 +115,7 @@ func templateCreate() *cobra.Command {
|
|||||||
"The "+cliui.Styles.Keyword.Render(templateName)+" template has been created! "+
|
"The "+cliui.Styles.Keyword.Render(templateName)+" template has been created! "+
|
||||||
"Developers can provision a workspace with this template using:")+"\n")
|
"Developers can provision a workspace with this template using:")+"\n")
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+cliui.Styles.Code.Render("coder workspaces create "+templateName))
|
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+cliui.Styles.Code.Render(fmt.Sprintf("coder workspaces create --template=%q [workspace name]", templateName)))
|
||||||
_, _ = fmt.Fprintln(cmd.OutOrStdout())
|
_, _ = fmt.Fprintln(cmd.OutOrStdout())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -214,9 +216,15 @@ func createValidTemplateVersion(cmd *cobra.Command, client *codersdk.Client, org
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return &version, parameters, cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{
|
|
||||||
|
err = cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{
|
||||||
HideAgentState: true,
|
HideAgentState: true,
|
||||||
HideAccess: true,
|
HideAccess: true,
|
||||||
Title: "Template Preview",
|
Title: "Template Preview",
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, xerrors.Errorf("preview template resources: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &version, parameters, nil
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/coder/coder/cli/cliflag"
|
"github.com/coder/coder/cli/cliflag"
|
||||||
@ -17,67 +17,24 @@ import (
|
|||||||
func workspaceCreate() *cobra.Command {
|
func workspaceCreate() *cobra.Command {
|
||||||
var (
|
var (
|
||||||
workspaceName string
|
workspaceName string
|
||||||
|
templateName string
|
||||||
)
|
)
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "create [template]",
|
Use: "create [name]",
|
||||||
Short: "Create a workspace from a template",
|
Short: "Create a workspace from a template",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
client, err := createClient(cmd)
|
client, err := createClient(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
organization, err := currentOrganization(cmd, client)
|
organization, err := currentOrganization(cmd, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
templateName := ""
|
|
||||||
if len(args) >= 1 {
|
if len(args) >= 1 {
|
||||||
templateName = args[0]
|
workspaceName = args[0]
|
||||||
}
|
|
||||||
|
|
||||||
var template codersdk.Template
|
|
||||||
if templateName == "" {
|
|
||||||
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Wrap.Render("Select a template below to preview the provisioned infrastructure:"))
|
|
||||||
|
|
||||||
templateNames := []string{}
|
|
||||||
templateByName := map[string]codersdk.Template{}
|
|
||||||
templates, err := client.TemplatesByOrganization(cmd.Context(), organization.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, template := range templates {
|
|
||||||
templateName := template.Name
|
|
||||||
if template.WorkspaceOwnerCount > 0 {
|
|
||||||
developerText := "developer"
|
|
||||||
if template.WorkspaceOwnerCount != 1 {
|
|
||||||
developerText = "developers"
|
|
||||||
}
|
|
||||||
templateName += cliui.Styles.Placeholder.Render(fmt.Sprintf(" (used by %d %s)", template.WorkspaceOwnerCount, developerText))
|
|
||||||
}
|
|
||||||
templateNames = append(templateNames, templateName)
|
|
||||||
templateByName[templateName] = template
|
|
||||||
}
|
|
||||||
sort.Slice(templateNames, func(i, j int) bool {
|
|
||||||
return templateByName[templateNames[i]].WorkspaceOwnerCount > templateByName[templateNames[j]].WorkspaceOwnerCount
|
|
||||||
})
|
|
||||||
// Move the cursor up a single line for nicer display!
|
|
||||||
option, err := cliui.Select(cmd, cliui.SelectOptions{
|
|
||||||
Options: templateNames,
|
|
||||||
HideSearch: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
template = templateByName[option]
|
|
||||||
} else {
|
|
||||||
template, err = client.TemplateByName(cmd.Context(), organization.ID, templateName)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("get template by name: %w", err)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if workspaceName == "" {
|
if workspaceName == "" {
|
||||||
@ -101,6 +58,55 @@ func workspaceCreate() *cobra.Command {
|
|||||||
return xerrors.Errorf("A workspace already exists named %q!", workspaceName)
|
return xerrors.Errorf("A workspace already exists named %q!", workspaceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var template codersdk.Template
|
||||||
|
if templateName == "" {
|
||||||
|
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Wrap.Render("Select a template below to preview the provisioned infrastructure:"))
|
||||||
|
|
||||||
|
templates, err := client.TemplatesByOrganization(cmd.Context(), organization.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.SortFunc(templates, func(a, b codersdk.Template) bool {
|
||||||
|
return a.WorkspaceOwnerCount > b.WorkspaceOwnerCount
|
||||||
|
})
|
||||||
|
|
||||||
|
templateNames := make([]string, 0, len(templates))
|
||||||
|
templateByName := make(map[string]codersdk.Template, len(templates))
|
||||||
|
|
||||||
|
for _, template := range templates {
|
||||||
|
templateName := template.Name
|
||||||
|
|
||||||
|
if template.WorkspaceOwnerCount > 0 {
|
||||||
|
developerText := "developer"
|
||||||
|
if template.WorkspaceOwnerCount != 1 {
|
||||||
|
developerText = "developers"
|
||||||
|
}
|
||||||
|
|
||||||
|
templateName += cliui.Styles.Placeholder.Render(fmt.Sprintf(" (used by %d %s)", template.WorkspaceOwnerCount, developerText))
|
||||||
|
}
|
||||||
|
|
||||||
|
templateNames = append(templateNames, templateName)
|
||||||
|
templateByName[templateName] = template
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the cursor up a single line for nicer display!
|
||||||
|
option, err := cliui.Select(cmd, cliui.SelectOptions{
|
||||||
|
Options: templateNames,
|
||||||
|
HideSearch: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
template = templateByName[option]
|
||||||
|
} else {
|
||||||
|
template, err = client.TemplateByName(cmd.Context(), organization.ID, templateName)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("get template by name: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
templateVersion, err := client.TemplateVersion(cmd.Context(), template.ActiveVersionID)
|
templateVersion, err := client.TemplateVersion(cmd.Context(), template.ActiveVersionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -164,10 +170,12 @@ func workspaceCreate() *cobra.Command {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStdout(), client, workspace.LatestBuild.ID, before)
|
err = cliui.WorkspaceBuild(cmd.Context(), cmd.OutOrStdout(), client, workspace.LatestBuild.ID, before)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resources, err = client.WorkspaceResourcesByBuild(cmd.Context(), workspace.LatestBuild.ID)
|
resources, err = client.WorkspaceResourcesByBuild(cmd.Context(), workspace.LatestBuild.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -179,11 +187,12 @@ func workspaceCreate() *cobra.Command {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "The %s workspace has been created!\n", cliui.Styles.Keyword.Render(workspace.Name))
|
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "The %s workspace has been created!\n", cliui.Styles.Keyword.Render(workspace.Name))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cliflag.StringVarP(cmd.Flags(), &workspaceName, "name", "n", "CODER_WORKSPACE_NAME", "", "Specify a workspace name.")
|
|
||||||
|
|
||||||
|
cliflag.StringVarP(cmd.Flags(), &templateName, "template", "t", "CODER_TEMPLATE_NAME", "", "Specify a template name.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ func TestWorkspaceCreate(t *testing.T) {
|
|||||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||||
cmd, root := clitest.New(t, "workspaces", "create", template.Name, "--name", "my-workspace")
|
cmd, root := clitest.New(t, "workspaces", "create", "my-workspace", "--template", template.Name)
|
||||||
clitest.SetupConfig(t, client, root)
|
clitest.SetupConfig(t, client, root)
|
||||||
doneChan := make(chan struct{})
|
doneChan := make(chan struct{})
|
||||||
pty := ptytest.New(t)
|
pty := ptytest.New(t)
|
||||||
@ -52,7 +52,7 @@ func TestWorkspaceCreate(t *testing.T) {
|
|||||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||||
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||||
cmd, root := clitest.New(t, "workspaces", "create", "--name", "my-workspace")
|
cmd, root := clitest.New(t, "workspaces", "create", "my-workspace")
|
||||||
clitest.SetupConfig(t, client, root)
|
clitest.SetupConfig(t, client, root)
|
||||||
doneChan := make(chan struct{})
|
doneChan := make(chan struct{})
|
||||||
pty := ptytest.New(t)
|
pty := ptytest.New(t)
|
||||||
@ -82,7 +82,7 @@ func TestWorkspaceCreate(t *testing.T) {
|
|||||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||||
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||||
cmd, root := clitest.New(t, "workspaces", "create", "--name", "")
|
cmd, root := clitest.New(t, "workspaces", "create", "")
|
||||||
clitest.SetupConfig(t, client, root)
|
clitest.SetupConfig(t, client, root)
|
||||||
doneChan := make(chan struct{})
|
doneChan := make(chan struct{})
|
||||||
pty := ptytest.New(t)
|
pty := ptytest.New(t)
|
||||||
@ -134,7 +134,7 @@ func TestWorkspaceCreate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||||
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
_ = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||||
cmd, root := clitest.New(t, "workspaces", "create", "--name", "")
|
cmd, root := clitest.New(t, "workspaces", "create", "")
|
||||||
clitest.SetupConfig(t, client, root)
|
clitest.SetupConfig(t, client, root)
|
||||||
doneChan := make(chan struct{})
|
doneChan := make(chan struct{})
|
||||||
pty := ptytest.New(t)
|
pty := ptytest.New(t)
|
||||||
|
3
go.mod
3
go.mod
@ -92,7 +92,8 @@ require (
|
|||||||
go.uber.org/atomic v1.9.0
|
go.uber.org/atomic v1.9.0
|
||||||
go.uber.org/goleak v1.1.12
|
go.uber.org/goleak v1.1.12
|
||||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
||||||
golang.org/x/mod v0.5.1
|
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57
|
||||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
|
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886
|
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886
|
||||||
|
6
go.sum
6
go.sum
@ -1787,6 +1787,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
|
|||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20200901203048-c4f52b2c50aa/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200901203048-c4f52b2c50aa/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20200908183739-ae8ad444f925/go.mod h1:1phAWC201xIgDyaFpmDeZkgf70Q4Pd/CNqfRtVPtxNw=
|
golang.org/x/exp v0.0.0-20200908183739-ae8ad444f925/go.mod h1:1phAWC201xIgDyaFpmDeZkgf70Q4Pd/CNqfRtVPtxNw=
|
||||||
|
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4=
|
||||||
|
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
@ -1821,8 +1823,8 @@ golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hM
|
|||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
Reference in New Issue
Block a user