Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
github
hub
提交
349df6f7
H
hub
项目概览
github
/
hub
9 个月 前同步成功
通知
3
Star
22523
Fork
2406
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
hub
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
349df6f7
编写于
2月 07, 2019
作者:
M
Mislav Marohnić
提交者:
GitHub
2月 07, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #2031 from github/api-raw-body
Allow raw request body via `hub api --input <FILE>`
上级
f2b3fd88
9ef7b64b
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
103 addition
and
33 deletion
+103
-33
commands/api.go
commands/api.go
+34
-10
features/api.feature
features/api.feature
+34
-0
github/client.go
github/client.go
+34
-22
utils/args_parser.go
utils/args_parser.go
+1
-1
未找到文件。
commands/api.go
浏览文件 @
349df6f7
...
...
@@ -16,20 +16,21 @@ import (
var
cmdApi
=
&
Command
{
Run
:
apiCommand
,
Usage
:
"api [-
t] [-X <METHOD>] [--cache <TTL>] <ENDPOINT> [-F <KEY-VALU
E>]"
,
Usage
:
"api [-
it] [-X <METHOD>] [-H <HEADER>] [--cache <TTL>] <ENDPOINT> [-F <FIELD>|--input <FIL
E>]"
,
Long
:
`Low-level GitHub API request interface.
## Options:
-X, --method <METHOD>
The HTTP method to use for the request (default: "GET"). The method is
automatically set to "POST" if '--field' or '--raw-field' are used.
automatically set to "POST" if '--field', '--raw-field', or '--input' are
used.
Use '-XGET' to force serializing fields into the query string for the GET
request instead of JSON body of the POST request.
-F, --field <KEY
-
VALUE>
Send data in 'KEY=VALUE' format. The <VALUE> part has some magic handling;
see '--raw-field' for passing arbitrary string
s.
-F, --field <KEY
>=<
VALUE>
Data to serialize with the request. <VALUE> has some magic handling; use
'--raw-field' for sending arbitrary string value
s.
If <VALUE> starts with "@", the rest of the value is interpreted as a
filename to read the value from. Use "@-" to read from standard input.
...
...
@@ -37,18 +38,26 @@ var cmdApi = &Command{
If <VALUE> is "true", "false", "null", or looks like a number, an
appropriate JSON type is used instead of a string.
It is not possible to serialize <VALUE> as a nested JSON array or hash.
Instead, construct the request payload externally and pass it via
'--input'.
Unless '-XGET' was used, all fields are sent serialized as JSON within the
request body. When <ENDPOINT> is "graphql", all fields other than "query"
are grouped under "variables". See
<https://graphql.org/learn/queries/#variables>
-f, --raw-field <KEY
-
VALUE>
-f, --raw-field <KEY
>=<
VALUE>
Same as '--field', except that it allows values starting with "@", literal
strings "true", "false", and "null", as well as strings that look like
numbers.
-H, --header <KEY-VALUE>
An HTTP request header in 'KEY: VALUE' format.
--input <FILE>
The filename to read the raw request body from. Use "-" to read from standard
input. Use this when you want to manually construct the request payload.
-H, --header <KEY>:<VALUE>
Set an HTTP request header.
-i, --include
Include HTTP response headers in the output.
...
...
@@ -107,7 +116,7 @@ func apiCommand(cmd *Command, args *Args) {
method
:=
"GET"
if
args
.
Flag
.
HasReceived
(
"--method"
)
{
method
=
args
.
Flag
.
Value
(
"--method"
)
}
else
if
args
.
Flag
.
HasReceived
(
"--field"
)
||
args
.
Flag
.
HasReceived
(
"--raw-field"
)
{
}
else
if
args
.
Flag
.
HasReceived
(
"--field"
)
||
args
.
Flag
.
HasReceived
(
"--raw-field"
)
||
args
.
Flag
.
HasReceived
(
"--input"
)
{
method
=
"POST"
}
cacheTTL
:=
args
.
Flag
.
Int
(
"--cache"
)
...
...
@@ -174,8 +183,23 @@ func apiCommand(cmd *Command, args *Args) {
path
=
strings
.
Replace
(
path
,
"{repo}"
,
repo
,
1
)
}
var
body
interface
{}
if
args
.
Flag
.
HasReceived
(
"--input"
)
{
fn
:=
args
.
Flag
.
Value
(
"--input"
)
if
fn
==
"-"
{
body
=
os
.
Stdin
}
else
{
fi
,
err
:=
os
.
Open
(
fn
)
utils
.
Check
(
err
)
body
=
fi
defer
fi
.
Close
()
}
}
else
{
body
=
params
}
gh
:=
github
.
NewClient
(
host
)
response
,
err
:=
gh
.
GenericAPIRequest
(
method
,
path
,
params
,
headers
,
cacheTTL
)
response
,
err
:=
gh
.
GenericAPIRequest
(
method
,
path
,
body
,
headers
,
cacheTTL
)
utils
.
Check
(
err
)
defer
response
.
Body
.
Close
()
...
...
features/api.feature
浏览文件 @
349df6f7
...
...
@@ -193,6 +193,40 @@ Feature: hub api
.query query {\n repository\n}\n\n
"""
Scenario
:
POST body from file
Given the GitHub API server
:
"""
post('/create') {
params[:obj].inspect
}
"""
Given a file named "payload.json" with
:
"""
{"obj": ["one", 2, null]}
"""
When
I successfully run `hub api create --input payload.json`
Then the output should contain exactly
:
"""
["one", 2, nil]
"""
Scenario
:
POST body from stdin
Given the GitHub API server
:
"""
post('/create') {
params[:obj].inspect
}
"""
When
I run `hub api create --input -` interactively
And I pass in
:
"""
{"obj": {"name": "Ein", "datadog": true}}
"""
Then the output should contain exactly
:
"""
{"name"=>"Ein", "datadog"=>true}
"""
Scenario
:
Pass extra GraphQL variables
Given the GitHub API server
:
"""
...
...
github/client.go
浏览文件 @
349df6f7
...
...
@@ -812,7 +812,7 @@ func (client *Client) FetchMilestones(project *Project) (milestones []Milestone,
return
}
func
(
client
*
Client
)
GenericAPIRequest
(
method
,
path
string
,
params
map
[
string
]
interface
{},
headers
map
[
string
]
string
,
ttl
int
)
(
*
simpleResponse
,
error
)
{
func
(
client
*
Client
)
GenericAPIRequest
(
method
,
path
string
,
data
interface
{},
headers
map
[
string
]
string
,
ttl
int
)
(
*
simpleResponse
,
error
)
{
api
,
err
:=
client
.
simpleApi
()
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -820,33 +820,19 @@ func (client *Client) GenericAPIRequest(method, path string, params map[string]i
api
.
CacheTTL
=
ttl
var
body
io
.
Reader
if
len
(
params
)
>
0
{
switch
d
:=
data
.
(
type
)
{
case
map
[
string
]
interface
{}
:
if
method
==
"GET"
{
query
:=
url
.
Values
{}
for
key
,
value
:=
range
params
{
switch
v
:=
value
.
(
type
)
{
case
string
:
query
.
Add
(
key
,
v
)
case
nil
:
query
.
Add
(
key
,
""
)
case
int
:
query
.
Add
(
key
,
fmt
.
Sprintf
(
"%d"
,
v
))
case
bool
:
query
.
Add
(
key
,
fmt
.
Sprintf
(
"%v"
,
v
))
}
}
sep
:=
"?"
if
strings
.
Contains
(
path
,
sep
)
{
sep
=
"&"
}
path
+=
sep
+
query
.
Encode
()
}
else
{
json
,
err
:=
json
.
Marshal
(
params
)
path
=
addQuery
(
path
,
d
)
}
else
if
len
(
d
)
>
0
{
json
,
err
:=
json
.
Marshal
(
d
)
if
err
!=
nil
{
return
nil
,
err
}
body
=
bytes
.
NewBuffer
(
json
)
}
case
io
.
Reader
:
body
=
d
}
return
api
.
performRequest
(
method
,
path
,
body
,
func
(
req
*
http
.
Request
)
{
...
...
@@ -1111,3 +1097,29 @@ func perPage(limit, max int) int {
}
return
max
}
func
addQuery
(
path
string
,
params
map
[
string
]
interface
{})
string
{
if
len
(
params
)
==
0
{
return
path
}
query
:=
url
.
Values
{}
for
key
,
value
:=
range
params
{
switch
v
:=
value
.
(
type
)
{
case
string
:
query
.
Add
(
key
,
v
)
case
nil
:
query
.
Add
(
key
,
""
)
case
int
:
query
.
Add
(
key
,
fmt
.
Sprintf
(
"%d"
,
v
))
case
bool
:
query
.
Add
(
key
,
fmt
.
Sprintf
(
"%v"
,
v
))
}
}
sep
:=
"?"
if
strings
.
Contains
(
path
,
sep
)
{
sep
=
"&"
}
return
path
+
sep
+
query
.
Encode
()
}
utils/args_parser.go
浏览文件 @
349df6f7
...
...
@@ -192,7 +192,7 @@ func NewArgsParser() *ArgsParser {
func
NewArgsParserWithUsage
(
usage
string
)
*
ArgsParser
{
p
:=
NewArgsParser
()
f
:=
`(-[a-zA-Z0-9@^]|--[a-z][a-z0-9-]+)(?:[ =]
<?([a-zA-Z_-]+)>?
)?`
f
:=
`(-[a-zA-Z0-9@^]|--[a-z][a-z0-9-]+)(?:[ =]
([a-zA-Z_<>:=-]+)
)?`
re
:=
regexp
.
MustCompile
(
fmt
.
Sprintf
(
`(?m)^\s*%s(?:,\s*%s)?$`
,
f
,
f
))
for
_
,
match
:=
range
re
.
FindAllStringSubmatch
(
usage
,
-
1
)
{
n1
:=
match
[
1
]
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录