feat: Add "projects list" command to the CLI (#333)

This adds a WorkspaceOwnerCount parameter returned from the
projects API. It's helpful to display the amount of usage
a specific project has.
This commit is contained in:
Kyle Carberry
2022-02-21 12:47:08 -06:00
committed by GitHub
parent 59ee22d368
commit 67613da86d
13 changed files with 311 additions and 16 deletions

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"net/http"
"time"
"github.com/go-chi/render"
"github.com/google/uuid"
@ -30,7 +31,16 @@ type CreateParameterValueRequest struct {
// Project is the JSON representation of a Coder project.
// This type matches the database object for now, but is
// abstracted for ease of change later on.
type Project database.Project
type Project struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
Provisioner database.ProvisionerType `json:"provisioner"`
ActiveVersionID uuid.UUID `json:"active_version_id"`
WorkspaceOwnerCount uint32 `json:"workspace_owner_count"`
}
// CreateProjectRequest enables callers to create a new Project.
type CreateProjectRequest struct {
@ -69,11 +79,22 @@ func (api *api) projects(rw http.ResponseWriter, r *http.Request) {
})
return
}
if projects == nil {
projects = []database.Project{}
projectIDs := make([]uuid.UUID, 0, len(projects))
for _, project := range projects {
projectIDs = append(projectIDs, project.ID)
}
workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByProjectIDs(r.Context(), projectIDs)
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace counts: %s", err.Error()),
})
return
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, projects)
render.JSON(rw, r, convertProjects(projects, workspaceCounts))
}
// Lists all projects in an organization.
@ -89,11 +110,22 @@ func (api *api) projectsByOrganization(rw http.ResponseWriter, r *http.Request)
})
return
}
if projects == nil {
projects = []database.Project{}
projectIDs := make([]uuid.UUID, 0, len(projects))
for _, project := range projects {
projectIDs = append(projectIDs, project.ID)
}
workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByProjectIDs(r.Context(), projectIDs)
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace counts: %s", err.Error()),
})
return
}
render.Status(r, http.StatusOK)
render.JSON(rw, r, projects)
render.JSON(rw, r, convertProjects(projects, workspaceCounts))
}
// Create a new project in an organization.
@ -162,7 +194,7 @@ func (api *api) postProjectsByOrganization(rw http.ResponseWriter, r *http.Reque
if err != nil {
return xerrors.Errorf("insert project version: %s", err)
}
project = Project(dbProject)
project = convertProject(dbProject, 0)
return nil
})
if err != nil {
@ -241,6 +273,38 @@ func (api *api) parametersByProject(rw http.ResponseWriter, r *http.Request) {
render.JSON(rw, r, apiParameterValues)
}
func convertProjects(projects []database.Project, workspaceCounts []database.GetWorkspaceOwnerCountsByProjectIDsRow) []Project {
apiProjects := make([]Project, 0, len(projects))
for _, project := range projects {
found := false
for _, workspaceCount := range workspaceCounts {
if workspaceCount.ProjectID.String() != project.ID.String() {
continue
}
apiProjects = append(apiProjects, convertProject(project, uint32(workspaceCount.Count)))
found = true
break
}
if !found {
apiProjects = append(apiProjects, convertProject(project, uint32(0)))
}
}
return apiProjects
}
func convertProject(project database.Project, workspaceOwnerCount uint32) Project {
return Project{
ID: project.ID,
CreatedAt: project.CreatedAt,
UpdatedAt: project.UpdatedAt,
OrganizationID: project.OrganizationID,
Name: project.Name,
Provisioner: project.Provisioner,
ActiveVersionID: project.ActiveVersionID,
WorkspaceOwnerCount: workspaceOwnerCount,
}
}
func convertParameterValue(parameterValue database.ParameterValue) ParameterValue {
parameterValue.SourceValue = ""
return ParameterValue(parameterValue)

View File

@ -36,6 +36,22 @@ func TestProjects(t *testing.T) {
require.NoError(t, err)
require.Len(t, projects, 1)
})
t.Run("ListWorkspaceOwnerCount", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t)
user := coderdtest.CreateInitialUser(t, client)
coderdtest.NewProvisionerDaemon(t, client)
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
coderdtest.AwaitProjectImportJob(t, client, user.Organization, job.ID)
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
_ = coderdtest.CreateWorkspace(t, client, "", project.ID)
_ = coderdtest.CreateWorkspace(t, client, "", project.ID)
projects, err := client.Projects(context.Background(), "")
require.NoError(t, err)
require.Len(t, projects, 1)
require.Equal(t, projects[0].WorkspaceOwnerCount, uint32(1))
})
}
func TestProjectsByOrganization(t *testing.T) {