Skip to content

Commit d7451d0

Browse files
committed
update build url to @username/workspace/builds/buildnumber
1 parent 953e8c8 commit d7451d0

File tree

16 files changed

+200
-49
lines changed

16 files changed

+200
-49
lines changed

coderd/coderd.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,10 @@ func New(options *Options) *API {
270270
r.Get("/", api.organizationsByUser)
271271
r.Get("/{organizationname}", api.organizationByUserAndName)
272272
})
273-
r.Get("/workspace/{workspacename}", api.workspaceByOwnerAndName)
273+
r.Route("/workspace/{workspacename}", func(r chi.Router) {
274+
r.Get("/", api.workspaceByOwnerAndName)
275+
r.Get("/builds/{buildnumber}", api.workspaceBuildByBuildNumber)
276+
})
274277
r.Get("/gitsshkey", api.gitSSHKey)
275278
r.Put("/gitsshkey", api.regenerateGitSSHKey)
276279
})

coderd/coderd_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"io"
66
"net/http"
7+
"strconv"
78
"strings"
89
"testing"
910
"time"
@@ -163,6 +164,10 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
163164
AssertObject: rbac.ResourceWorkspace,
164165
AssertAction: rbac.ActionRead,
165166
},
167+
"GET:/api/v2/users/me/workspace/{workspacename}/builds/{buildnumber}": {
168+
AssertObject: rbac.ResourceWorkspace,
169+
AssertAction: rbac.ActionRead,
170+
},
166171
"GET:/api/v2/workspaces/{workspace}/builds/{workspacebuildname}": {
167172
AssertAction: rbac.ActionRead,
168173
AssertObject: workspaceRBACObj,
@@ -388,6 +393,7 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
388393
route = strings.ReplaceAll(route, "{workspacename}", workspace.Name)
389394
route = strings.ReplaceAll(route, "{workspacebuildname}", workspace.LatestBuild.Name)
390395
route = strings.ReplaceAll(route, "{workspaceagent}", workspaceResources[0].Agents[0].ID.String())
396+
route = strings.ReplaceAll(route, "{buildnumber}", strconv.FormatInt(int64(workspace.LatestBuild.BuildNumber), 10))
391397
route = strings.ReplaceAll(route, "{template}", template.ID.String())
392398
route = strings.ReplaceAll(route, "{hash}", file.Hash)
393399
route = strings.ReplaceAll(route, "{workspaceresource}", workspaceResources[0].ID.String())

coderd/database/databasefake/databasefake.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,22 @@ func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndName(_ context.Context, a
616616
return database.WorkspaceBuild{}, sql.ErrNoRows
617617
}
618618

619+
func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams) (database.WorkspaceBuild, error) {
620+
q.mutex.RLock()
621+
defer q.mutex.RUnlock()
622+
623+
for _, workspaceBuild := range q.workspaceBuilds {
624+
if workspaceBuild.WorkspaceID.String() != arg.WorkspaceID.String() {
625+
continue
626+
}
627+
if workspaceBuild.BuildNumber != arg.BuildNumber {
628+
continue
629+
}
630+
return workspaceBuild, nil
631+
}
632+
return database.WorkspaceBuild{}, sql.ErrNoRows
633+
}
634+
619635
func (q *fakeQuerier) GetWorkspacesByOrganizationIDs(_ context.Context, req database.GetWorkspacesByOrganizationIDsParams) ([]database.Workspace, error) {
620636
q.mutex.RLock()
621637
defer q.mutex.RUnlock()

coderd/database/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/workspacebuilds.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ WHERE
2727
workspace_id = $1
2828
AND "name" = $2;
2929

30+
-- name: GetWorkspaceBuildByWorkspaceIDAndBuildNumber :one
31+
SELECT
32+
*
33+
FROM
34+
workspace_builds
35+
WHERE
36+
workspace_id = $1
37+
AND build_number = $2;
38+
3039
-- name: GetWorkspaceBuildByWorkspaceID :many
3140
SELECT
3241
*

coderd/workspacebuilds.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
"fmt"
88
"net/http"
9+
"strconv"
910

1011
"github.com/go-chi/chi/v5"
1112
"github.com/google/uuid"
@@ -160,6 +161,70 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
160161
httpapi.Write(rw, http.StatusOK, apiBuilds)
161162
}
162163

164+
func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Request) {
165+
owner := httpmw.UserParam(r)
166+
workspaceName := chi.URLParam(r, "workspacename")
167+
buildNumber, err := strconv.ParseInt(chi.URLParam(r, "buildnumber"), 10, 32)
168+
if err != nil {
169+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
170+
Message: "Internal error parsing build number as integer.",
171+
Detail: err.Error(),
172+
})
173+
return
174+
}
175+
176+
workspace, err := api.Database.GetWorkspaceByOwnerIDAndName(r.Context(), database.GetWorkspaceByOwnerIDAndNameParams{
177+
OwnerID: owner.ID,
178+
Name: workspaceName,
179+
})
180+
181+
if err != nil {
182+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
183+
Message: "Internal error fetching workspace by name.",
184+
Detail: err.Error(),
185+
})
186+
return
187+
}
188+
if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceWorkspace.
189+
InOrg(workspace.OrganizationID).WithOwner(workspace.OwnerID.String()).WithID(workspace.ID.String())) {
190+
return
191+
}
192+
193+
workspaceBuild, err := api.Database.GetWorkspaceBuildByWorkspaceIDAndBuildNumber(r.Context(), database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams{
194+
WorkspaceID: workspace.ID,
195+
BuildNumber: int32(buildNumber),
196+
})
197+
if err != nil {
198+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
199+
Message: "Internal error fetching workspace build.",
200+
Detail: err.Error(),
201+
})
202+
return
203+
}
204+
205+
job, err := api.Database.GetProvisionerJobByID(r.Context(), workspaceBuild.JobID)
206+
if err != nil {
207+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
208+
Message: "Internal error fetching provisioner job.",
209+
Detail: err.Error(),
210+
})
211+
return
212+
}
213+
214+
users, err := api.Database.GetUsersByIDs(r.Context(), []uuid.UUID{workspace.OwnerID, workspaceBuild.InitiatorID})
215+
if err != nil {
216+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
217+
Message: "Internal error fetching user.",
218+
Detail: err.Error(),
219+
})
220+
return
221+
}
222+
223+
httpapi.Write(rw, http.StatusOK,
224+
convertWorkspaceBuild(findUser(workspace.OwnerID, users), findUser(workspaceBuild.InitiatorID, users),
225+
workspace, workspaceBuild, job))
226+
}
227+
163228
func (api *API) workspaceBuildByName(rw http.ResponseWriter, r *http.Request) {
164229
workspace := httpmw.WorkspaceParam(r)
165230
if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceWorkspace.

site/src/AppRouter.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,6 @@ export const AppRouter: FC = () => (
113113
<Route path="ssh-keys" element={<SSHKeysPage />} />
114114
</Route>
115115

116-
<Route
117-
path="builds/:buildId"
118-
element={
119-
<AuthAndFrame>
120-
<WorkspaceBuildPage />
121-
</AuthAndFrame>
122-
}
123-
/>
124-
125116
<Route path="/@:username">
126117
<Route path=":workspace">
127118
<Route
@@ -160,6 +151,15 @@ export const AppRouter: FC = () => (
160151
}
161152
/>
162153
</Route>
154+
155+
<Route
156+
path="builds/:buildNumber"
157+
element={
158+
<AuthAndFrame>
159+
<WorkspaceBuildPage />
160+
</AuthAndFrame>
161+
}
162+
/>
163163
</Route>
164164
</Route>
165165

site/src/api/api.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,14 @@ export const getWorkspaceBuilds = async (workspaceId: string): Promise<TypesGen.
268268
return response.data
269269
}
270270

271-
export const getWorkspaceBuild = async (workspaceId: string): Promise<TypesGen.WorkspaceBuild> => {
272-
const response = await axios.get<TypesGen.WorkspaceBuild>(`/api/v2/workspacebuilds/${workspaceId}`)
271+
export const getWorkspaceBuildByNumber = async (
272+
username = "me",
273+
workspaceName: string,
274+
buildNumber: string,
275+
): Promise<TypesGen.WorkspaceBuild> => {
276+
const response = await axios.get<TypesGen.WorkspaceBuild>(
277+
`/api/v2/users/${username}/workspace/${workspaceName}/builds/${buildNumber}`,
278+
)
273279
return response.data
274280
}
275281

site/src/components/BuildsTable/BuildsTable.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ export const Language = {
2626
export interface BuildsTableProps {
2727
builds?: TypesGen.WorkspaceBuild[]
2828
className?: string
29+
username: string
30+
workspaceName: string
2931
}
3032

31-
export const BuildsTable: FC<BuildsTableProps> = ({ builds, className }) => {
33+
export const BuildsTable: FC<BuildsTableProps> = ({ builds, className, username, workspaceName }) => {
3234
const isLoading = !builds
3335
const theme: Theme = useTheme()
3436
const navigate = useNavigate()
@@ -52,7 +54,7 @@ export const BuildsTable: FC<BuildsTableProps> = ({ builds, className }) => {
5254
const status = getDisplayWorkspaceBuildStatus(theme, build)
5355

5456
const navigateToBuildPage = () => {
55-
navigate(`/builds/${build.id}`)
57+
navigate(`/@${username}/${workspaceName}/builds/${build.build_number}`)
5658
}
5759

5860
return (

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy