Skip to content

Commit 14cd5c8

Browse files
fix: added domain, and env stuff
1 parent 1309979 commit 14cd5c8

25 files changed

Lines changed: 632 additions & 199 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.claude
22
.createos.json
3+
.env.*

cmd/deployments/deployments_build_logs.go

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,41 @@ package deployments
22

33
import (
44
"fmt"
5+
"os"
6+
"os/signal"
7+
"syscall"
8+
"time"
59

610
"github.com/pterm/pterm"
711
"github.com/urfave/cli/v2"
812

913
"github.com/NodeOps-app/createos-cli/internal/api"
10-
"github.com/NodeOps-app/createos-cli/internal/cmdutil"
1114
)
1215

1316
func newDeploymentBuildLogsCommand() *cli.Command {
1417
return &cli.Command{
1518
Name: "build-logs",
1619
Usage: "Get build logs for a deployment",
1720
ArgsUsage: "[project-id] <deployment-id>",
18-
Description: "Fetches the build logs for a deployment.\n\n" +
19-
" To find your deployment ID, run:\n" +
20-
" createos projects deployments list <project-id>",
21+
Flags: []cli.Flag{
22+
&cli.BoolFlag{
23+
Name: "follow",
24+
Aliases: []string{"f"},
25+
Usage: "Continuously poll for new build logs",
26+
},
27+
&cli.DurationFlag{
28+
Name: "interval",
29+
Value: 2 * time.Second,
30+
Usage: "Polling interval when using --follow",
31+
},
32+
},
2133
Action: func(c *cli.Context) error {
2234
client, ok := c.App.Metadata[api.ClientKey].(*api.APIClient)
2335
if !ok {
2436
return fmt.Errorf("you're not signed in — run 'createos login' to get started")
2537
}
2638

27-
projectID, deploymentID, err := cmdutil.ResolveProjectScopedArg(c.Args().Slice(), "a deployment ID")
39+
projectID, deploymentID, err := resolveDeployment(c.Args().Slice(), client)
2840
if err != nil {
2941
return err
3042
}
@@ -36,17 +48,53 @@ func newDeploymentBuildLogsCommand() *cli.Command {
3648

3749
if len(entries) == 0 {
3850
fmt.Println("No build logs available yet.")
51+
} else {
52+
for _, e := range entries {
53+
fmt.Println(e.Log)
54+
}
55+
}
56+
57+
if !c.Bool("follow") {
3958
return nil
4059
}
4160

61+
pterm.Println(pterm.Gray(" Tailing build logs (Ctrl+C to stop)..."))
62+
fmt.Println()
63+
64+
lastLineNumber := 0
4265
for _, e := range entries {
43-
fmt.Println(e.Log)
66+
if e.LineNumber > lastLineNumber {
67+
lastLineNumber = e.LineNumber
68+
}
4469
}
4570

46-
fmt.Println()
47-
pterm.Println(pterm.Gray(" Tip: To see runtime logs, run:"))
48-
pterm.Println(pterm.Gray(" createos projects deployments logs " + projectID + " " + deploymentID))
49-
return nil
71+
interval := c.Duration("interval")
72+
ticker := time.NewTicker(interval)
73+
defer ticker.Stop()
74+
75+
sigCh := make(chan os.Signal, 1)
76+
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
77+
defer signal.Stop(sigCh)
78+
79+
for {
80+
select {
81+
case <-sigCh:
82+
fmt.Println()
83+
pterm.Info.Println("Log streaming stopped.")
84+
return nil
85+
case <-ticker.C:
86+
newEntries, err := client.GetDeploymentBuildLogs(projectID, deploymentID)
87+
if err != nil {
88+
continue
89+
}
90+
for _, e := range newEntries {
91+
if e.LineNumber > lastLineNumber {
92+
fmt.Println(e.Log)
93+
lastLineNumber = e.LineNumber
94+
}
95+
}
96+
}
97+
}
5098
},
5199
}
52100
}

cmd/deployments/deployments_delete.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/urfave/cli/v2"
88

99
"github.com/NodeOps-app/createos-cli/internal/api"
10-
"github.com/NodeOps-app/createos-cli/internal/cmdutil"
1110
)
1211

1312
func newDeploymentDeleteCommand() *cli.Command {
@@ -24,7 +23,7 @@ func newDeploymentDeleteCommand() *cli.Command {
2423
return fmt.Errorf("you're not signed in — run 'createos login' to get started")
2524
}
2625

27-
projectID, deploymentID, err := cmdutil.ResolveProjectScopedArg(c.Args().Slice(), "a deployment ID")
26+
projectID, deploymentID, err := resolveDeployment(c.Args().Slice(), client)
2827
if err != nil {
2928
return err
3029
}
@@ -47,9 +46,6 @@ func newDeploymentDeleteCommand() *cli.Command {
4746
}
4847

4948
pterm.Success.Println("Deployment has been cancelled.")
50-
fmt.Println()
51-
pterm.Println(pterm.Gray(" Tip: To see your deployments, run:"))
52-
pterm.Println(pterm.Gray(" createos projects deployments list " + projectID))
5349
return nil
5450
},
5551
}

cmd/deployments/deployments_list.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ func newDeploymentsListCommand() *cli.Command {
5151
if err := pterm.DefaultTable.WithHasHeader().WithData(tableData).Render(); err != nil {
5252
return err
5353
}
54-
fmt.Println()
55-
pterm.Println(pterm.Gray(" Tip: To see logs for a deployment, run:"))
56-
pterm.Println(pterm.Gray(" createos projects deployments logs " + projectID + " <deployment-id>"))
5754
return nil
5855
},
5956
}

cmd/deployments/deployments_logs.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"github.com/urfave/cli/v2"
1313

1414
"github.com/NodeOps-app/createos-cli/internal/api"
15-
"github.com/NodeOps-app/createos-cli/internal/cmdutil"
1615
)
1716

1817
func newDeploymentLogsCommand() *cli.Command {
@@ -41,7 +40,7 @@ func newDeploymentLogsCommand() *cli.Command {
4140
return fmt.Errorf("you're not signed in — run 'createos login' to get started")
4241
}
4342

44-
projectID, deploymentID, err := cmdutil.ResolveProjectScopedArg(c.Args().Slice(), "a deployment ID")
43+
projectID, deploymentID, err := resolveDeployment(c.Args().Slice(), client)
4544
if err != nil {
4645
return err
4746
}
@@ -61,8 +60,6 @@ func newDeploymentLogsCommand() *cli.Command {
6160
}
6261

6362
if !c.Bool("follow") {
64-
fmt.Println()
65-
pterm.Println(pterm.Gray(" Tip: Use --follow (-f) to tail logs in real-time."))
6663
return nil
6764
}
6865

cmd/deployments/deployments_retrigger.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/urfave/cli/v2"
88

99
"github.com/NodeOps-app/createos-cli/internal/api"
10-
"github.com/NodeOps-app/createos-cli/internal/cmdutil"
1110
)
1211

1312
func newDeploymentRetriggerCommand() *cli.Command {
@@ -24,7 +23,7 @@ func newDeploymentRetriggerCommand() *cli.Command {
2423
return fmt.Errorf("you're not signed in — run 'createos login' to get started")
2524
}
2625

27-
projectID, deploymentID, err := cmdutil.ResolveProjectScopedArg(c.Args().Slice(), "a deployment ID")
26+
projectID, deploymentID, err := resolveDeployment(c.Args().Slice(), client)
2827
if err != nil {
2928
return err
3029
}
@@ -34,9 +33,6 @@ func newDeploymentRetriggerCommand() *cli.Command {
3433
}
3534

3635
pterm.Success.Println("Deployment retriggered. A new deployment is now being built.")
37-
fmt.Println()
38-
pterm.Println(pterm.Gray(" Tip: To check the status of your deployments, run:"))
39-
pterm.Println(pterm.Gray(" createos projects deployments list " + projectID))
4036
return nil
4137
},
4238
}

cmd/deployments/deployments_wakeup.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/urfave/cli/v2"
88

99
"github.com/NodeOps-app/createos-cli/internal/api"
10-
"github.com/NodeOps-app/createos-cli/internal/cmdutil"
1110
)
1211

1312
func newDeploymentWakeupCommand() *cli.Command {
@@ -24,7 +23,7 @@ func newDeploymentWakeupCommand() *cli.Command {
2423
return fmt.Errorf("you're not signed in — run 'createos login' to get started")
2524
}
2625

27-
projectID, deploymentID, err := cmdutil.ResolveProjectScopedArg(c.Args().Slice(), "a deployment ID")
26+
projectID, deploymentID, err := resolveDeployment(c.Args().Slice(), client)
2827
if err != nil {
2928
return err
3029
}
@@ -34,9 +33,6 @@ func newDeploymentWakeupCommand() *cli.Command {
3433
}
3534

3635
pterm.Success.Println("Your deployment is waking up.")
37-
fmt.Println()
38-
pterm.Println(pterm.Gray(" Tip: To check the status of your deployments, run:"))
39-
pterm.Println(pterm.Gray(" createos projects deployments list " + projectID))
4036
return nil
4137
},
4238
}

cmd/deployments/helpers.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package deployments
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/pterm/pterm"
7+
8+
"github.com/NodeOps-app/createos-cli/internal/api"
9+
"github.com/NodeOps-app/createos-cli/internal/cmdutil"
10+
)
11+
12+
// resolveDeployment resolves projectID and deploymentID from args or interactively.
13+
// Args can be:
14+
// - <deployment-id> (project resolved from .createos.json)
15+
// - <project-id> <deployment-id> (explicit)
16+
// - (none) → project from config, deployment from interactive select
17+
func resolveDeployment(args []string, client *api.APIClient) (string, string, error) {
18+
switch len(args) {
19+
case 0:
20+
// No args — resolve project from config, then prompt for deployment
21+
projectID, err := cmdutil.ResolveProjectID("")
22+
if err != nil {
23+
return "", "", err
24+
}
25+
deploymentID, err := pickDeployment(client, projectID)
26+
if err != nil {
27+
return "", "", err
28+
}
29+
return projectID, deploymentID, nil
30+
case 1:
31+
// One arg — could be deployment ID (project from config)
32+
projectID, err := cmdutil.ResolveProjectID("")
33+
if err != nil {
34+
return "", "", err
35+
}
36+
return projectID, args[0], nil
37+
default:
38+
// Two args — project ID + deployment ID
39+
return args[0], args[1], nil
40+
}
41+
}
42+
43+
func pickDeployment(client *api.APIClient, projectID string) (string, error) {
44+
deployments, err := client.ListDeployments(projectID)
45+
if err != nil {
46+
return "", err
47+
}
48+
if len(deployments) == 0 {
49+
return "", fmt.Errorf("no deployments found for this project")
50+
}
51+
if len(deployments) == 1 {
52+
pterm.Println(pterm.Gray(fmt.Sprintf(" Using deployment: v%d (%s)", deployments[0].VersionNumber, deployments[0].Status)))
53+
return deployments[0].ID, nil
54+
}
55+
56+
options := make([]string, len(deployments))
57+
for i, d := range deployments {
58+
label := fmt.Sprintf("%s %s %s", d.CreatedAt.Format("Jan 02 15:04"), d.Status, d.ID[:8])
59+
if d.Source != nil && d.Source.Commit != "" {
60+
commit := d.Source.Commit
61+
if len(commit) > 7 {
62+
commit = commit[:7]
63+
}
64+
msg := d.Source.CommitMessage
65+
if len(msg) > 50 {
66+
msg = msg[:50] + "…"
67+
}
68+
label = fmt.Sprintf("%s %s %s %s %s", d.CreatedAt.Format("Jan 02 15:04"), d.Status, d.ID[:8], commit, msg)
69+
}
70+
options[i] = label
71+
}
72+
selected, err := pterm.DefaultInteractiveSelect.
73+
WithOptions(options).
74+
WithDefaultText("Select a deployment").
75+
Show()
76+
if err != nil {
77+
return "", fmt.Errorf("could not read selection: %w", err)
78+
}
79+
for i, opt := range options {
80+
if opt == selected {
81+
return deployments[i].ID, nil
82+
}
83+
}
84+
return "", fmt.Errorf("no deployment selected")
85+
}

cmd/domains/domains.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ func NewDomainsCommand() *cli.Command {
1313
Subcommands: []*cli.Command{
1414
newDomainsListCommand(),
1515
newDomainsAddCommand(),
16-
newDomainsRefreshCommand(),
1716
newDomainsVerifyCommand(),
1817
newDomainsDeleteCommand(),
1918
},

cmd/domains/domains_add.go

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ func newDomainsAddCommand() *cli.Command {
1515
Name: "add",
1616
Usage: "Add a custom domain to a project",
1717
ArgsUsage: "[project-id] <domain>",
18-
Description: "Adds a custom domain to your project.\n\n" +
19-
" After adding, point your DNS to the provided records, then run:\n" +
20-
" createos domains refresh <project-id> <domain-id>",
2118
Action: func(c *cli.Context) error {
2219
client, ok := c.App.Metadata[api.ClientKey].(*api.APIClient)
2320
if !ok {
@@ -29,28 +26,54 @@ func newDomainsAddCommand() *cli.Command {
2926
return err
3027
}
3128

32-
id, err := client.AddDomain(projectID, name)
29+
environmentID, err := pickEnvironment(client, projectID)
30+
if err != nil {
31+
return err
32+
}
33+
34+
id, err := client.AddDomain(projectID, name, environmentID)
3335
if err != nil {
3436
return err
3537
}
3638

3739
pterm.Success.Printf("Domain %q added successfully.\n", name)
3840
fmt.Println()
3941

40-
// Show DNS setup instructions
41-
fmt.Println(" Configure your DNS with the following record:")
42-
fmt.Println()
43-
tableData := pterm.TableData{
44-
{"Type", "Name", "Value"},
45-
{"CNAME", name, projectID + ".nodeops.app"},
42+
// Fetch domain to get DNS records
43+
domains, err := client.ListDomains(projectID)
44+
if err == nil {
45+
for _, d := range domains {
46+
if d.ID == id {
47+
printDNSRecords(d)
48+
return nil
49+
}
50+
}
4651
}
47-
if err := pterm.DefaultTable.WithHasHeader().WithData(tableData).Render(); err != nil {
48-
return err
49-
}
50-
fmt.Println()
51-
pterm.Println(pterm.Gray(" After updating DNS, verify with:"))
52-
pterm.Println(pterm.Gray(" createos domains refresh " + projectID + " " + id))
52+
53+
// Fallback if records not yet available
54+
fmt.Println(" DNS records are being generated. Run 'createos domains verify' to check status.")
5355
return nil
5456
},
5557
}
5658
}
59+
60+
func printDNSRecords(d api.Domain) {
61+
if d.Records == nil || (len(d.Records.ARecords) == 0 && len(d.Records.TXTRecords) == 0) {
62+
fmt.Println(" DNS records are being generated. Run verify to check status.")
63+
return
64+
}
65+
66+
fmt.Println(" Configure your DNS with the following records:")
67+
fmt.Println()
68+
69+
tableData := pterm.TableData{{"Type", "Name", "Value"}}
70+
for _, a := range d.Records.ARecords {
71+
tableData = append(tableData, []string{"A", d.Name, a})
72+
}
73+
for _, txt := range d.Records.TXTRecords {
74+
tableData = append(tableData, []string{"TXT", txt.Name + "." + d.Name, txt.Value})
75+
}
76+
77+
_ = pterm.DefaultTable.WithHasHeader().WithData(tableData).Render()
78+
fmt.Println()
79+
}

0 commit comments

Comments
 (0)