Skip to content

Commit 30fa093

Browse files
Rename register to register-team for clarity
The command registers a team, not an app. Rename to javabin register-team to make this explicit and avoid confusion with future registration commands.
1 parent bd12a24 commit 30fa093

File tree

3 files changed

+85
-98
lines changed

3 files changed

+85
-98
lines changed

CLAUDE.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ Developer CLI for the Javabin platform, written in Go.
88
main.go Entrypoint — calls cmd.Execute()
99
cmd/
1010
root.go Cobra root command, registers subcommands
11-
register.go Interactive app registration wizard
11+
init.go Interactive app scaffolding wizard
12+
register.go Interactive team registration wizard
1213
status.go Project status (costs, ECS services)
1314
whoami.go Show AWS + GitHub identity
1415
internal/
@@ -33,7 +34,8 @@ internal/
3334

3435
| Command | What it does |
3536
|---------|-------------|
36-
| `javabin register` | Interactive wizard — prompts for repo, team, auth, budget; creates a registration PR against `javaBin/registry` via GitHub API |
37+
| `javabin register-team` | Interactive wizard — prompts for team name, description, members (google + github), and budget; creates a team registration PR against `javaBin/registry` (`teams/{name}.yaml`) |
38+
| `javabin init` | Interactive wizard — scaffolds a new app repo from `javaBin/app-template`, writes `app.yaml`, `Dockerfile`, and deploy workflow, then prints next steps for adding the repo to a GitHub team |
3739
| `javabin status` | Shows month-to-date cost (Cost Explorer) and ECS service status. Infers project from git remote or accepts `--project` flag |
3840
| `javabin whoami` | Shows AWS identity (STS GetCallerIdentity) and GitHub user (gh API) |
3941

@@ -59,4 +61,4 @@ Releases are built with GoReleaser on semver tags. Binaries go to GitHub Release
5961
## Related
6062

6163
- [javaBin/platform](https://github.com/javaBin/platform) — infrastructure the CLI queries
62-
- [javaBin/registry](https://github.com/javaBin/registry) — where `javabin register` creates PRs
64+
- [javaBin/registry](https://github.com/javaBin/registry) — where `javabin register-team` creates PRs

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,26 @@ go install github.com/javaBin/javabin-cli@latest # Go toolchain
1111

1212
## Commands
1313

14-
### `javabin register`
14+
### `javabin register-team`
1515

16-
Interactive wizard to register a new app with the platform. Creates a PR against [javaBin/registry](https://github.com/javaBin/registry).
16+
Interactive wizard to register a new team with the platform. Prompts for team name, description, members (Google handle + GitHub username), and optional budget. Creates a PR against [javaBin/registry](https://github.com/javaBin/registry) with `teams/{name}.yaml`.
17+
18+
After your team is created, add repos to your GitHub team:
19+
20+
```bash
21+
gh api orgs/javaBin/teams/TEAM/repos -f owner=javaBin -f repo=REPO -f permission=push
22+
```
23+
24+
```bash
25+
javabin register-team
26+
```
27+
28+
### `javabin init`
29+
30+
Interactive wizard to scaffold a new app repo from the Javabin app template. Creates the repo under `javaBin/`, writes `app.yaml`, `Dockerfile`, and a deploy workflow, then prints next steps for adding the repo to your GitHub team.
1731

1832
```bash
19-
javabin register
33+
javabin init
2034
```
2135

2236
### `javabin status`

cmd/register.go

Lines changed: 63 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ package cmd
22

33
import (
44
"bufio"
5-
"encoding/json"
65
"fmt"
7-
"net/http"
86
"os"
97
"strings"
108

@@ -14,12 +12,17 @@ import (
1412
)
1513

1614
var registerCmd = &cobra.Command{
17-
Use: "register",
18-
Short: "Register a new app with the Javabin platform",
19-
Long: "Interactive wizard that creates a registration PR against javaBin/registry.",
15+
Use: "register-team",
16+
Short: "Register a new team with the Javabin platform",
17+
Long: "Interactive wizard that creates a team registration PR against javaBin/registry.",
2018
RunE: runRegister,
2119
}
2220

21+
type member struct {
22+
Google string
23+
GitHub string
24+
}
25+
2326
func runRegister(cmd *cobra.Command, args []string) error {
2427
reader := bufio.NewReader(os.Stdin)
2528
prompt := func(label, defaultVal string) string {
@@ -41,53 +44,52 @@ func runRegister(cmd *cobra.Command, args []string) error {
4144
return fmt.Errorf("GitHub auth required: %w", err)
4245
}
4346

44-
// Repo name
45-
repoName := prompt("Repository name (e.g. moresleep)", "")
46-
if repoName == "" {
47-
return fmt.Errorf("repository name is required")
47+
// Team name
48+
teamName := prompt("Team name (lowercase, e.g. video)", "")
49+
if teamName == "" {
50+
return fmt.Errorf("team name is required")
4851
}
52+
teamName = strings.ToLower(teamName)
4953

50-
// Validate repo exists
51-
fmt.Printf("Checking javaBin/%s exists... ", repoName)
52-
if !repoExists(token, repoName) {
53-
fmt.Println("not found")
54-
return fmt.Errorf("repository javaBin/%s does not exist", repoName)
54+
// Description
55+
description := prompt("Description (what the team does)", "")
56+
if description == "" {
57+
return fmt.Errorf("description is required")
5558
}
56-
fmt.Println("ok")
5759

58-
// List teams from registry
59-
fmt.Println("\nAvailable teams:")
60-
teams, err := listTeams(token)
61-
if err != nil {
62-
fmt.Printf(" (could not fetch teams: %v)\n", err)
63-
} else {
64-
for _, t := range teams {
65-
fmt.Printf(" - %s\n", t)
60+
// Members
61+
fmt.Println("\nAdd team members (at least one). Leave blank to stop.")
62+
var members []member
63+
for i := 1; ; i++ {
64+
fmt.Printf("\n--- Member %d ---\n", i)
65+
google := prompt("Google handle (firstname.lastname)", "")
66+
if google == "" {
67+
if len(members) == 0 {
68+
fmt.Println("At least one member is required.")
69+
continue
70+
}
71+
break
6672
}
73+
github := prompt("GitHub username", "")
74+
if github == "" {
75+
fmt.Println("GitHub username is required for each member.")
76+
continue
77+
}
78+
members = append(members, member{Google: google, GitHub: github})
6779
}
68-
team := prompt("\nTeam", "")
69-
if team == "" {
70-
return fmt.Errorf("team is required")
71-
}
72-
73-
// Auth
74-
fmt.Println("\nAuth options: internal, external, both, none")
75-
auth := prompt("Auth", "none")
7680

7781
// Budget
78-
budget := prompt("Monthly budget (NOK)", "1000")
79-
80-
// Dev environment
81-
devEnv := prompt("Need a dev environment? (y/n)", "n")
82+
budget := prompt("\nMonthly budget (NOK)", "500")
8283

8384
// Confirm
84-
fmt.Println("\n--- Registration Summary ---")
85-
fmt.Printf(" Repo: javaBin/%s\n", repoName)
86-
fmt.Printf(" Team: %s\n", team)
87-
fmt.Printf(" Auth: %s\n", auth)
88-
fmt.Printf(" Budget: %s NOK\n", budget)
89-
if strings.ToLower(devEnv) == "y" {
90-
fmt.Println(" Dev: yes")
85+
fmt.Println("\n--- Team Registration Summary ---")
86+
fmt.Printf(" Name: %s\n", teamName)
87+
fmt.Printf(" Description: %s\n", description)
88+
fmt.Printf(" Google Group: team-%s@java.no\n", teamName)
89+
fmt.Printf(" Budget: %s NOK/mo\n", budget)
90+
fmt.Println(" Members:")
91+
for _, m := range members {
92+
fmt.Printf(" - %s (github: %s)\n", m.Google, m.GitHub)
9193
}
9294
fmt.Println()
9395

@@ -97,24 +99,29 @@ func runRegister(cmd *cobra.Command, args []string) error {
9799
return nil
98100
}
99101

100-
// Build app YAML content
102+
// Build team YAML content
101103
var yamlLines []string
102-
yamlLines = append(yamlLines, fmt.Sprintf("name: %s", repoName))
103-
yamlLines = append(yamlLines, fmt.Sprintf("team: %s", team))
104-
yamlLines = append(yamlLines, fmt.Sprintf("repo: javaBin/%s", repoName))
105-
if auth != "none" && auth != "" {
106-
yamlLines = append(yamlLines, fmt.Sprintf("auth: %s", auth))
104+
yamlLines = append(yamlLines, fmt.Sprintf("name: %s", teamName))
105+
yamlLines = append(yamlLines, fmt.Sprintf("description: %s", description))
106+
yamlLines = append(yamlLines, "members:")
107+
for _, m := range members {
108+
yamlLines = append(yamlLines, fmt.Sprintf(" - google: %s", m.Google))
109+
yamlLines = append(yamlLines, fmt.Sprintf(" github: %s", m.GitHub))
107110
}
108-
if budget != "1000" && budget != "" {
109-
yamlLines = append(yamlLines, fmt.Sprintf("budget_alert_nok: %s", budget))
111+
if budget != "500" && budget != "" {
112+
yamlLines = append(yamlLines, fmt.Sprintf("budget_nok: %s", budget))
110113
}
111114
yamlContent := strings.Join(yamlLines, "\n") + "\n"
112115

113116
// Create PR via GitHub API
114-
filePath := fmt.Sprintf("apps/%s.yaml", repoName)
115-
branchName := fmt.Sprintf("register-%s", repoName)
116-
prTitle := fmt.Sprintf("Register %s", repoName)
117-
prBody := fmt.Sprintf("Register `javaBin/%s` with team `%s`.\n\nCreated by `javabin register`.", repoName, team)
117+
filePath := fmt.Sprintf("teams/%s.yaml", teamName)
118+
branchName := fmt.Sprintf("register-team-%s", teamName)
119+
prTitle := fmt.Sprintf("Register team %s", teamName)
120+
prBody := fmt.Sprintf("Register team `%s`.\n\n**Description:** %s\n\n**Members:**\n", teamName, description)
121+
for _, m := range members {
122+
prBody += fmt.Sprintf("- %s (@%s)\n", m.Google, m.GitHub)
123+
}
124+
prBody += fmt.Sprintf("\nGoogle Group: `team-%s@java.no`\n\nCreated by `javabin register-team`.", teamName)
118125

119126
prURL, err := gh.CreateRegistrationPR(token, branchName, filePath, yamlContent, prTitle, prBody)
120127
if err != nil {
@@ -123,45 +130,9 @@ func runRegister(cmd *cobra.Command, args []string) error {
123130

124131
fmt.Printf("\nRegistration PR created: %s\n", prURL)
125132
fmt.Println("A platform owner will review and merge it.")
133+
fmt.Println("\nAfter your team is created, add repos to your GitHub team:")
134+
fmt.Printf(" gh api orgs/javaBin/teams/%s/repos -f owner=javaBin -f repo=REPO -f permission=push\n", teamName)
126135

127136
_ = config.EnsureConfigDir()
128137
return nil
129138
}
130-
131-
func repoExists(token, name string) bool {
132-
req, _ := http.NewRequest("GET", fmt.Sprintf("https://api.github.com/repos/javaBin/%s", name), nil)
133-
req.Header.Set("Authorization", "Bearer "+token)
134-
resp, err := http.DefaultClient.Do(req)
135-
if err != nil {
136-
return false
137-
}
138-
defer resp.Body.Close()
139-
return resp.StatusCode == 200
140-
}
141-
142-
func listTeams(token string) ([]string, error) {
143-
url := "https://api.github.com/repos/javaBin/registry/contents/teams"
144-
req, _ := http.NewRequest("GET", url, nil)
145-
req.Header.Set("Authorization", "Bearer "+token)
146-
resp, err := http.DefaultClient.Do(req)
147-
if err != nil {
148-
return nil, err
149-
}
150-
defer resp.Body.Close()
151-
if resp.StatusCode != 200 {
152-
return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
153-
}
154-
var items []struct {
155-
Name string `json:"name"`
156-
}
157-
if err := json.NewDecoder(resp.Body).Decode(&items); err != nil {
158-
return nil, err
159-
}
160-
var teams []string
161-
for _, item := range items {
162-
if strings.HasSuffix(item.Name, ".yaml") {
163-
teams = append(teams, strings.TrimSuffix(item.Name, ".yaml"))
164-
}
165-
}
166-
return teams, nil
167-
}

0 commit comments

Comments
 (0)