Skip to content

Commit a417b18

Browse files
committed
add project commands and reference documentation
1 parent 21fbde5 commit a417b18

25 files changed

Lines changed: 1096 additions & 38 deletions

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ define gen-doc-in-dir
3232
cat ./$1/koyeb_sandbox_*.md >> ./$1/reference.md
3333
cat ./$1/koyeb_version.md >> ./$1/reference.md
3434
cat ./$1/koyeb_volumes.md >> ./$1/reference.md
35+
cat ./$1/koyeb_projects.md >> ./$1/reference.md
36+
cat ./$1/koyeb_projects_*.md >> ./$1/reference.md
37+
3538
find ./$1 -type f -not -name 'reference.md' -delete
3639
endef
3740

docs/reference.md

Lines changed: 401 additions & 36 deletions
Large diffs are not rendered by default.

pkg/koyeb/apps.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func NewAppCmd() *cobra.Command {
3838
}),
3939
}
4040
createAppCmd.Flags().Bool("delete-when-empty", false, "Automatically delete the app after the last service is deleted. Empty apps created without services are not deleted.")
41+
createAppCmd.Flags().StringP("project", "p", "", "Project name or ID")
4142
appCmd.AddCommand(createAppCmd)
4243

4344
initAppCmd := &cobra.Command{
@@ -64,6 +65,7 @@ func NewAppCmd() *cobra.Command {
6465
}
6566
initAppCmd.Flags().Bool("wait", false, "Waits until app deployment is done")
6667
initAppCmd.Flags().Duration("wait-timeout", 5*time.Minute, "Duration the wait will last until timeout")
68+
initAppCmd.Flags().StringP("project", "p", "", "Project name or ID")
6769
appCmd.AddCommand(initAppCmd)
6870
serviceHandler.addServiceDefinitionFlags(initAppCmd.Flags())
6971

@@ -73,13 +75,16 @@ func NewAppCmd() *cobra.Command {
7375
Args: cobra.ExactArgs(1),
7476
RunE: WithCLIContext(h.Get),
7577
}
78+
getAppCmd.Flags().StringP("project", "p", "", "Project name or ID (optional context)")
7679
appCmd.AddCommand(getAppCmd)
7780

7881
listAppCmd := &cobra.Command{
7982
Use: "list",
8083
Short: "List apps",
8184
RunE: WithCLIContext(h.List),
8285
}
86+
listAppCmd.Flags().StringP("project", "p", "", "Project name or ID (filter apps by project)")
87+
listAppCmd.Flags().Bool("all-projects", false, "List apps from all projects (overrides project filter)")
8388
appCmd.AddCommand(listAppCmd)
8489

8590
describeAppCmd := &cobra.Command{
@@ -88,6 +93,7 @@ func NewAppCmd() *cobra.Command {
8893
Args: cobra.ExactArgs(1),
8994
RunE: WithCLIContext(h.Describe),
9095
}
96+
describeAppCmd.Flags().StringP("project", "p", "", "Project name or ID (optional context)")
9197
appCmd.AddCommand(describeAppCmd)
9298

9399
updateAppCmd := &cobra.Command{
@@ -130,6 +136,7 @@ func NewAppCmd() *cobra.Command {
130136
updateAppCmd.Flags().StringP("name", "n", "", "Change the name of the app")
131137
updateAppCmd.Flags().StringP("domain", "D", "", "Change the subdomain of the app (only specify the subdomain, skipping \".koyeb.app\")")
132138
updateAppCmd.Flags().Bool("delete-when-empty", false, "Automatically delete the app after the last service is deleted. Empty apps created without services are not deleted.")
139+
updateAppCmd.Flags().StringP("project", "p", "", "Project name or ID (optional context)")
133140
appCmd.AddCommand(updateAppCmd)
134141

135142
deleteAppCmd := &cobra.Command{
@@ -138,6 +145,7 @@ func NewAppCmd() *cobra.Command {
138145
Args: cobra.ExactArgs(1),
139146
RunE: WithCLIContext(h.Delete),
140147
}
148+
deleteAppCmd.Flags().StringP("project", "p", "", "Project name or ID (optional context)")
141149
appCmd.AddCommand(deleteAppCmd)
142150

143151
pauseServiceCmd := &cobra.Command{

pkg/koyeb/apps_create.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ func (h *AppHandler) CreateApp(ctx *CLIContext, payload *koyeb.CreateApp) (*koye
2323
func (h *AppHandler) Create(ctx *CLIContext, cmd *cobra.Command, args []string, createApp *koyeb.CreateApp) error {
2424
createApp.SetName(args[0])
2525

26+
projectFlag, _ := cmd.Flags().GetString("project")
27+
if projectFlag != "" {
28+
projectHandler := NewProjectHandler()
29+
projectID, err := projectHandler.ResolveProjectArgs(ctx, projectFlag)
30+
if err != nil {
31+
return err
32+
}
33+
createApp.SetProjectId(projectID)
34+
}
35+
2636
res, err := h.CreateApp(ctx, createApp)
2737
if err != nil {
2838
return err

pkg/koyeb/apps_list.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ import (
1313
func (h *AppHandler) List(ctx *CLIContext, cmd *cobra.Command, args []string) error {
1414
list := []koyeb.AppListItem{}
1515

16+
// TODO: Implement project filtering when API support is available
17+
// Check if we should filter by project
18+
// allProjects, _ := cmd.Flags().GetBool("all-projects")
19+
// projectFlag, _ := cmd.Flags().GetString("project")
20+
//
21+
// var projectID string
22+
// if !allProjects && projectFlag != "" {
23+
// projectHandler := NewProjectHandler()
24+
// var err error
25+
// projectID, err = projectHandler.ResolveProjectArgs(ctx, projectFlag)
26+
// if err != nil {
27+
// return err
28+
// }
29+
// }
30+
1631
page := int64(0)
1732
offset := int64(0)
1833
limit := int64(100)

pkg/koyeb/context.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ const (
1818
ctx_mapper
1919
ctx_renderer
2020
ctx_organization
21+
ctx_project
2122
)
2223

2324
// SetupCLIContext is called by the root command to setup the context for all subcommands.
2425
// When `organization` is not empty, it should contain the ID of the organization to switch the context to.
25-
func SetupCLIContext(cmd *cobra.Command, organization string) error {
26+
// When `project` is not empty, it should contain the ID of the project to use in the context.
27+
// If the project is invalid or doesn't exist in the current organization, it will be cleared.
28+
func SetupCLIContext(cmd *cobra.Command, organization string, project string) error {
2629
apiClient, err := getApiClient()
2730
if err != nil {
2831
return err
@@ -60,6 +63,17 @@ func SetupCLIContext(cmd *cobra.Command, organization string) error {
6063
ctx = context.WithValue(ctx, ctx_mapper, idmapper.NewMapper(ctx, apiClient))
6164
ctx = context.WithValue(ctx, ctx_renderer, renderer.NewRenderer(outputFormat))
6265
ctx = context.WithValue(ctx, ctx_organization, organization)
66+
67+
// Validate project exists in current organization. If not, clear it as fallback.
68+
if project != "" {
69+
projectMapper := idmapper.NewMapper(ctx, apiClient).Project()
70+
if _, err := projectMapper.ResolveID(project); err != nil {
71+
// Project is invalid or doesn't exist - clear it silently as fallback
72+
project = ""
73+
}
74+
}
75+
76+
ctx = context.WithValue(ctx, ctx_project, project)
6377
cmd.SetContext(ctx)
6478

6579
return nil
@@ -74,6 +88,7 @@ type CLIContext struct {
7488
Token string
7589
Renderer renderer.Renderer
7690
Organization string
91+
Project string
7792
}
7893

7994
// GetCLIContext transforms the untyped context passed to cobra commands into a CLIContext.
@@ -87,6 +102,7 @@ func GetCLIContext(ctx context.Context) *CLIContext {
87102
Token: ctx.Value(koyeb.ContextAccessToken).(string),
88103
Renderer: ctx.Value(ctx_renderer).(renderer.Renderer),
89104
Organization: ctx.Value(ctx_organization).(string),
105+
Project: ctx.Value(ctx_project).(string),
90106
}
91107
}
92108

pkg/koyeb/databases.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ func NewDatabaseCmd() *cobra.Command {
2525
Short: "List databases",
2626
RunE: WithCLIContext(h.List),
2727
}
28+
listDbCmd.Flags().StringP("project", "p", "", "Project name or ID")
2829
databaseCmd.AddCommand(listDbCmd)
2930

3031
getDbCmd := &cobra.Command{
@@ -34,6 +35,7 @@ func NewDatabaseCmd() *cobra.Command {
3435
RunE: WithCLIContext(h.Get),
3536
}
3637
getDbCmd.Flags().String("app", "", "Database application. If the application does not exist, it will be created. Can also be provided in the database name with the format `app-name/database-name`")
38+
getDbCmd.Flags().StringP("project", "p", "", "Project name or ID")
3739
databaseCmd.AddCommand(getDbCmd)
3840

3941
createDbCmd := &cobra.Command{
@@ -58,6 +60,7 @@ func NewDatabaseCmd() *cobra.Command {
5860
}),
5961
}
6062
addCreateDbServiceDefinitionFlags(createDbCmd.Flags())
63+
createDbCmd.Flags().StringP("project", "p", "", "Project name or ID")
6164
databaseCmd.AddCommand(createDbCmd)
6265

6366
updateDbCmd := &cobra.Command{
@@ -113,6 +116,7 @@ func NewDatabaseCmd() *cobra.Command {
113116
}),
114117
}
115118
addUpdateDbServiceDefinitionFlags(updateDbCmd.Flags())
119+
updateDbCmd.Flags().StringP("project", "p", "", "Project name or ID")
116120
databaseCmd.AddCommand(updateDbCmd)
117121

118122
deleteDbCmd := &cobra.Command{
@@ -121,6 +125,7 @@ func NewDatabaseCmd() *cobra.Command {
121125
Args: cobra.ExactArgs(1),
122126
RunE: WithCLIContext(h.Delete),
123127
}
128+
deleteDbCmd.Flags().StringP("project", "p", "", "Project name or ID")
124129
databaseCmd.AddCommand(deleteDbCmd)
125130

126131
return databaseCmd

pkg/koyeb/domains.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func NewDomainCmd() *cobra.Command {
1919
Args: cobra.ExactArgs(1),
2020
RunE: WithCLIContext(h.Get),
2121
}
22+
getDomainCmd.Flags().StringP("project", "p", "", "Project name or ID")
2223
domainCmd.AddCommand(getDomainCmd)
2324

2425
createDomainCmd := &cobra.Command{
@@ -28,6 +29,7 @@ func NewDomainCmd() *cobra.Command {
2829
RunE: WithCLIContext(h.Create),
2930
}
3031
createDomainCmd.Flags().String("attach-to", "", "Upon creation, assign to given app")
32+
createDomainCmd.Flags().StringP("project", "p", "", "Project name or ID")
3133
domainCmd.AddCommand(createDomainCmd)
3234

3335
describeDomainCmd := &cobra.Command{
@@ -36,20 +38,23 @@ func NewDomainCmd() *cobra.Command {
3638
Args: cobra.ExactArgs(1),
3739
RunE: WithCLIContext(h.Describe),
3840
}
41+
describeDomainCmd.Flags().StringP("project", "p", "", "Project name or ID")
3942
domainCmd.AddCommand(describeDomainCmd)
4043

4144
listDomainCmd := &cobra.Command{
4245
Use: "list",
4346
Short: "List domains",
4447
RunE: WithCLIContext(h.List),
4548
}
49+
listDomainCmd.Flags().StringP("project", "p", "", "Project name or ID")
4650
domainCmd.AddCommand(listDomainCmd)
4751

4852
deleteDomainCmd := &cobra.Command{
4953
Use: "delete",
5054
Short: "Delete domain",
5155
RunE: WithCLIContext(h.Delete),
5256
}
57+
deleteDomainCmd.Flags().StringP("project", "p", "", "Project name or ID")
5358
domainCmd.AddCommand(deleteDomainCmd)
5459

5560
refreshDomainCmd := &cobra.Command{
@@ -58,6 +63,7 @@ func NewDomainCmd() *cobra.Command {
5863
Args: cobra.ExactArgs(1),
5964
RunE: WithCLIContext(h.Refresh),
6065
}
66+
refreshDomainCmd.Flags().StringP("project", "p", "", "Project name or ID")
6167
domainCmd.AddCommand(refreshDomainCmd)
6268

6369
attachDomainCmd := &cobra.Command{
@@ -66,6 +72,7 @@ func NewDomainCmd() *cobra.Command {
6672
Args: cobra.ExactArgs(2),
6773
RunE: WithCLIContext(h.Attach),
6874
}
75+
attachDomainCmd.Flags().StringP("project", "p", "", "Project name or ID")
6976
domainCmd.AddCommand(attachDomainCmd)
7077

7178
detachDomainCmd := &cobra.Command{
@@ -74,6 +81,7 @@ func NewDomainCmd() *cobra.Command {
7481
Args: cobra.ExactArgs(1),
7582
RunE: WithCLIContext(h.Detach),
7683
}
84+
detachDomainCmd.Flags().StringP("project", "p", "", "Project name or ID")
7785
domainCmd.AddCommand(detachDomainCmd)
7886

7987
return domainCmd

pkg/koyeb/domains_create.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ func (h *DomainHandler) Create(ctx *CLIContext, cmd *cobra.Command, args []strin
1313
createDomainReq.SetName(args[0])
1414
createDomainReq.SetType(koyeb.DOMAINTYPE_CUSTOM)
1515

16+
projectFlag, _ := cmd.Flags().GetString("project")
17+
if projectFlag != "" {
18+
projectHandler := NewProjectHandler()
19+
projectID, err := projectHandler.ResolveProjectArgs(ctx, projectFlag)
20+
if err != nil {
21+
return err
22+
}
23+
createDomainReq.SetProjectId(projectID)
24+
}
25+
1626
attachToApp := GetStringFlags(cmd, "attach-to")
1727
if attachToApp != "" {
1828
appID, err := ctx.Mapper.App().ResolveID(attachToApp)

pkg/koyeb/idmapper/idmapper.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type Mapper struct {
1818
database *DatabaseMapper
1919
volume *VolumeMapper
2020
snapshot *SnapshotMapper
21+
project *ProjectMapper
2122
}
2223

2324
func NewMapper(ctx context.Context, client *koyeb.APIClient) *Mapper {
@@ -32,6 +33,7 @@ func NewMapper(ctx context.Context, client *koyeb.APIClient) *Mapper {
3233
databaseMapper := NewDatabaseMapper(ctx, client, appMapper)
3334
volumeMapper := NewVolumeMapper(ctx, client)
3435
snapshotMapper := NewSnapshotMapper(ctx, client)
36+
projectMapper := NewProjectMapper(ctx, client)
3537

3638
return &Mapper{
3739
app: appMapper,
@@ -45,6 +47,7 @@ func NewMapper(ctx context.Context, client *koyeb.APIClient) *Mapper {
4547
database: databaseMapper,
4648
volume: volumeMapper,
4749
snapshot: snapshotMapper,
50+
project: projectMapper,
4851
}
4952
}
5053

@@ -91,3 +94,7 @@ func (mapper *Mapper) Volume() *VolumeMapper {
9194
func (mapper *Mapper) Snapshot() *SnapshotMapper {
9295
return mapper.snapshot
9396
}
97+
98+
func (mapper *Mapper) Project() *ProjectMapper {
99+
return mapper.project
100+
}

0 commit comments

Comments
 (0)