Merge pull request #10384 from iamazeem/9798-gh-api-encode-package-name
[gh api] Escape package name (URL encoding) for packages endpoint
This commit is contained in:
commit
ed2c322a73
2 changed files with 103 additions and 0 deletions
|
|
@ -7,6 +7,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
|
@ -264,6 +265,8 @@ func NewCmdApi(f *cmdutil.Factory, runF func(*ApiOptions) error) *cobra.Command
|
|||
return err
|
||||
}
|
||||
|
||||
opts.RequestPath = escapePackageNameInPath(opts.RequestPath)
|
||||
|
||||
if runF != nil {
|
||||
return runF(&opts)
|
||||
}
|
||||
|
|
@ -691,3 +694,37 @@ func previewNamesToMIMETypes(names []string) string {
|
|||
}
|
||||
return strings.Join(types, ", ")
|
||||
}
|
||||
|
||||
// The package name part in the `packages` endpoints may contain slashes and
|
||||
// other characters that need to be URL encoded.
|
||||
//
|
||||
// The `escapePackageNameInPath` function extracts and normalizes package names
|
||||
// in the path. The regex `pathWithPackageNameRE` is being used to extract the
|
||||
// package name with a capture group named `package`.
|
||||
//
|
||||
// See https://docs.github.com/en/rest/packages/packages APIs for more details.
|
||||
//
|
||||
// Here's an example:
|
||||
//
|
||||
// The package name `orders/cache` needs to be URL encoded because it contains
|
||||
// a slash `/`. The `escapePackageNameInPath` function will extract the
|
||||
// `orders/cache` part, perform the URL encoding, and return the normalized API
|
||||
// endpoint with `%2F` replacing the slash `/` in the package name part only.
|
||||
//
|
||||
// - Package name: `orders/cache`
|
||||
// - API endpoint: `/users/USER/packages/container/orders/cache`
|
||||
// - Normalized: `/users/USER/packages/container/orders%2Fcache`
|
||||
|
||||
var pathWithPackageNameRE = regexp.MustCompile(`^\/(?:orgs|user|users)(?:\/.*)?\/packages\/(?:npm|maven|rubygems|docker|nuget|container)\/(?<package>.*?)(?:\/(?:restore|versions)|$)`)
|
||||
|
||||
func escapePackageNameInPath(path string) string {
|
||||
matches := pathWithPackageNameRE.FindStringSubmatch(path)
|
||||
if len(matches) > 0 {
|
||||
i := pathWithPackageNameRE.SubexpIndex("package")
|
||||
packageName := matches[i]
|
||||
if packageName != "" {
|
||||
return strings.Replace(path, packageName, url.QueryEscape(packageName), 1)
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
|
|
|||
|
|
@ -367,6 +367,72 @@ func Test_NewCmdApi(t *testing.T) {
|
|||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "request path with container package name containing slashes",
|
||||
cli: "/user/packages/container/github.com/username/package_name --verbose",
|
||||
wants: ApiOptions{
|
||||
Hostname: "",
|
||||
RequestMethod: "GET",
|
||||
RequestMethodPassed: false,
|
||||
RequestPath: "/user/packages/container/github.com%2Fusername%2Fpackage_name",
|
||||
RequestInputFile: "",
|
||||
RawFields: []string(nil),
|
||||
MagicFields: []string(nil),
|
||||
RequestHeaders: []string(nil),
|
||||
ShowResponseHeaders: false,
|
||||
Paginate: false,
|
||||
Silent: false,
|
||||
CacheTTL: 0,
|
||||
Template: "",
|
||||
FilterOutput: "",
|
||||
Verbose: true,
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "request path with container package name containing slashes and restore",
|
||||
cli: "/user/packages/container/github.com/username/package_name/restore --verbose",
|
||||
wants: ApiOptions{
|
||||
Hostname: "",
|
||||
RequestMethod: "GET",
|
||||
RequestMethodPassed: false,
|
||||
RequestPath: "/user/packages/container/github.com%2Fusername%2Fpackage_name/restore",
|
||||
RequestInputFile: "",
|
||||
RawFields: []string(nil),
|
||||
MagicFields: []string(nil),
|
||||
RequestHeaders: []string(nil),
|
||||
ShowResponseHeaders: false,
|
||||
Paginate: false,
|
||||
Silent: false,
|
||||
CacheTTL: 0,
|
||||
Template: "",
|
||||
FilterOutput: "",
|
||||
Verbose: true,
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "request path with container package name containing slashes and versions",
|
||||
cli: "/user/packages/container/github.com/username/package_name/versions --verbose",
|
||||
wants: ApiOptions{
|
||||
Hostname: "",
|
||||
RequestMethod: "GET",
|
||||
RequestMethodPassed: false,
|
||||
RequestPath: "/user/packages/container/github.com%2Fusername%2Fpackage_name/versions",
|
||||
RequestInputFile: "",
|
||||
RawFields: []string(nil),
|
||||
MagicFields: []string(nil),
|
||||
RequestHeaders: []string(nil),
|
||||
ShowResponseHeaders: false,
|
||||
Paginate: false,
|
||||
Silent: false,
|
||||
CacheTTL: 0,
|
||||
Template: "",
|
||||
FilterOutput: "",
|
||||
Verbose: true,
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue