unprovision

This commit is contained in:
pavel 2026-05-15 18:41:27 +02:00
commit 1e53bba6e7
6 changed files with 148 additions and 0 deletions

View file

@ -46,6 +46,8 @@ func RunCLI(args []string) error {
switch args[0] {
case "provision":
return runCLIProvision(args[1:])
case "unprovision":
return runCLIUnprovision(args[1:])
case "login":
return runCLILogin(args[1:])
case "help", "--help", "-h":
@ -121,6 +123,44 @@ func runCLIProvision(args []string) error {
return nil
}
func runCLIUnprovision(args []string) error {
state, _ := loadCLIState()
fs := flag.NewFlagSet("unprovision", flag.ContinueOnError)
fs.SetOutput(os.Stderr)
var apiURL, name string
fs.StringVar(&apiURL, "api-url", firstNonEmpty(state.APIURL, getenv("BOX_API_URL", "http://127.0.0.1:8080")), "box server API base URL")
fs.StringVar(&name, "name", "", "project name (required)")
if err := fs.Parse(args); err != nil {
return err
}
apiURL = strings.TrimRight(strings.TrimSpace(apiURL), "/")
name = strings.TrimSpace(name)
if apiURL == "" || name == "" {
return errors.New("required flags: --api-url, --name")
}
state.APIURL = apiURL
c := cliClient{baseURL: apiURL, state: &state}
if err := c.ensureAccessToken(); err != nil {
return err
}
if err := saveCLIState(state); err != nil {
return err
}
existing, err := c.findProjectBySlug(slugify(name))
if err != nil {
return err
}
if existing == nil {
return errors.New("project not found")
}
if err := c.postEmpty(fmt.Sprintf("/api/projects/%d/unprovision", existing.ID)); err != nil {
return err
}
fmt.Printf("project unprovisioned id=%d name=%s slug=%s\n", existing.ID, existing.Name, existing.Slug)
return nil
}
func runCLILogin(args []string) error {
state, _ := loadCLIState()
fs := flag.NewFlagSet("login", flag.ContinueOnError)
@ -448,6 +488,28 @@ func (c *cliClient) postJSON(path string, payload any, out any) error {
return json.Unmarshal(body, out)
}
func (c *cliClient) postEmpty(path string) error {
if err := c.ensureAccessToken(); err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, c.baseURL+path, bytes.NewReader([]byte("{}")))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+c.state.AccessToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode >= 300 {
return fmt.Errorf("api %s failed status=%d body=%s", path, resp.StatusCode, strings.TrimSpace(string(body)))
}
return nil
}
func printCLIProject(action string, p Project) {
fmt.Printf("project %s id=%d name=%s slug=%s\n", action, p.ID, p.Name, p.Slug)
fmt.Printf("workspace=%s unix_user=%s\n", p.Workspace, p.UnixUser)
@ -533,9 +595,11 @@ func cliUsageText() string {
go run . # server
go run ./cmd/boxctl login --api-url https://box.example.com --issuer https://auth.example.com/application/o/box --client-id box-cli [--workspace <name>] [--unix-user <unix_user>]
go run ./cmd/boxctl provision --name <project_name> [--repo-url <url>] [--description <text>] [--private=true|false]
go run ./cmd/boxctl unprovision --name <project_name>
Commands:
login OAuth browser login (PKCE) and save tokens/defaults in ~/.config/boxctl/config.json
provision Upsert project via API using bearer token
unprovision Tear down project service/db/route and remove project record
`
}