diff --git a/CHANGELOG.md b/CHANGELOG.md index fff2bd9..6b5a4a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New `server` sub-command flag `--max-page-size` for setting the max page size. +### Fixed + +- The "attempt to download manually" URL in VS Code will now work. + ## [2.1.0](https://github.com/coder/code-marketplace/releases/tag/v2.1.0) - 2023-12-21 ### Added diff --git a/api/api.go b/api/api.go index 0d4bbee..50f07c5 100644 --- a/api/api.go +++ b/api/api.go @@ -120,8 +120,13 @@ func New(options *Options) *API { r.Get("/assets/{publisher}/{extension}/{version}/{type}", api.assetRedirect) // This is the "download manually" URL, which like /assets is hardcoded and - // ignores the VSIX asset URL provided to VS Code in the response. + // ignores the VSIX asset URL provided to VS Code in the response. We provide + // it at /publishers for backwards compatibility since that is where we + // originally had it, but VS Code appends to the service URL which means the + // path VS Code actually uses is /api/publishers. + // https://github.com/microsoft/vscode/blob/c727b5484ebfbeff1e1d29654cae5c17af1c826f/build/lib/extensions.ts#L228 r.Get("/publishers/{publisher}/vsextensions/{extension}/{version}/{type}", api.assetRedirect) + r.Get("/api/publishers/{publisher}/vsextensions/{extension}/{version}/{type}", api.assetRedirect) // This is the URL you get taken to when you click the extension's names, // ratings, etc from the extension details page. diff --git a/api/api_test.go b/api/api_test.go index 62b9144..a144482 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -36,6 +36,7 @@ func TestAPI(t *testing.T) { Request any Response any Status int + Method string }{ { Name: "Root", @@ -216,6 +217,7 @@ func TestAPI(t *testing.T) { Status: http.StatusMovedPermanently, Response: "/files/publisher/extension/version@darwin-x64/foo", }, + // Old vspackage path, for backwards compatibility. { Name: "DownloadNotExist", Path: "/publishers/notexist/vsextensions/extension/version/vspackage", @@ -231,6 +233,24 @@ func TestAPI(t *testing.T) { Status: http.StatusMovedPermanently, Response: "/files/publisher/extension/version/extension.vsix", }, + // The vspackage path currently generated by VS Code. + { + Name: "APIDownloadNotExist", + Path: "/api/publishers/notexist/vsextensions/extension/version/vspackage", + Status: http.StatusNotFound, + Response: &httpapi.ErrorResponse{ + Message: "Extension asset does not exist", + Detail: "Please check the asset path", + }, + Method: http.MethodGet, + }, + { + Name: "APIDownloadOK", + Path: "/api/publishers/publisher/vsextensions/extension/version/vspackage", + Status: http.StatusMovedPermanently, + Response: "/files/publisher/extension/version/extension.vsix", + Method: http.MethodGet, + }, { Name: "Item", Path: "/item", @@ -273,9 +293,19 @@ func TestAPI(t *testing.T) { }, } + // Most /api calls are POSTs, the rest are GETs. + var method = c.Method + if method == "" { + if strings.HasPrefix(c.Path, "/api") { + method = http.MethodPost + } else { + method = http.MethodGet + } + } + var resp *http.Response var err error - if strings.HasPrefix(c.Path, "/api") { + if method == http.MethodPost { var body []byte if str, ok := c.Request.(string); ok { body = []byte(str) @@ -284,8 +314,10 @@ func TestAPI(t *testing.T) { require.NoError(t, err) } resp, err = client.Post(url, "application/json", bytes.NewReader(body)) - } else { + } else if method == http.MethodGet { resp, err = client.Get(url) + } else { + t.Fatal(method + " is not handled in the test yet, please add it now") } require.NoError(t, err) require.Equal(t, c.Status, resp.StatusCode)