mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Update dependencies
This commit is contained in:
parent
8f3ae94b4e
commit
3a0bcd21e7
77
Gopkg.lock
generated
77
Gopkg.lock
generated
@ -6,16 +6,16 @@
|
|||||||
name = "cloud.google.com/go"
|
name = "cloud.google.com/go"
|
||||||
packages = ["compute/metadata"]
|
packages = ["compute/metadata"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "64a2037ec6be8a4b0c1d1f706ed35b428b989239"
|
revision = "dfffe386c33fb24c34ee501e5723df5b97b98514"
|
||||||
version = "v0.26.0"
|
version = "v0.30.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:1164f5eccc8905c03a2c688141c81f06522ed5fd2eb65cb43debeb730a018276"
|
digest = "1:636ac9f696c988f0038afd43592f7a0fff29038588ab1064ba8ba3476bb41091"
|
||||||
name = "github.com/adlio/trello"
|
name = "github.com/adlio/trello"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "8a458717123e328d9103a3bf075e64bc1ec961f8"
|
revision = "e4cc07c871d0ee17c5579131fc1c786efbb5fe2a"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:9253f97cfbbe049b631877c80badecc69620711b3e335f6cf97a7809681da388"
|
digest = "1:9253f97cfbbe049b631877c80badecc69620711b3e335f6cf97a7809681da388"
|
||||||
@ -59,11 +59,11 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:b5d1ba5dc01e8129b7df5cf95380a66b0e0f122850189b7ec255953b15522f16"
|
digest = "1:579829cc9bf515e2f9e39f91df03b9333c311402bac5a4935dc8ef81e3a57160"
|
||||||
name = "github.com/andygrunwald/go-gerrit"
|
name = "github.com/andygrunwald/go-gerrit"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "197fe0d2e796b3d985b9cd91be8afd4415692f39"
|
revision = "30ce279197661497040ec81c4b64539562eb2d4b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -117,12 +117,12 @@
|
|||||||
version = "v1.1.6"
|
version = "v1.1.6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
digest = "1:6f9339c912bbdda81302633ad7e99a28dfa5a639c864061f1929510a9a64aa74"
|
digest = "1:6f9339c912bbdda81302633ad7e99a28dfa5a639c864061f1929510a9a64aa74"
|
||||||
name = "github.com/dustin/go-humanize"
|
name = "github.com/dustin/go-humanize"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "9f541cc9db5d55bce703bd99987c9d5cb8eea45e"
|
revision = "9f541cc9db5d55bce703bd99987c9d5cb8eea45e"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -134,14 +134,14 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:00b9cce210566117aff926677c005aeaea6c85374e67bdcb72783af237c48f97"
|
digest = "1:490cf9d7deec1b0dcac6cc8b17f307c48c4821bc2140d46e48175a83acbfe40d"
|
||||||
name = "github.com/gdamore/tcell"
|
name = "github.com/gdamore/tcell"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"terminfo",
|
"terminfo",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "de7e78efa4a71b3f36c7154989c529dbdf9ae623"
|
revision = "493f3b46b3c20880afc8e04ceeb1c6d5aa3363d7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:57fa4c058c21ce25d0b7272518dd746065117abf6cc706158b0d361202024520"
|
digest = "1:57fa4c058c21ce25d0b7272518dd746065117abf6cc706158b0d361202024520"
|
||||||
@ -152,28 +152,28 @@
|
|||||||
version = "v4.1.0"
|
version = "v4.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861"
|
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d"
|
||||||
name = "github.com/golang/protobuf"
|
name = "github.com/golang/protobuf"
|
||||||
packages = ["proto"]
|
packages = ["proto"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||||
version = "v1.1.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:4be3c01ef56542da4f1268c52a8b88bae5309ec3dade7755e250bc933e13ac70"
|
digest = "1:8c90219e8a1f5f7cad019b77697aaae2b236db5a1a46ae688e5ede406e109182"
|
||||||
name = "github.com/google/go-github"
|
name = "github.com/google/go-github"
|
||||||
packages = ["github"]
|
packages = ["github"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "d7732128a00e8e95e8fe896017da18ee20b2180d"
|
revision = "68a79fc6a32bab9406083545e667a65ba67b0a3e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
digest = "1:a63cff6b5d8b95638bfe300385d93b2a6d9d687734b863da8e09dc834510a690"
|
digest = "1:a63cff6b5d8b95638bfe300385d93b2a6d9d687734b863da8e09dc834510a690"
|
||||||
name = "github.com/google/go-querystring"
|
name = "github.com/google/go-querystring"
|
||||||
packages = ["query"]
|
packages = ["query"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
|
revision = "44c6ddd0a2342c386950e880b658017258da92fc"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:a2cff208d4759f6ba1b1cd228587b0a1869f95f22542ec9cd17fff64430113c7"
|
digest = "1:a2cff208d4759f6ba1b1cd228587b0a1869f95f22542ec9cd17fff64430113c7"
|
||||||
@ -201,11 +201,11 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:3a16300d913e1050d4a7ff296106a11b72da05c5dd3475f2ae1feb0830866461"
|
digest = "1:2277d06c9dcd34d70119b624115f3d74672647322349bb76a8adedbc623a3955"
|
||||||
name = "github.com/olebedev/config"
|
name = "github.com/olebedev/config"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "ed90d2035b8114c30b9cb65e7d52e10a7148f8c6"
|
revision = "57f804269e64d41bfe46efb76232c47f49d40902"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
|
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
|
||||||
@ -241,19 +241,19 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:9deb696e9739b45e91369ffb3876d4e0d2bc45e0d35062fb3c5aa44fa77eff6c"
|
digest = "1:00d9f4017b55d590139b77fbd851aef56f179479fc40a4afdedaf187e828f99d"
|
||||||
name = "github.com/rivo/tview"
|
name = "github.com/rivo/tview"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "21f50f5bc400083b4eb23304887d9cd0fc00d075"
|
revision = "a7c1880d62d37422830f0a15823b51301ca9f354"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:de0cf35afb9cad7b20ff8871ae3b64cecc7116bffb583bc7b3c1bb5c37473149"
|
digest = "1:93ff598337cb35c40079a1ba766729c20eb1756e37f5740eac4c8e943f59664d"
|
||||||
name = "github.com/sticreations/spotigopher"
|
name = "github.com/sticreations/spotigopher"
|
||||||
packages = ["spotigopher"]
|
packages = ["spotigopher"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "995ee350dc1c54259597de65dde7a9e56a4b73af"
|
revision = "98632f6f94b087f2582be76980f76bc070d37176"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83"
|
digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83"
|
||||||
@ -265,11 +265,11 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:ca067f3d378064d50a239b1f0d4dcd2dab6356f7643993bdf02c91d6e621c028"
|
digest = "1:afc7e1c726a88e6cd5689cca19fbc86128dffe86fd37e3e0841767f3a951182e"
|
||||||
name = "github.com/xanzy/go-gitlab"
|
name = "github.com/xanzy/go-gitlab"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "f3bc634ab936f7e4ee5e21334ccfdfeb5601d477"
|
revision = "1444249c1b2a8e4cdb5a76dc9c8d02d1133180be"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -281,11 +281,19 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:f6f2814b88ad3dd5ca45e1e9a7a0caba1ddb1bfaf1c4173ebd991d854e1669eb"
|
digest = "1:1ff6915a45fb06d272e614e72219aa058aefc545f597a708eb0cc6cb778c344a"
|
||||||
|
name = "github.com/zmb3/spotify"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "a4bd83f60e06ab58f3516c61680d0532aabf470e"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:02a2f8f0718f239866000d2d1bca016d14f0f6de37615c315f34da17dc630259"
|
||||||
name = "github.com/zorkian/go-datadog-api"
|
name = "github.com/zorkian/go-datadog-api"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "d7b8b10db6a7eb1c1c2424b10a795a1662e80c9a"
|
revision = "dc324c09cf05eef3e3a82bde06ae0c4dd349a767"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -296,11 +304,11 @@
|
|||||||
"context/ctxhttp",
|
"context/ctxhttp",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "aaf60122140d3fcf75376d319f0554393160eb50"
|
revision = "04a2e542c03f1d053ab3e4d6e5abcd4b66e2be8e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:bea0314c10bd362ab623af4880d853b5bad3b63d0ab9945c47e461b8d04203ed"
|
digest = "1:faa25cb78cf9c8cec9345d4ed07322cdef6a8c968b3d0a6b6c3609067c7386eb"
|
||||||
name = "golang.org/x/oauth2"
|
name = "golang.org/x/oauth2"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@ -310,7 +318,7 @@
|
|||||||
"jwt",
|
"jwt",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "3d292e4d0cdc3a0113e6d207bb137145ef1de42f"
|
revision = "9dcd33a902f40452422c2367fefcb95b54f9f8f8"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:37672ad5821719e2df8509c2edd4ba5ae192463237c73c3a2d24ef8b2bc9e36f"
|
digest = "1:37672ad5821719e2df8509c2edd4ba5ae192463237c73c3a2d24ef8b2bc9e36f"
|
||||||
@ -328,7 +336,7 @@
|
|||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:c8d95fbc783cab4e8986b1bf3dbe5312db7521e4342ac755280cfa78ce0ee792"
|
digest = "1:a1d58b7c9eeceeac201a6f6b10092cd2a5985791a45843c838151ee3f751d3c3"
|
||||||
name = "google.golang.org/api"
|
name = "google.golang.org/api"
|
||||||
packages = [
|
packages = [
|
||||||
"calendar/v3",
|
"calendar/v3",
|
||||||
@ -338,10 +346,10 @@
|
|||||||
"sheets/v4",
|
"sheets/v4",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "e21acd801f91da814261b938941d193bb036441a"
|
revision = "a2651947f503a1793446d4058bb073a6fdf99e53"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:c8907869850adaa8bd7631887948d0684f3787d0912f1c01ab72581a6c34432e"
|
digest = "1:193950893ea275f89ed92e5da11ed8fa1436872f755a9ea5d4afa83dc9d9c3a8"
|
||||||
name = "google.golang.org/appengine"
|
name = "google.golang.org/appengine"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@ -356,8 +364,8 @@
|
|||||||
"urlfetch",
|
"urlfetch",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
|
revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06"
|
||||||
version = "v1.1.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
|
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
|
||||||
@ -390,6 +398,7 @@
|
|||||||
"github.com/stretchr/testify/assert",
|
"github.com/stretchr/testify/assert",
|
||||||
"github.com/xanzy/go-gitlab",
|
"github.com/xanzy/go-gitlab",
|
||||||
"github.com/yfronto/newrelic",
|
"github.com/yfronto/newrelic",
|
||||||
|
"github.com/zmb3/spotify",
|
||||||
"github.com/zorkian/go-datadog-api",
|
"github.com/zorkian/go-datadog-api",
|
||||||
"golang.org/x/oauth2",
|
"golang.org/x/oauth2",
|
||||||
"golang.org/x/oauth2/google",
|
"golang.org/x/oauth2/google",
|
||||||
|
27
vendor/github.com/adlio/trello/action.go
generated
vendored
27
vendor/github.com/adlio/trello/action.go
generated
vendored
@ -21,20 +21,29 @@ type Action struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ActionData struct {
|
type ActionData struct {
|
||||||
Text string `json:"text,omitempty"`
|
Text string `json:"text,omitempty"`
|
||||||
List *List `json:"list,omitempty"`
|
List *List `json:"list,omitempty"`
|
||||||
Card *Card `json:"card,omitempty"`
|
Card *ActionDataCard `json:"card,omitempty"`
|
||||||
CardSource *Card `json:"cardSource,omitempty"`
|
CardSource *ActionDataCard `json:"cardSource,omitempty"`
|
||||||
Board *Board `json:"board,omitempty"`
|
Board *Board `json:"board,omitempty"`
|
||||||
Old *Card `json:"old,omitempty"`
|
Old *ActionDataCard `json:"old,omitempty"`
|
||||||
ListBefore *List `json:"listBefore,omitempty"`
|
ListBefore *List `json:"listBefore,omitempty"`
|
||||||
ListAfter *List `json:"listAfter,omitempty"`
|
ListAfter *List `json:"listAfter,omitempty"`
|
||||||
DateLastEdited time.Time `json:"dateLastEdited"`
|
DateLastEdited time.Time `json:"dateLastEdited"`
|
||||||
|
|
||||||
CheckItem *CheckItem `json:"checkItem"`
|
CheckItem *CheckItem `json:"checkItem"`
|
||||||
Checklist *Checklist `json:"checklist"`
|
Checklist *Checklist `json:"checklist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ActionDataCard struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
IDShort int `json:"idShort"`
|
||||||
|
ShortLink string `json:"shortLink"`
|
||||||
|
Pos float64 `json:"pos"`
|
||||||
|
Closed bool `json:"closed"`
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Board) GetActions(args Arguments) (actions ActionCollection, err error) {
|
func (b *Board) GetActions(args Arguments) (actions ActionCollection, err error) {
|
||||||
path := fmt.Sprintf("boards/%s/actions", b.ID)
|
path := fmt.Sprintf("boards/%s/actions", b.ID)
|
||||||
err = b.client.Get(path, args, &actions)
|
err = b.client.Get(path, args, &actions)
|
||||||
|
5
vendor/github.com/adlio/trello/board.go
generated
vendored
5
vendor/github.com/adlio/trello/board.go
generated
vendored
@ -52,8 +52,9 @@ type Board struct {
|
|||||||
Sky string `json:"sky,omitempty"`
|
Sky string `json:"sky,omitempty"`
|
||||||
Yellow string `json:"yellow,omitempty"`
|
Yellow string `json:"yellow,omitempty"`
|
||||||
} `json:"labelNames"`
|
} `json:"labelNames"`
|
||||||
Lists []*List `json:"lists"`
|
Lists []*List `json:"lists"`
|
||||||
Actions []*Action `json:"actions"`
|
Actions []*Action `json:"actions"`
|
||||||
|
Organization Organization `json:"organization"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BackgroundImage struct {
|
type BackgroundImage struct {
|
||||||
|
63
vendor/github.com/adlio/trello/card.go
generated
vendored
63
vendor/github.com/adlio/trello/card.go
generated
vendored
@ -76,6 +76,11 @@ type Card struct {
|
|||||||
// Labels
|
// Labels
|
||||||
IDLabels []string `json:"idLabels,omitempty"`
|
IDLabels []string `json:"idLabels,omitempty"`
|
||||||
Labels []*Label `json:"labels,omitempty"`
|
Labels []*Label `json:"labels,omitempty"`
|
||||||
|
|
||||||
|
// Custom Fields
|
||||||
|
CustomFieldItems []*CustomFieldItem `json:"customFieldItems",omitempty`
|
||||||
|
|
||||||
|
customFieldMap *map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Card) CreatedAt() time.Time {
|
func (c *Card) CreatedAt() time.Time {
|
||||||
@ -83,6 +88,52 @@ func (c *Card) CreatedAt() time.Time {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Card) CustomFields(boardCustomFields []*CustomField) (map[string]interface{}) {
|
||||||
|
|
||||||
|
cfm := c.customFieldMap
|
||||||
|
|
||||||
|
if cfm == nil {
|
||||||
|
cfm = &(map[string]interface{} {})
|
||||||
|
|
||||||
|
// bcfOptionNames[CustomField ID] = Custom Field Name
|
||||||
|
bcfOptionNames := map[string]string{}
|
||||||
|
|
||||||
|
// bcfOptionsMap[CustomField ID][ID of the option] = Value of the option
|
||||||
|
bcfOptionsMap := map[string] map[string]interface{}{}
|
||||||
|
|
||||||
|
for _, bcf := range boardCustomFields {
|
||||||
|
bcfOptionNames[bcf.ID] = bcf.Name
|
||||||
|
for _, cf := range bcf.Options {
|
||||||
|
// create 2nd level map when not available yet
|
||||||
|
map2, ok := bcfOptionsMap[cf.IDCustomField]
|
||||||
|
if !ok {
|
||||||
|
map2 = map[string]interface{}{}
|
||||||
|
bcfOptionsMap[bcf.ID] = map2
|
||||||
|
}
|
||||||
|
|
||||||
|
bcfOptionsMap[bcf.ID][cf.ID] = cf.Value.Text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cf := range c.CustomFieldItems {
|
||||||
|
name := bcfOptionNames[cf.IDCustomField]
|
||||||
|
|
||||||
|
// create 2nd level map when not available yet
|
||||||
|
map2, ok := bcfOptionsMap[cf.IDCustomField]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
value, ok := map2[cf.IDValue]
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
(*cfm)[name] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.customFieldMap = cfm
|
||||||
|
}
|
||||||
|
return *cfm
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Card) MoveToList(listID string, args Arguments) error {
|
func (c *Card) MoveToList(listID string, args Arguments) error {
|
||||||
path := fmt.Sprintf("cards/%s", c.ID)
|
path := fmt.Sprintf("cards/%s", c.ID)
|
||||||
args["idList"] = listID
|
args["idList"] = listID
|
||||||
@ -105,6 +156,18 @@ func (c *Card) AddMemberID(memberID string) (member []*Member, err error) {
|
|||||||
return member, err
|
return member, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Card) RemoveIDLabel(labelID string, label *Label) error {
|
||||||
|
path := fmt.Sprintf("cards/%s/idLabels/%s", c.ID, labelID)
|
||||||
|
return c.client.Delete(path, Defaults(), label)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Card) AddIDLabel(labelID string) error {
|
||||||
|
path := fmt.Sprintf("cards/%s/idLabels", c.ID)
|
||||||
|
err := c.client.Post(path, Arguments{"value": labelID}, &c.IDLabels)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Card) MoveToTopOfList() error {
|
func (c *Card) MoveToTopOfList() error {
|
||||||
path := fmt.Sprintf("cards/%s", c.ID)
|
path := fmt.Sprintf("cards/%s", c.ID)
|
||||||
return c.client.Put(path, Arguments{"pos": "top"}, c)
|
return c.client.Put(path, Arguments{"pos": "top"}, c)
|
||||||
|
2
vendor/github.com/adlio/trello/client.go
generated
vendored
2
vendor/github.com/adlio/trello/client.go
generated
vendored
@ -234,6 +234,6 @@ func (c *Client) Delete(path string, args Arguments, target interface{}) error {
|
|||||||
|
|
||||||
func (c *Client) log(format string, args ...interface{}) {
|
func (c *Client) log(format string, args ...interface{}) {
|
||||||
if c.Logger != nil {
|
if c.Logger != nil {
|
||||||
c.Logger.Debugf(format, args)
|
c.Logger.Debugf(format, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
vendor/github.com/adlio/trello/custom-fields.go
generated
vendored
Normal file
49
vendor/github.com/adlio/trello/custom-fields.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package trello
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type CustomFieldItem struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
IDValue string `json:"idValue"`
|
||||||
|
IDCustomField string `json:"idCustomField"`
|
||||||
|
IDModel string `json:"idModel"`
|
||||||
|
IDModelType string `json:"modelType,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CustomField struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
IDModel string `json:"idModel"`
|
||||||
|
IDModelType string `json:"modelType,omitempty"`
|
||||||
|
FieldGroup string `json:"fieldGroup"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Pos int `json:"pos"`
|
||||||
|
Display struct {
|
||||||
|
CardFront bool `json:"cardfront"`
|
||||||
|
} `json:"display"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Options []*CustomFieldOption `json:"options"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CustomFieldOption struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
IDCustomField string `json:"idCustomField"`
|
||||||
|
Value struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
} `json:"value"`
|
||||||
|
Color string `json:"color,omitempty"`
|
||||||
|
Pos int `json:"pos"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetCustomField(fieldID string, args Arguments) (customField *CustomField, err error) {
|
||||||
|
path := fmt.Sprintf("customFields/%s", fieldID)
|
||||||
|
err = c.Get(path, args, &customField)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (b *Board) GetCustomFields(args Arguments) (customFields []*CustomField, err error) {
|
||||||
|
path := fmt.Sprintf("boards/%s/customFields", b.ID)
|
||||||
|
err = b.client.Get(path, args, &customFields)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
1
vendor/github.com/andygrunwald/go-gerrit/.travis.yml
generated
vendored
1
vendor/github.com/andygrunwald/go-gerrit/.travis.yml
generated
vendored
@ -3,6 +3,7 @@ language: go
|
|||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
go:
|
go:
|
||||||
|
- "1.11.x"
|
||||||
- "1.10.x"
|
- "1.10.x"
|
||||||
- "1.9.x"
|
- "1.9.x"
|
||||||
- "1.8.x"
|
- "1.8.x"
|
||||||
|
8
vendor/github.com/andygrunwald/go-gerrit/authentication.go
generated
vendored
8
vendor/github.com/andygrunwald/go-gerrit/authentication.go
generated
vendored
@ -1,7 +1,7 @@
|
|||||||
package gerrit
|
package gerrit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5" // nolint: gas
|
"crypto/md5" // nolint: gosec
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
@ -117,7 +117,7 @@ func (s *AuthenticationService) digestAuthHeader(response *http.Response) (strin
|
|||||||
uriHeader := authenticate["uri"]
|
uriHeader := authenticate["uri"]
|
||||||
|
|
||||||
// A1
|
// A1
|
||||||
h := md5.New() // nolint: gas
|
h := md5.New() // nolint: gosec
|
||||||
A1 := fmt.Sprintf("%s:%s:%s", s.name, realmHeader, s.secret)
|
A1 := fmt.Sprintf("%s:%s:%s", s.name, realmHeader, s.secret)
|
||||||
if _, err := io.WriteString(h, A1); err != nil {
|
if _, err := io.WriteString(h, A1); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -125,7 +125,7 @@ func (s *AuthenticationService) digestAuthHeader(response *http.Response) (strin
|
|||||||
HA1 := fmt.Sprintf("%x", h.Sum(nil))
|
HA1 := fmt.Sprintf("%x", h.Sum(nil))
|
||||||
|
|
||||||
// A2
|
// A2
|
||||||
h = md5.New() // nolint: gas
|
h = md5.New() // nolint: gosec
|
||||||
A2 := fmt.Sprintf("%s:%s", response.Request.Method, uriHeader)
|
A2 := fmt.Sprintf("%s:%s", response.Request.Method, uriHeader)
|
||||||
if _, err := io.WriteString(h, A2); err != nil {
|
if _, err := io.WriteString(h, A2); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -141,7 +141,7 @@ func (s *AuthenticationService) digestAuthHeader(response *http.Response) (strin
|
|||||||
bytes += n
|
bytes += n
|
||||||
}
|
}
|
||||||
cnonce := base64.StdEncoding.EncodeToString(k)
|
cnonce := base64.StdEncoding.EncodeToString(k)
|
||||||
digest := md5.New() // nolint: gas
|
digest := md5.New() // nolint: gosec
|
||||||
if _, err := digest.Write([]byte(strings.Join([]string{HA1, nonceHeader, "00000001", cnonce, qopHeader, HA2}, ":"))); err != nil {
|
if _, err := digest.Write([]byte(strings.Join([]string{HA1, nonceHeader, "00000001", cnonce, qopHeader, HA2}, ":"))); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
28
vendor/github.com/andygrunwald/go-gerrit/changes.go
generated
vendored
28
vendor/github.com/andygrunwald/go-gerrit/changes.go
generated
vendored
@ -258,11 +258,11 @@ type RobotCommentInput struct {
|
|||||||
CommentInput
|
CommentInput
|
||||||
|
|
||||||
// The ID of the robot that generated this comment.
|
// The ID of the robot that generated this comment.
|
||||||
RobotId string `json:"robot_id"`
|
RobotID string `json:"robot_id"`
|
||||||
// An ID of the run of the robot.
|
// An ID of the run of the robot.
|
||||||
RobotRunId string `json:"robot_run_id"`
|
RobotRunID string `json:"robot_run_id"`
|
||||||
// URL to more information.
|
// URL to more information.
|
||||||
Url string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
// Robot specific properties as map that maps arbitrary keys to values.
|
// Robot specific properties as map that maps arbitrary keys to values.
|
||||||
Properties *map[string]*string `json:"properties,omitempty"`
|
Properties *map[string]*string `json:"properties,omitempty"`
|
||||||
// Suggested fixes for this robot comment as a list of FixSuggestionInfo
|
// Suggested fixes for this robot comment as a list of FixSuggestionInfo
|
||||||
@ -277,11 +277,11 @@ type RobotCommentInfo struct {
|
|||||||
CommentInfo
|
CommentInfo
|
||||||
|
|
||||||
// The ID of the robot that generated this comment.
|
// The ID of the robot that generated this comment.
|
||||||
RobotId string `json:"robot_id"`
|
RobotID string `json:"robot_id"`
|
||||||
// An ID of the run of the robot.
|
// An ID of the run of the robot.
|
||||||
RobotRunId string `json:"robot_run_id"`
|
RobotRunID string `json:"robot_run_id"`
|
||||||
// URL to more information.
|
// URL to more information.
|
||||||
Url string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
// Robot specific properties as map that maps arbitrary keys to values.
|
// Robot specific properties as map that maps arbitrary keys to values.
|
||||||
Properties map[string]string `json:"properties,omitempty"`
|
Properties map[string]string `json:"properties,omitempty"`
|
||||||
// Suggested fixes for this robot comment as a list of FixSuggestionInfo
|
// Suggested fixes for this robot comment as a list of FixSuggestionInfo
|
||||||
@ -294,7 +294,7 @@ type RobotCommentInfo struct {
|
|||||||
type FixSuggestionInfo struct {
|
type FixSuggestionInfo struct {
|
||||||
// The UUID of the suggested fix. It will be generated automatically and
|
// The UUID of the suggested fix. It will be generated automatically and
|
||||||
// hence will be ignored if it’s set for input objects.
|
// hence will be ignored if it’s set for input objects.
|
||||||
FixId string `json:"fix_id"`
|
FixID string `json:"fix_id"`
|
||||||
// A description of the suggested fix.
|
// A description of the suggested fix.
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
// A list of FixReplacementInfo entities indicating how the content of one or
|
// A list of FixReplacementInfo entities indicating how the content of one or
|
||||||
@ -780,11 +780,17 @@ func (s *ChangesService) change(tail string, changeID string, input interface{})
|
|||||||
|
|
||||||
v := new(ChangeInfo)
|
v := new(ChangeInfo)
|
||||||
resp, err := s.client.Do(req, v)
|
resp, err := s.client.Do(req, v)
|
||||||
if resp.StatusCode == http.StatusConflict {
|
if err != nil {
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
return nil, resp, err
|
||||||
err = errors.New(string(body[:]))
|
|
||||||
}
|
}
|
||||||
return v, resp, err
|
if resp.StatusCode == http.StatusConflict {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return v, resp, err
|
||||||
|
}
|
||||||
|
return v, resp, errors.New(string(body[:]))
|
||||||
|
}
|
||||||
|
return v, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubmitChange submits a change.
|
// SubmitChange submits a change.
|
||||||
|
1
vendor/github.com/gdamore/tcell/README.md
generated
vendored
1
vendor/github.com/gdamore/tcell/README.md
generated
vendored
@ -25,6 +25,7 @@ ways. It also adds substantial functionality beyond termbox.
|
|||||||
* [tui-go](https://github.com/marcusolsson/tui-go) - UI library for terminal apps
|
* [tui-go](https://github.com/marcusolsson/tui-go) - UI library for terminal apps
|
||||||
* [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot!
|
* [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot!
|
||||||
* [WTF](https://github.com/senorprogrammer/wtf)- Personal information dashboard for your terminal
|
* [WTF](https://github.com/senorprogrammer/wtf)- Personal information dashboard for your terminal
|
||||||
|
* [browsh](https://github.com/browsh-org/browsh) - A fully-modern text-based browser, rendering to TTY and browsers ([video](https://www.youtube.com/watch?v=HZq86XfBoRo))
|
||||||
|
|
||||||
## Pure Go Terminfo Database
|
## Pure Go Terminfo Database
|
||||||
|
|
||||||
|
7
vendor/github.com/gdamore/tcell/cell.go
generated
vendored
7
vendor/github.com/gdamore/tcell/cell.go
generated
vendored
@ -52,6 +52,10 @@ func (cb *CellBuffer) SetContent(x int, y int,
|
|||||||
i := 0
|
i := 0
|
||||||
for i < len(c.currComb) {
|
for i < len(c.currComb) {
|
||||||
r := c.currComb[i]
|
r := c.currComb[i]
|
||||||
|
if r == '\u200d' {
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
if runewidth.RuneWidth(r) != 0 {
|
if runewidth.RuneWidth(r) != 0 {
|
||||||
// not a combining character, yank it
|
// not a combining character, yank it
|
||||||
c.currComb = append(c.currComb[:i-1], c.currComb[i+1:]...)
|
c.currComb = append(c.currComb[:i-1], c.currComb[i+1:]...)
|
||||||
@ -175,12 +179,13 @@ func (cb *CellBuffer) Resize(w, h int) {
|
|||||||
|
|
||||||
// Fill fills the entire cell buffer array with the specified character
|
// Fill fills the entire cell buffer array with the specified character
|
||||||
// and style. Normally choose ' ' to clear the screen. This API doesn't
|
// and style. Normally choose ' ' to clear the screen. This API doesn't
|
||||||
// support combining characters.
|
// support combining characters, or characters with a width larger than one.
|
||||||
func (cb *CellBuffer) Fill(r rune, style Style) {
|
func (cb *CellBuffer) Fill(r rune, style Style) {
|
||||||
for i := range cb.cells {
|
for i := range cb.cells {
|
||||||
c := &cb.cells[i]
|
c := &cb.cells[i]
|
||||||
c.currMain = r
|
c.currMain = r
|
||||||
c.currComb = nil
|
c.currComb = nil
|
||||||
c.currStyle = style
|
c.currStyle = style
|
||||||
|
c.width = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
vendor/github.com/golang/protobuf/LICENSE
generated
vendored
3
vendor/github.com/golang/protobuf/LICENSE
generated
vendored
@ -1,7 +1,4 @@
|
|||||||
Go support for Protocol Buffers - Google's data interchange format
|
|
||||||
|
|
||||||
Copyright 2010 The Go Authors. All rights reserved.
|
Copyright 2010 The Go Authors. All rights reserved.
|
||||||
https://github.com/golang/protobuf
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
18
vendor/github.com/golang/protobuf/proto/encode.go
generated
vendored
18
vendor/github.com/golang/protobuf/proto/encode.go
generated
vendored
@ -37,27 +37,9 @@ package proto
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequiredNotSetError is the error returned if Marshal is called with
|
|
||||||
// a protocol buffer struct whose required fields have not
|
|
||||||
// all been initialized. It is also the error returned if Unmarshal is
|
|
||||||
// called with an encoded protocol buffer that does not include all the
|
|
||||||
// required fields.
|
|
||||||
//
|
|
||||||
// When printed, RequiredNotSetError reports the first unset required field in a
|
|
||||||
// message. If the field cannot be precisely determined, it is reported as
|
|
||||||
// "{Unknown}".
|
|
||||||
type RequiredNotSetError struct {
|
|
||||||
field string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *RequiredNotSetError) Error() string {
|
|
||||||
return fmt.Sprintf("proto: required field %q not set", e.field)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// errRepeatedHasNil is the error returned if Marshal is called with
|
// errRepeatedHasNil is the error returned if Marshal is called with
|
||||||
// a struct with a repeated field containing a nil element.
|
// a struct with a repeated field containing a nil element.
|
||||||
|
62
vendor/github.com/golang/protobuf/proto/lib.go
generated
vendored
62
vendor/github.com/golang/protobuf/proto/lib.go
generated
vendored
@ -265,7 +265,6 @@ package proto
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -274,7 +273,66 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errInvalidUTF8 = errors.New("proto: invalid UTF-8 string")
|
// RequiredNotSetError is an error type returned by either Marshal or Unmarshal.
|
||||||
|
// Marshal reports this when a required field is not initialized.
|
||||||
|
// Unmarshal reports this when a required field is missing from the wire data.
|
||||||
|
type RequiredNotSetError struct{ field string }
|
||||||
|
|
||||||
|
func (e *RequiredNotSetError) Error() string {
|
||||||
|
if e.field == "" {
|
||||||
|
return fmt.Sprintf("proto: required field not set")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("proto: required field %q not set", e.field)
|
||||||
|
}
|
||||||
|
func (e *RequiredNotSetError) RequiredNotSet() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type invalidUTF8Error struct{ field string }
|
||||||
|
|
||||||
|
func (e *invalidUTF8Error) Error() string {
|
||||||
|
if e.field == "" {
|
||||||
|
return "proto: invalid UTF-8 detected"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field)
|
||||||
|
}
|
||||||
|
func (e *invalidUTF8Error) InvalidUTF8() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8.
|
||||||
|
// This error should not be exposed to the external API as such errors should
|
||||||
|
// be recreated with the field information.
|
||||||
|
var errInvalidUTF8 = &invalidUTF8Error{}
|
||||||
|
|
||||||
|
// isNonFatal reports whether the error is either a RequiredNotSet error
|
||||||
|
// or a InvalidUTF8 error.
|
||||||
|
func isNonFatal(err error) bool {
|
||||||
|
if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonFatal struct{ E error }
|
||||||
|
|
||||||
|
// Merge merges err into nf and reports whether it was successful.
|
||||||
|
// Otherwise it returns false for any fatal non-nil errors.
|
||||||
|
func (nf *nonFatal) Merge(err error) (ok bool) {
|
||||||
|
if err == nil {
|
||||||
|
return true // not an error
|
||||||
|
}
|
||||||
|
if !isNonFatal(err) {
|
||||||
|
return false // fatal error
|
||||||
|
}
|
||||||
|
if nf.E == nil {
|
||||||
|
nf.E = err // store first instance of non-fatal error
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Message is implemented by generated protocol buffer messages.
|
// Message is implemented by generated protocol buffer messages.
|
||||||
type Message interface {
|
type Message interface {
|
||||||
|
16
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
16
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
@ -139,7 +139,7 @@ type Properties struct {
|
|||||||
Repeated bool
|
Repeated bool
|
||||||
Packed bool // relevant for repeated primitives only
|
Packed bool // relevant for repeated primitives only
|
||||||
Enum string // set for enum types only
|
Enum string // set for enum types only
|
||||||
proto3 bool // whether this is known to be a proto3 field; set for []byte only
|
proto3 bool // whether this is known to be a proto3 field
|
||||||
oneof bool // whether this is a oneof field
|
oneof bool // whether this is a oneof field
|
||||||
|
|
||||||
Default string // default value
|
Default string // default value
|
||||||
@ -148,9 +148,9 @@ type Properties struct {
|
|||||||
stype reflect.Type // set for struct types only
|
stype reflect.Type // set for struct types only
|
||||||
sprop *StructProperties // set for struct types only
|
sprop *StructProperties // set for struct types only
|
||||||
|
|
||||||
mtype reflect.Type // set for map types only
|
mtype reflect.Type // set for map types only
|
||||||
mkeyprop *Properties // set for map types only
|
MapKeyProp *Properties // set for map types only
|
||||||
mvalprop *Properties // set for map types only
|
MapValProp *Properties // set for map types only
|
||||||
}
|
}
|
||||||
|
|
||||||
// String formats the properties in the protobuf struct field tag style.
|
// String formats the properties in the protobuf struct field tag style.
|
||||||
@ -275,16 +275,16 @@ func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, loc
|
|||||||
|
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
p.mtype = t1
|
p.mtype = t1
|
||||||
p.mkeyprop = &Properties{}
|
p.MapKeyProp = &Properties{}
|
||||||
p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
|
p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
|
||||||
p.mvalprop = &Properties{}
|
p.MapValProp = &Properties{}
|
||||||
vtype := p.mtype.Elem()
|
vtype := p.mtype.Elem()
|
||||||
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
|
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
|
||||||
// The value type is not a message (*T) or bytes ([]byte),
|
// The value type is not a message (*T) or bytes ([]byte),
|
||||||
// so we need encoders for the pointer to this type.
|
// so we need encoders for the pointer to this type.
|
||||||
vtype = reflect.PtrTo(vtype)
|
vtype = reflect.PtrTo(vtype)
|
||||||
}
|
}
|
||||||
p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
|
p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.stype != nil {
|
if p.stype != nil {
|
||||||
|
190
vendor/github.com/golang/protobuf/proto/table_marshal.go
generated
vendored
190
vendor/github.com/golang/protobuf/proto/table_marshal.go
generated
vendored
@ -231,7 +231,7 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
|
|||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var err, errreq error
|
var err, errLater error
|
||||||
// The old marshaler encodes extensions at beginning.
|
// The old marshaler encodes extensions at beginning.
|
||||||
if u.extensions.IsValid() {
|
if u.extensions.IsValid() {
|
||||||
e := ptr.offset(u.extensions).toExtensions()
|
e := ptr.offset(u.extensions).toExtensions()
|
||||||
@ -252,11 +252,13 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, f := range u.fields {
|
for _, f := range u.fields {
|
||||||
if f.required && errreq == nil {
|
if f.required {
|
||||||
if ptr.offset(f.field).getPointer().isNil() {
|
if ptr.offset(f.field).getPointer().isNil() {
|
||||||
// Required field is not set.
|
// Required field is not set.
|
||||||
// We record the error but keep going, to give a complete marshaling.
|
// We record the error but keep going, to give a complete marshaling.
|
||||||
errreq = &RequiredNotSetError{f.name}
|
if errLater == nil {
|
||||||
|
errLater = &RequiredNotSetError{f.name}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,14 +271,21 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
|
|||||||
if err1, ok := err.(*RequiredNotSetError); ok {
|
if err1, ok := err.(*RequiredNotSetError); ok {
|
||||||
// Required field in submessage is not set.
|
// Required field in submessage is not set.
|
||||||
// We record the error but keep going, to give a complete marshaling.
|
// We record the error but keep going, to give a complete marshaling.
|
||||||
if errreq == nil {
|
if errLater == nil {
|
||||||
errreq = &RequiredNotSetError{f.name + "." + err1.field}
|
errLater = &RequiredNotSetError{f.name + "." + err1.field}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err == errRepeatedHasNil {
|
if err == errRepeatedHasNil {
|
||||||
err = errors.New("proto: repeated field " + f.name + " has nil element")
|
err = errors.New("proto: repeated field " + f.name + " has nil element")
|
||||||
}
|
}
|
||||||
|
if err == errInvalidUTF8 {
|
||||||
|
if errLater == nil {
|
||||||
|
fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
|
||||||
|
errLater = &invalidUTF8Error{fullName}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,7 +293,7 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
|
|||||||
s := *ptr.offset(u.unrecognized).toBytes()
|
s := *ptr.offset(u.unrecognized).toBytes()
|
||||||
b = append(b, s...)
|
b = append(b, s...)
|
||||||
}
|
}
|
||||||
return b, errreq
|
return b, errLater
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeMarshalInfo initializes the marshal info.
|
// computeMarshalInfo initializes the marshal info.
|
||||||
@ -530,6 +539,7 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
|
|||||||
|
|
||||||
packed := false
|
packed := false
|
||||||
proto3 := false
|
proto3 := false
|
||||||
|
validateUTF8 := true
|
||||||
for i := 2; i < len(tags); i++ {
|
for i := 2; i < len(tags); i++ {
|
||||||
if tags[i] == "packed" {
|
if tags[i] == "packed" {
|
||||||
packed = true
|
packed = true
|
||||||
@ -538,6 +548,7 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
|
|||||||
proto3 = true
|
proto3 = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
validateUTF8 = validateUTF8 && proto3
|
||||||
|
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
@ -735,6 +746,18 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
|
|||||||
}
|
}
|
||||||
return sizeFloat64Value, appendFloat64Value
|
return sizeFloat64Value, appendFloat64Value
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
|
if validateUTF8 {
|
||||||
|
if pointer {
|
||||||
|
return sizeStringPtr, appendUTF8StringPtr
|
||||||
|
}
|
||||||
|
if slice {
|
||||||
|
return sizeStringSlice, appendUTF8StringSlice
|
||||||
|
}
|
||||||
|
if nozero {
|
||||||
|
return sizeStringValueNoZero, appendUTF8StringValueNoZero
|
||||||
|
}
|
||||||
|
return sizeStringValue, appendUTF8StringValue
|
||||||
|
}
|
||||||
if pointer {
|
if pointer {
|
||||||
return sizeStringPtr, appendStringPtr
|
return sizeStringPtr, appendStringPtr
|
||||||
}
|
}
|
||||||
@ -1984,9 +2007,6 @@ func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byt
|
|||||||
}
|
}
|
||||||
func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
v := *ptr.toString()
|
v := *ptr.toString()
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
b = appendVarint(b, wiretag)
|
b = appendVarint(b, wiretag)
|
||||||
b = appendVarint(b, uint64(len(v)))
|
b = appendVarint(b, uint64(len(v)))
|
||||||
b = append(b, v...)
|
b = append(b, v...)
|
||||||
@ -1997,9 +2017,6 @@ func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]b
|
|||||||
if v == "" {
|
if v == "" {
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
b = appendVarint(b, wiretag)
|
b = appendVarint(b, wiretag)
|
||||||
b = appendVarint(b, uint64(len(v)))
|
b = appendVarint(b, uint64(len(v)))
|
||||||
b = append(b, v...)
|
b = append(b, v...)
|
||||||
@ -2011,24 +2028,83 @@ func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, err
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
v := *p
|
v := *p
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
b = appendVarint(b, wiretag)
|
b = appendVarint(b, wiretag)
|
||||||
b = appendVarint(b, uint64(len(v)))
|
b = appendVarint(b, uint64(len(v)))
|
||||||
b = append(b, v...)
|
b = append(b, v...)
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
s := *ptr.toStringSlice()
|
||||||
|
for _, v := range s {
|
||||||
|
b = appendVarint(b, wiretag)
|
||||||
|
b = appendVarint(b, uint64(len(v)))
|
||||||
|
b = append(b, v...)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
var invalidUTF8 bool
|
||||||
|
v := *ptr.toString()
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
invalidUTF8 = true
|
||||||
|
}
|
||||||
|
b = appendVarint(b, wiretag)
|
||||||
|
b = appendVarint(b, uint64(len(v)))
|
||||||
|
b = append(b, v...)
|
||||||
|
if invalidUTF8 {
|
||||||
|
return b, errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
var invalidUTF8 bool
|
||||||
|
v := *ptr.toString()
|
||||||
|
if v == "" {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
invalidUTF8 = true
|
||||||
|
}
|
||||||
|
b = appendVarint(b, wiretag)
|
||||||
|
b = appendVarint(b, uint64(len(v)))
|
||||||
|
b = append(b, v...)
|
||||||
|
if invalidUTF8 {
|
||||||
|
return b, errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
var invalidUTF8 bool
|
||||||
|
p := *ptr.toStringPtr()
|
||||||
|
if p == nil {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
v := *p
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
invalidUTF8 = true
|
||||||
|
}
|
||||||
|
b = appendVarint(b, wiretag)
|
||||||
|
b = appendVarint(b, uint64(len(v)))
|
||||||
|
b = append(b, v...)
|
||||||
|
if invalidUTF8 {
|
||||||
|
return b, errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
var invalidUTF8 bool
|
||||||
s := *ptr.toStringSlice()
|
s := *ptr.toStringSlice()
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
if !utf8.ValidString(v) {
|
if !utf8.ValidString(v) {
|
||||||
return nil, errInvalidUTF8
|
invalidUTF8 = true
|
||||||
}
|
}
|
||||||
b = appendVarint(b, wiretag)
|
b = appendVarint(b, wiretag)
|
||||||
b = appendVarint(b, uint64(len(v)))
|
b = appendVarint(b, uint64(len(v)))
|
||||||
b = append(b, v...)
|
b = append(b, v...)
|
||||||
}
|
}
|
||||||
|
if invalidUTF8 {
|
||||||
|
return b, errInvalidUTF8
|
||||||
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
@ -2107,7 +2183,8 @@ func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
|
|||||||
},
|
},
|
||||||
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
|
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
|
||||||
s := ptr.getPointerSlice()
|
s := ptr.getPointerSlice()
|
||||||
var err, errreq error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
if v.isNil() {
|
if v.isNil() {
|
||||||
return b, errRepeatedHasNil
|
return b, errRepeatedHasNil
|
||||||
@ -2115,22 +2192,14 @@ func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
|
|||||||
b = appendVarint(b, wiretag) // start group
|
b = appendVarint(b, wiretag) // start group
|
||||||
b, err = u.marshal(b, v, deterministic)
|
b, err = u.marshal(b, v, deterministic)
|
||||||
b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group
|
b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
if _, ok := err.(*RequiredNotSetError); ok {
|
|
||||||
// Required field in submessage is not set.
|
|
||||||
// We record the error but keep going, to give a complete marshaling.
|
|
||||||
if errreq == nil {
|
|
||||||
errreq = err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err == ErrNil {
|
if err == ErrNil {
|
||||||
err = errRepeatedHasNil
|
err = errRepeatedHasNil
|
||||||
}
|
}
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, errreq
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2174,7 +2243,8 @@ func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
|
|||||||
},
|
},
|
||||||
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
|
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
|
||||||
s := ptr.getPointerSlice()
|
s := ptr.getPointerSlice()
|
||||||
var err, errreq error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
if v.isNil() {
|
if v.isNil() {
|
||||||
return b, errRepeatedHasNil
|
return b, errRepeatedHasNil
|
||||||
@ -2184,22 +2254,14 @@ func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
|
|||||||
b = appendVarint(b, uint64(siz))
|
b = appendVarint(b, uint64(siz))
|
||||||
b, err = u.marshal(b, v, deterministic)
|
b, err = u.marshal(b, v, deterministic)
|
||||||
|
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
if _, ok := err.(*RequiredNotSetError); ok {
|
|
||||||
// Required field in submessage is not set.
|
|
||||||
// We record the error but keep going, to give a complete marshaling.
|
|
||||||
if errreq == nil {
|
|
||||||
errreq = err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err == ErrNil {
|
if err == ErrNil {
|
||||||
err = errRepeatedHasNil
|
err = errRepeatedHasNil
|
||||||
}
|
}
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, errreq
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2223,6 +2285,25 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
|
|||||||
// value.
|
// value.
|
||||||
// Key cannot be pointer-typed.
|
// Key cannot be pointer-typed.
|
||||||
valIsPtr := valType.Kind() == reflect.Ptr
|
valIsPtr := valType.Kind() == reflect.Ptr
|
||||||
|
|
||||||
|
// If value is a message with nested maps, calling
|
||||||
|
// valSizer in marshal may be quadratic. We should use
|
||||||
|
// cached version in marshal (but not in size).
|
||||||
|
// If value is not message type, we don't have size cache,
|
||||||
|
// but it cannot be nested either. Just use valSizer.
|
||||||
|
valCachedSizer := valSizer
|
||||||
|
if valIsPtr && valType.Elem().Kind() == reflect.Struct {
|
||||||
|
u := getMarshalInfo(valType.Elem())
|
||||||
|
valCachedSizer = func(ptr pointer, tagsize int) int {
|
||||||
|
// Same as message sizer, but use cache.
|
||||||
|
p := ptr.getPointer()
|
||||||
|
if p.isNil() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
siz := u.cachedsize(p)
|
||||||
|
return siz + SizeVarint(uint64(siz)) + tagsize
|
||||||
|
}
|
||||||
|
}
|
||||||
return func(ptr pointer, tagsize int) int {
|
return func(ptr pointer, tagsize int) int {
|
||||||
m := ptr.asPointerTo(t).Elem() // the map
|
m := ptr.asPointerTo(t).Elem() // the map
|
||||||
n := 0
|
n := 0
|
||||||
@ -2243,24 +2324,26 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
|
|||||||
if len(keys) > 1 && deterministic {
|
if len(keys) > 1 && deterministic {
|
||||||
sort.Sort(mapKeys(keys))
|
sort.Sort(mapKeys(keys))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nerr nonFatal
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
ki := k.Interface()
|
ki := k.Interface()
|
||||||
vi := m.MapIndex(k).Interface()
|
vi := m.MapIndex(k).Interface()
|
||||||
kaddr := toAddrPointer(&ki, false) // pointer to key
|
kaddr := toAddrPointer(&ki, false) // pointer to key
|
||||||
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
|
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
|
||||||
b = appendVarint(b, tag)
|
b = appendVarint(b, tag)
|
||||||
siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
|
siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
|
||||||
b = appendVarint(b, uint64(siz))
|
b = appendVarint(b, uint64(siz))
|
||||||
b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic)
|
b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
b, err = valMarshaler(b, vaddr, valWireTag, deterministic)
|
b, err = valMarshaler(b, vaddr, valWireTag, deterministic)
|
||||||
if err != nil && err != ErrNil { // allow nil value in map
|
if err != ErrNil && !nerr.Merge(err) { // allow nil value in map
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2333,6 +2416,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
|
|
||||||
// Fast-path for common cases: zero or one extensions.
|
// Fast-path for common cases: zero or one extensions.
|
||||||
// Don't bother sorting the keys.
|
// Don't bother sorting the keys.
|
||||||
@ -2352,11 +2436,11 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the keys to provide a deterministic encoding.
|
// Sort the keys to provide a deterministic encoding.
|
||||||
@ -2383,11 +2467,11 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// message set format is:
|
// message set format is:
|
||||||
@ -2444,6 +2528,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
|
|
||||||
// Fast-path for common cases: zero or one extensions.
|
// Fast-path for common cases: zero or one extensions.
|
||||||
// Don't bother sorting the keys.
|
// Don't bother sorting the keys.
|
||||||
@ -2470,12 +2555,12 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
b = append(b, 1<<3|WireEndGroup)
|
b = append(b, 1<<3|WireEndGroup)
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the keys to provide a deterministic encoding.
|
// Sort the keys to provide a deterministic encoding.
|
||||||
@ -2509,11 +2594,11 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
||||||
b = append(b, 1<<3|WireEndGroup)
|
b = append(b, 1<<3|WireEndGroup)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// sizeV1Extensions computes the size of encoded data for a V1-API extension field.
|
// sizeV1Extensions computes the size of encoded data for a V1-API extension field.
|
||||||
@ -2556,6 +2641,7 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
|
|||||||
sort.Ints(keys)
|
sort.Ints(keys)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
e := m[int32(k)]
|
e := m[int32(k)]
|
||||||
if e.value == nil || e.desc == nil {
|
if e.value == nil || e.desc == nil {
|
||||||
@ -2572,11 +2658,11 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
|
|||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// newMarshaler is the interface representing objects that can marshal themselves.
|
// newMarshaler is the interface representing objects that can marshal themselves.
|
||||||
|
146
vendor/github.com/golang/protobuf/proto/table_unmarshal.go
generated
vendored
146
vendor/github.com/golang/protobuf/proto/table_unmarshal.go
generated
vendored
@ -97,6 +97,8 @@ type unmarshalFieldInfo struct {
|
|||||||
|
|
||||||
// if a required field, contains a single set bit at this field's index in the required field list.
|
// if a required field, contains a single set bit at this field's index in the required field list.
|
||||||
reqMask uint64
|
reqMask uint64
|
||||||
|
|
||||||
|
name string // name of the field, for error reporting
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -136,8 +138,8 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
|
|||||||
if u.isMessageSet {
|
if u.isMessageSet {
|
||||||
return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
|
return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
|
||||||
}
|
}
|
||||||
var reqMask uint64 // bitmask of required fields we've seen.
|
var reqMask uint64 // bitmask of required fields we've seen.
|
||||||
var rnse *RequiredNotSetError // an instance of a RequiredNotSetError returned by a submessage.
|
var errLater error
|
||||||
for len(b) > 0 {
|
for len(b) > 0 {
|
||||||
// Read tag and wire type.
|
// Read tag and wire type.
|
||||||
// Special case 1 and 2 byte varints.
|
// Special case 1 and 2 byte varints.
|
||||||
@ -176,11 +178,20 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
|
|||||||
if r, ok := err.(*RequiredNotSetError); ok {
|
if r, ok := err.(*RequiredNotSetError); ok {
|
||||||
// Remember this error, but keep parsing. We need to produce
|
// Remember this error, but keep parsing. We need to produce
|
||||||
// a full parse even if a required field is missing.
|
// a full parse even if a required field is missing.
|
||||||
rnse = r
|
if errLater == nil {
|
||||||
|
errLater = r
|
||||||
|
}
|
||||||
reqMask |= f.reqMask
|
reqMask |= f.reqMask
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != errInternalBadWireType {
|
if err != errInternalBadWireType {
|
||||||
|
if err == errInvalidUTF8 {
|
||||||
|
if errLater == nil {
|
||||||
|
fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
|
||||||
|
errLater = &invalidUTF8Error{fullName}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Fragments with bad wire type are treated as unknown fields.
|
// Fragments with bad wire type are treated as unknown fields.
|
||||||
@ -239,20 +250,16 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
|
|||||||
emap[int32(tag)] = e
|
emap[int32(tag)] = e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rnse != nil {
|
if reqMask != u.reqMask && errLater == nil {
|
||||||
// A required field of a submessage/group is missing. Return that error.
|
|
||||||
return rnse
|
|
||||||
}
|
|
||||||
if reqMask != u.reqMask {
|
|
||||||
// A required field of this message is missing.
|
// A required field of this message is missing.
|
||||||
for _, n := range u.reqFields {
|
for _, n := range u.reqFields {
|
||||||
if reqMask&1 == 0 {
|
if reqMask&1 == 0 {
|
||||||
return &RequiredNotSetError{n}
|
errLater = &RequiredNotSetError{n}
|
||||||
}
|
}
|
||||||
reqMask >>= 1
|
reqMask >>= 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return errLater
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeUnmarshalInfo fills in u with information for use
|
// computeUnmarshalInfo fills in u with information for use
|
||||||
@ -351,7 +358,7 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store the info in the correct slot in the message.
|
// Store the info in the correct slot in the message.
|
||||||
u.setTag(tag, toField(&f), unmarshal, reqMask)
|
u.setTag(tag, toField(&f), unmarshal, reqMask, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find any types associated with oneof fields.
|
// Find any types associated with oneof fields.
|
||||||
@ -366,10 +373,17 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
|
|
||||||
f := typ.Field(0) // oneof implementers have one field
|
f := typ.Field(0) // oneof implementers have one field
|
||||||
baseUnmarshal := fieldUnmarshaler(&f)
|
baseUnmarshal := fieldUnmarshaler(&f)
|
||||||
tagstr := strings.Split(f.Tag.Get("protobuf"), ",")[1]
|
tags := strings.Split(f.Tag.Get("protobuf"), ",")
|
||||||
tag, err := strconv.Atoi(tagstr)
|
fieldNum, err := strconv.Atoi(tags[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("protobuf tag field not an integer: " + tagstr)
|
panic("protobuf tag field not an integer: " + tags[1])
|
||||||
|
}
|
||||||
|
var name string
|
||||||
|
for _, tag := range tags {
|
||||||
|
if strings.HasPrefix(tag, "name=") {
|
||||||
|
name = strings.TrimPrefix(tag, "name=")
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the oneof field that this struct implements.
|
// Find the oneof field that this struct implements.
|
||||||
@ -380,7 +394,7 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
// That lets us know where this struct should be stored
|
// That lets us know where this struct should be stored
|
||||||
// when we encounter it during unmarshaling.
|
// when we encounter it during unmarshaling.
|
||||||
unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
|
unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
|
||||||
u.setTag(tag, of.field, unmarshal, 0)
|
u.setTag(fieldNum, of.field, unmarshal, 0, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,7 +415,7 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
// [0 0] is [tag=0/wiretype=varint varint-encoded-0].
|
// [0 0] is [tag=0/wiretype=varint varint-encoded-0].
|
||||||
u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) {
|
u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w)
|
return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w)
|
||||||
}, 0)
|
}, 0, "")
|
||||||
|
|
||||||
// Set mask for required field check.
|
// Set mask for required field check.
|
||||||
u.reqMask = uint64(1)<<uint(len(u.reqFields)) - 1
|
u.reqMask = uint64(1)<<uint(len(u.reqFields)) - 1
|
||||||
@ -413,8 +427,9 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
// tag = tag # for field
|
// tag = tag # for field
|
||||||
// field/unmarshal = unmarshal info for that field.
|
// field/unmarshal = unmarshal info for that field.
|
||||||
// reqMask = if required, bitmask for field position in required field list. 0 otherwise.
|
// reqMask = if required, bitmask for field position in required field list. 0 otherwise.
|
||||||
func (u *unmarshalInfo) setTag(tag int, field field, unmarshal unmarshaler, reqMask uint64) {
|
// name = short name of the field.
|
||||||
i := unmarshalFieldInfo{field: field, unmarshal: unmarshal, reqMask: reqMask}
|
func (u *unmarshalInfo) setTag(tag int, field field, unmarshal unmarshaler, reqMask uint64, name string) {
|
||||||
|
i := unmarshalFieldInfo{field: field, unmarshal: unmarshal, reqMask: reqMask, name: name}
|
||||||
n := u.typ.NumField()
|
n := u.typ.NumField()
|
||||||
if tag >= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here?
|
if tag >= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here?
|
||||||
for len(u.dense) <= tag {
|
for len(u.dense) <= tag {
|
||||||
@ -442,11 +457,17 @@ func typeUnmarshaler(t reflect.Type, tags string) unmarshaler {
|
|||||||
tagArray := strings.Split(tags, ",")
|
tagArray := strings.Split(tags, ",")
|
||||||
encoding := tagArray[0]
|
encoding := tagArray[0]
|
||||||
name := "unknown"
|
name := "unknown"
|
||||||
|
proto3 := false
|
||||||
|
validateUTF8 := true
|
||||||
for _, tag := range tagArray[3:] {
|
for _, tag := range tagArray[3:] {
|
||||||
if strings.HasPrefix(tag, "name=") {
|
if strings.HasPrefix(tag, "name=") {
|
||||||
name = tag[5:]
|
name = tag[5:]
|
||||||
}
|
}
|
||||||
|
if tag == "proto3" {
|
||||||
|
proto3 = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
validateUTF8 = validateUTF8 && proto3
|
||||||
|
|
||||||
// Figure out packaging (pointer, slice, or both)
|
// Figure out packaging (pointer, slice, or both)
|
||||||
slice := false
|
slice := false
|
||||||
@ -594,6 +615,15 @@ func typeUnmarshaler(t reflect.Type, tags string) unmarshaler {
|
|||||||
}
|
}
|
||||||
return unmarshalBytesValue
|
return unmarshalBytesValue
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
|
if validateUTF8 {
|
||||||
|
if pointer {
|
||||||
|
return unmarshalUTF8StringPtr
|
||||||
|
}
|
||||||
|
if slice {
|
||||||
|
return unmarshalUTF8StringSlice
|
||||||
|
}
|
||||||
|
return unmarshalUTF8StringValue
|
||||||
|
}
|
||||||
if pointer {
|
if pointer {
|
||||||
return unmarshalStringPtr
|
return unmarshalStringPtr
|
||||||
}
|
}
|
||||||
@ -1448,9 +1478,6 @@ func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) {
|
|||||||
return nil, io.ErrUnexpectedEOF
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
v := string(b[:x])
|
v := string(b[:x])
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
*f.toString() = v
|
*f.toString() = v
|
||||||
return b[x:], nil
|
return b[x:], nil
|
||||||
}
|
}
|
||||||
@ -1468,9 +1495,6 @@ func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) {
|
|||||||
return nil, io.ErrUnexpectedEOF
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
v := string(b[:x])
|
v := string(b[:x])
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
*f.toStringPtr() = &v
|
*f.toStringPtr() = &v
|
||||||
return b[x:], nil
|
return b[x:], nil
|
||||||
}
|
}
|
||||||
@ -1488,14 +1512,72 @@ func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) {
|
|||||||
return nil, io.ErrUnexpectedEOF
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
v := string(b[:x])
|
v := string(b[:x])
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
s := f.toStringSlice()
|
s := f.toStringSlice()
|
||||||
*s = append(*s, v)
|
*s = append(*s, v)
|
||||||
return b[x:], nil
|
return b[x:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
|
if w != WireBytes {
|
||||||
|
return b, errInternalBadWireType
|
||||||
|
}
|
||||||
|
x, n := decodeVarint(b)
|
||||||
|
if n == 0 {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b = b[n:]
|
||||||
|
if x > uint64(len(b)) {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
v := string(b[:x])
|
||||||
|
*f.toString() = v
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
return b[x:], errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b[x:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
|
if w != WireBytes {
|
||||||
|
return b, errInternalBadWireType
|
||||||
|
}
|
||||||
|
x, n := decodeVarint(b)
|
||||||
|
if n == 0 {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b = b[n:]
|
||||||
|
if x > uint64(len(b)) {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
v := string(b[:x])
|
||||||
|
*f.toStringPtr() = &v
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
return b[x:], errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b[x:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
|
if w != WireBytes {
|
||||||
|
return b, errInternalBadWireType
|
||||||
|
}
|
||||||
|
x, n := decodeVarint(b)
|
||||||
|
if n == 0 {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b = b[n:]
|
||||||
|
if x > uint64(len(b)) {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
v := string(b[:x])
|
||||||
|
s := f.toStringSlice()
|
||||||
|
*s = append(*s, v)
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
return b[x:], errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b[x:], nil
|
||||||
|
}
|
||||||
|
|
||||||
var emptyBuf [0]byte
|
var emptyBuf [0]byte
|
||||||
|
|
||||||
func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) {
|
func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
@ -1674,6 +1756,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
|
|||||||
// Maps will be somewhat slow. Oh well.
|
// Maps will be somewhat slow. Oh well.
|
||||||
|
|
||||||
// Read key and value from data.
|
// Read key and value from data.
|
||||||
|
var nerr nonFatal
|
||||||
k := reflect.New(kt)
|
k := reflect.New(kt)
|
||||||
v := reflect.New(vt)
|
v := reflect.New(vt)
|
||||||
for len(b) > 0 {
|
for len(b) > 0 {
|
||||||
@ -1694,7 +1777,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
|
|||||||
err = errInternalBadWireType // skip unknown tag
|
err = errInternalBadWireType // skip unknown tag
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if nerr.Merge(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != errInternalBadWireType {
|
if err != errInternalBadWireType {
|
||||||
@ -1717,7 +1800,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
|
|||||||
// Insert into map.
|
// Insert into map.
|
||||||
m.SetMapIndex(k.Elem(), v.Elem())
|
m.SetMapIndex(k.Elem(), v.Elem())
|
||||||
|
|
||||||
return r, nil
|
return r, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1743,15 +1826,16 @@ func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshal
|
|||||||
// Unmarshal data into holder.
|
// Unmarshal data into holder.
|
||||||
// We unmarshal into the first field of the holder object.
|
// We unmarshal into the first field of the holder object.
|
||||||
var err error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
b, err = unmarshal(b, valToPointer(v).offset(field0), w)
|
b, err = unmarshal(b, valToPointer(v).offset(field0), w)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write pointer to holder into target field.
|
// Write pointer to holder into target field.
|
||||||
f.asPointerTo(ityp).Elem().Set(v)
|
f.asPointerTo(ityp).Elem().Set(v)
|
||||||
|
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
vendor/github.com/golang/protobuf/proto/text.go
generated
vendored
4
vendor/github.com/golang/protobuf/proto/text.go
generated
vendored
@ -353,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := tm.writeAny(w, key, props.mkeyprop); err != nil {
|
if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.WriteByte('\n'); err != nil {
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
@ -370,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := tm.writeAny(w, val, props.mvalprop); err != nil {
|
if err := tm.writeAny(w, val, props.MapValProp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.WriteByte('\n'); err != nil {
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
6
vendor/github.com/golang/protobuf/proto/text_parser.go
generated
vendored
6
vendor/github.com/golang/protobuf/proto/text_parser.go
generated
vendored
@ -630,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
|||||||
if err := p.consumeToken(":"); err != nil {
|
if err := p.consumeToken(":"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := p.readAny(key, props.mkeyprop); err != nil {
|
if err := p.readAny(key, props.MapKeyProp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "value":
|
case "value":
|
||||||
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
|
if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := p.readAny(val, props.mvalprop); err != nil {
|
if err := p.readAny(val, props.MapValProp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
15
vendor/github.com/google/go-github/AUTHORS
generated
vendored
15
vendor/github.com/google/go-github/AUTHORS
generated
vendored
@ -13,6 +13,7 @@ Abhinav Gupta <mail@abhinavg.net>
|
|||||||
Ahmed Hagy <a.akram93@gmail.com>
|
Ahmed Hagy <a.akram93@gmail.com>
|
||||||
Ainsley Chong <ainsley.chong@gmail.com>
|
Ainsley Chong <ainsley.chong@gmail.com>
|
||||||
Akeda Bagus <akeda@x-team.com>
|
Akeda Bagus <akeda@x-team.com>
|
||||||
|
Akhil Mohan <akhilerm@gmail.com>
|
||||||
Alec Thomas <alec@swapoff.org>
|
Alec Thomas <alec@swapoff.org>
|
||||||
Aleks Clark <aleks.clark@gmail.com>
|
Aleks Clark <aleks.clark@gmail.com>
|
||||||
Alex Bramley <a.bramley@gmail.com>
|
Alex Bramley <a.bramley@gmail.com>
|
||||||
@ -38,6 +39,7 @@ Björn Häuser <b.haeuser@rebuy.de>
|
|||||||
Brad Harris <bmharris@gmail.com>
|
Brad Harris <bmharris@gmail.com>
|
||||||
Brad Moylan <moylan.brad@gmail.com>
|
Brad Moylan <moylan.brad@gmail.com>
|
||||||
Bradley Falzon <brad@teambrad.net>
|
Bradley Falzon <brad@teambrad.net>
|
||||||
|
Brandon Cook <phylake@gmail.com>
|
||||||
Brian Egizi <brian@mojotech.com>
|
Brian Egizi <brian@mojotech.com>
|
||||||
Bryan Boreham <bryan@weave.works>
|
Bryan Boreham <bryan@weave.works>
|
||||||
Cami Diez <diezcami@gmail.com>
|
Cami Diez <diezcami@gmail.com>
|
||||||
@ -70,6 +72,7 @@ Drew Fradette <drew.fradette@gmail.com>
|
|||||||
Eli Uriegas <seemethere101@gmail.com>
|
Eli Uriegas <seemethere101@gmail.com>
|
||||||
Elliott Beach <elliott2.71828@gmail.com>
|
Elliott Beach <elliott2.71828@gmail.com>
|
||||||
Emerson Wood <emersonwood94@gmail.com>
|
Emerson Wood <emersonwood94@gmail.com>
|
||||||
|
eperm <staffordworrell@gmail.com>
|
||||||
erwinvaneyk <erwinvaneyk@gmail.com>
|
erwinvaneyk <erwinvaneyk@gmail.com>
|
||||||
Fabrice <fabrice.vaillant@student.ecp.fr>
|
Fabrice <fabrice.vaillant@student.ecp.fr>
|
||||||
Filippo Valsorda <hi@filippo.io>
|
Filippo Valsorda <hi@filippo.io>
|
||||||
@ -78,6 +81,7 @@ Francesc Gil <xescugil@gmail.com>
|
|||||||
Francis <hello@francismakes.com>
|
Francis <hello@francismakes.com>
|
||||||
Fredrik Jönsson <fredrik.jonsson@izettle.com>
|
Fredrik Jönsson <fredrik.jonsson@izettle.com>
|
||||||
Garrett Squire <garrettsquire@gmail.com>
|
Garrett Squire <garrettsquire@gmail.com>
|
||||||
|
George Kontridze <george.kontridze@gmail.com>
|
||||||
Georgy Buranov <gburanov@gmail.com>
|
Georgy Buranov <gburanov@gmail.com>
|
||||||
Gnahz <p@oath.pl>
|
Gnahz <p@oath.pl>
|
||||||
Google Inc.
|
Google Inc.
|
||||||
@ -95,15 +99,19 @@ Isao Jonas <isao.jonas@gmail.com>
|
|||||||
isqua <isqua@isqua.ru>
|
isqua <isqua@isqua.ru>
|
||||||
Jameel Haffejee <RC1140@republiccommandos.co.za>
|
Jameel Haffejee <RC1140@republiccommandos.co.za>
|
||||||
Jan Kosecki <jan.kosecki91@gmail.com>
|
Jan Kosecki <jan.kosecki91@gmail.com>
|
||||||
|
Javier Campanini <jcampanini@palantir.com>
|
||||||
Jeremy Morris <jeremylevanmorris@gmail.com>
|
Jeremy Morris <jeremylevanmorris@gmail.com>
|
||||||
|
Jesse Newland <jesse@jnewland.com>
|
||||||
Jihoon Chung <j.c@navercorp.com>
|
Jihoon Chung <j.c@navercorp.com>
|
||||||
Jimmi Dyson <jimmidyson@gmail.com>
|
Jimmi Dyson <jimmidyson@gmail.com>
|
||||||
Joan Saum <joan.saum@epitech.eu>
|
Joan Saum <joan.saum@epitech.eu>
|
||||||
Joe Tsai <joetsai@digital-static.net>
|
Joe Tsai <joetsai@digital-static.net>
|
||||||
John Barton <jrbarton@gmail.com>
|
John Barton <jrbarton@gmail.com>
|
||||||
John Engelman <john.r.engelman@gmail.com>
|
John Engelman <john.r.engelman@gmail.com>
|
||||||
|
JP Phillips <jonphill9@gmail.com>
|
||||||
jpbelanger-mtl <jp.belanger@gmail.com>
|
jpbelanger-mtl <jp.belanger@gmail.com>
|
||||||
Juan Basso <jrbasso@gmail.com>
|
Juan Basso <jrbasso@gmail.com>
|
||||||
|
Julien Garcia Gonzalez <garciagonzalez.julien@gmail.com>
|
||||||
Julien Rostand <jrostand@users.noreply.github.com>
|
Julien Rostand <jrostand@users.noreply.github.com>
|
||||||
Justin Abrahms <justin@abrah.ms>
|
Justin Abrahms <justin@abrah.ms>
|
||||||
Jusung Lee <e.jusunglee@gmail.com>
|
Jusung Lee <e.jusunglee@gmail.com>
|
||||||
@ -123,9 +131,11 @@ Luke Roberts <email@luke-roberts.co.uk>
|
|||||||
Luke Young <luke@hydrantlabs.org>
|
Luke Young <luke@hydrantlabs.org>
|
||||||
Maksim Zhylinski <uzzable@gmail.com>
|
Maksim Zhylinski <uzzable@gmail.com>
|
||||||
Martin-Louis Bright <mlbright@gmail.com>
|
Martin-Louis Bright <mlbright@gmail.com>
|
||||||
|
Marwan Sulaiman <marwan.sameer@gmail.com>
|
||||||
Mat Geist <matgeist@gmail.com>
|
Mat Geist <matgeist@gmail.com>
|
||||||
Matt <alpmatthew@gmail.com>
|
Matt <alpmatthew@gmail.com>
|
||||||
Matt Brender <mjbrender@gmail.com>
|
Matt Brender <mjbrender@gmail.com>
|
||||||
|
Matt Gaunt <matt@gauntface.co.uk>
|
||||||
Matt Landis <landis.matt@gmail.com>
|
Matt Landis <landis.matt@gmail.com>
|
||||||
Maxime Bury <maxime.bury@gmail.com>
|
Maxime Bury <maxime.bury@gmail.com>
|
||||||
Michael Spiegel <michael.m.spiegel@gmail.com>
|
Michael Spiegel <michael.m.spiegel@gmail.com>
|
||||||
@ -145,17 +155,20 @@ Parham Alvani <parham.alvani@gmail.com>
|
|||||||
Parker Moore <parkrmoore@gmail.com>
|
Parker Moore <parkrmoore@gmail.com>
|
||||||
parkhyukjun89 <park.hyukjun89@gmail.com>
|
parkhyukjun89 <park.hyukjun89@gmail.com>
|
||||||
Pavel Shtanko <pavel.shtanko@gmail.com>
|
Pavel Shtanko <pavel.shtanko@gmail.com>
|
||||||
|
Pete Wagner <thepwagner@github.com>
|
||||||
Petr Shevtsov <petr.shevtsov@gmail.com>
|
Petr Shevtsov <petr.shevtsov@gmail.com>
|
||||||
Pierre Carrier <pierre@meteor.com>
|
Pierre Carrier <pierre@meteor.com>
|
||||||
Piotr Zurek <p.zurek@gmail.com>
|
Piotr Zurek <p.zurek@gmail.com>
|
||||||
Quinn Slack <qslack@qslack.com>
|
Quinn Slack <qslack@qslack.com>
|
||||||
Rackspace US, Inc.
|
Rackspace US, Inc.
|
||||||
Radek Simko <radek.simko@gmail.com>
|
Radek Simko <radek.simko@gmail.com>
|
||||||
|
Radliński Ignacy <radlinsk@student.agh.edu.pl>
|
||||||
Rajendra arora <rajendraarora16@yahoo.com>
|
Rajendra arora <rajendraarora16@yahoo.com>
|
||||||
RaviTeja Pothana <ravi-teja@live.com>
|
RaviTeja Pothana <ravi-teja@live.com>
|
||||||
rc1140 <jameel@republiccommandos.co.za>
|
rc1140 <jameel@republiccommandos.co.za>
|
||||||
Red Hat, Inc.
|
Red Hat, Inc.
|
||||||
Rob Figueiredo <robfig@yext.com>
|
Rob Figueiredo <robfig@yext.com>
|
||||||
|
Rohit Upadhyay <urohit011@gmail.com>
|
||||||
Ronak Jain <ronakjain@outlook.in>
|
Ronak Jain <ronakjain@outlook.in>
|
||||||
Ruben Vereecken <rubenvereecken@gmail.com>
|
Ruben Vereecken <rubenvereecken@gmail.com>
|
||||||
Ryan Lower <rpjlower@gmail.com>
|
Ryan Lower <rpjlower@gmail.com>
|
||||||
@ -176,6 +189,7 @@ Shawn Smith <shawnpsmith@gmail.com>
|
|||||||
sona-tar <sona.zip@gmail.com>
|
sona-tar <sona.zip@gmail.com>
|
||||||
SoundCloud, Ltd.
|
SoundCloud, Ltd.
|
||||||
Stian Eikeland <stian@eikeland.se>
|
Stian Eikeland <stian@eikeland.se>
|
||||||
|
Tasya Aditya Rukmana <tadityar@gmail.com>
|
||||||
Thomas Bruyelle <thomas.bruyelle@gmail.com>
|
Thomas Bruyelle <thomas.bruyelle@gmail.com>
|
||||||
Timothée Peignier <timothee.peignier@tryphon.org>
|
Timothée Peignier <timothee.peignier@tryphon.org>
|
||||||
Trey Tacon <ttacon@gmail.com>
|
Trey Tacon <ttacon@gmail.com>
|
||||||
@ -186,6 +200,7 @@ Victor Vrantchan <vrancean+github@gmail.com>
|
|||||||
Vlad Ungureanu <vladu@palantir.com>
|
Vlad Ungureanu <vladu@palantir.com>
|
||||||
Will Maier <wcmaier@gmail.com>
|
Will Maier <wcmaier@gmail.com>
|
||||||
William Bailey <mail@williambailey.org.uk>
|
William Bailey <mail@williambailey.org.uk>
|
||||||
|
xibz <impactbchang@gmail.com>
|
||||||
Yann Malet <yann.malet@gmail.com>
|
Yann Malet <yann.malet@gmail.com>
|
||||||
Yannick Utard <yannickutard@gmail.com>
|
Yannick Utard <yannickutard@gmail.com>
|
||||||
Yicheng Qin <qycqycqycqycqyc@gmail.com>
|
Yicheng Qin <qycqycqycqycqyc@gmail.com>
|
||||||
|
2
vendor/github.com/google/go-github/github/activity_events.go
generated
vendored
2
vendor/github.com/google/go-github/github/activity_events.go
generated
vendored
@ -96,6 +96,8 @@ func (e *Event) ParsePayload() (payload interface{}, err error) {
|
|||||||
payload = &ReleaseEvent{}
|
payload = &ReleaseEvent{}
|
||||||
case "RepositoryEvent":
|
case "RepositoryEvent":
|
||||||
payload = &RepositoryEvent{}
|
payload = &RepositoryEvent{}
|
||||||
|
case "RepositoryVulnerabilityAlertEvent":
|
||||||
|
payload = &RepositoryVulnerabilityAlertEvent{}
|
||||||
case "StatusEvent":
|
case "StatusEvent":
|
||||||
payload = &StatusEvent{}
|
payload = &StatusEvent{}
|
||||||
case "TeamEvent":
|
case "TeamEvent":
|
||||||
|
6
vendor/github.com/google/go-github/github/activity_star.go
generated
vendored
6
vendor/github.com/google/go-github/github/activity_star.go
generated
vendored
@ -8,6 +8,7 @@ package github
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StarredRepository is returned by ListStarred.
|
// StarredRepository is returned by ListStarred.
|
||||||
@ -84,8 +85,9 @@ func (s *ActivityService) ListStarred(ctx context.Context, user string, opt *Act
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove custom Accept header when this API fully launches
|
// TODO: remove custom Accept header when APIs fully launch
|
||||||
req.Header.Set("Accept", mediaTypeStarringPreview)
|
acceptHeaders := []string{mediaTypeStarringPreview, mediaTypeTopicsPreview}
|
||||||
|
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
|
||||||
|
|
||||||
var repos []*StarredRepository
|
var repos []*StarredRepository
|
||||||
resp, err := s.client.Do(ctx, req, &repos)
|
resp, err := s.client.Do(ctx, req, &repos)
|
||||||
|
2
vendor/github.com/google/go-github/github/apps.go
generated
vendored
2
vendor/github.com/google/go-github/github/apps.go
generated
vendored
@ -164,7 +164,7 @@ func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOption
|
|||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token
|
// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token
|
||||||
func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64) (*InstallationToken, *Response, error) {
|
func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64) (*InstallationToken, *Response, error) {
|
||||||
u := fmt.Sprintf("installations/%v/access_tokens", id)
|
u := fmt.Sprintf("app/installations/%v/access_tokens", id)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("POST", u, nil)
|
req, err := s.client.NewRequest("POST", u, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
35
vendor/github.com/google/go-github/github/checks.go
generated
vendored
35
vendor/github.com/google/go-github/github/checks.go
generated
vendored
@ -19,6 +19,7 @@ type ChecksService service
|
|||||||
// CheckRun represents a GitHub check run on a repository associated with a GitHub app.
|
// CheckRun represents a GitHub check run on a repository associated with a GitHub app.
|
||||||
type CheckRun struct {
|
type CheckRun struct {
|
||||||
ID *int64 `json:"id,omitempty"`
|
ID *int64 `json:"id,omitempty"`
|
||||||
|
NodeID *string `json:"node_id,omitempty"`
|
||||||
HeadSHA *string `json:"head_sha,omitempty"`
|
HeadSHA *string `json:"head_sha,omitempty"`
|
||||||
ExternalID *string `json:"external_id,omitempty"`
|
ExternalID *string `json:"external_id,omitempty"`
|
||||||
URL *string `json:"url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
@ -47,14 +48,14 @@ type CheckRunOutput struct {
|
|||||||
|
|
||||||
// CheckRunAnnotation represents an annotation object for a CheckRun output.
|
// CheckRunAnnotation represents an annotation object for a CheckRun output.
|
||||||
type CheckRunAnnotation struct {
|
type CheckRunAnnotation struct {
|
||||||
FileName *string `json:"filename,omitempty"`
|
Path *string `json:"path,omitempty"`
|
||||||
BlobHRef *string `json:"blob_href,omitempty"`
|
BlobHRef *string `json:"blob_href,omitempty"`
|
||||||
StartLine *int `json:"start_line,omitempty"`
|
StartLine *int `json:"start_line,omitempty"`
|
||||||
EndLine *int `json:"end_line,omitempty"`
|
EndLine *int `json:"end_line,omitempty"`
|
||||||
WarningLevel *string `json:"warning_level,omitempty"`
|
AnnotationLevel *string `json:"annotation_level,omitempty"`
|
||||||
Message *string `json:"message,omitempty"`
|
Message *string `json:"message,omitempty"`
|
||||||
Title *string `json:"title,omitempty"`
|
Title *string `json:"title,omitempty"`
|
||||||
RawDetails *string `json:"raw_details,omitempty"`
|
RawDetails *string `json:"raw_details,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckRunImage represents an image object for a CheckRun output.
|
// CheckRunImage represents an image object for a CheckRun output.
|
||||||
@ -67,6 +68,7 @@ type CheckRunImage struct {
|
|||||||
// CheckSuite represents a suite of check runs.
|
// CheckSuite represents a suite of check runs.
|
||||||
type CheckSuite struct {
|
type CheckSuite struct {
|
||||||
ID *int64 `json:"id,omitempty"`
|
ID *int64 `json:"id,omitempty"`
|
||||||
|
NodeID *string `json:"node_id,omitempty"`
|
||||||
HeadBranch *string `json:"head_branch,omitempty"`
|
HeadBranch *string `json:"head_branch,omitempty"`
|
||||||
HeadSHA *string `json:"head_sha,omitempty"`
|
HeadSHA *string `json:"head_sha,omitempty"`
|
||||||
URL *string `json:"url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
@ -401,20 +403,11 @@ func (s *ChecksService) CreateCheckSuite(ctx context.Context, owner, repo string
|
|||||||
return checkSuite, resp, nil
|
return checkSuite, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestCheckSuiteOptions sets up the parameters for a request check suite endpoint.
|
// ReRequestCheckSuite triggers GitHub to rerequest an existing check suite, without pushing new code to a repository.
|
||||||
type RequestCheckSuiteOptions struct {
|
|
||||||
HeadSHA string `json:"head_sha"` // The sha of the head commit. (Required.)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestCheckSuite triggers GitHub to create a new check suite, without pushing new code to a repository.
|
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/checks/suites/#request-check-suites
|
// GitHub API docs: https://developer.github.com/v3/checks/suites/#rerequest-check-suite
|
||||||
func (s *ChecksService) RequestCheckSuite(ctx context.Context, owner, repo string, opt RequestCheckSuiteOptions) (*Response, error) {
|
func (s *ChecksService) ReRequestCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*Response, error) {
|
||||||
u := fmt.Sprintf("repos/%v/%v/check-suite-requests", owner, repo)
|
u := fmt.Sprintf("repos/%v/%v/check-suites/%v/rerequest", owner, repo, checkSuiteID)
|
||||||
u, err := addOptions(u, opt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := s.client.NewRequest("POST", u, nil)
|
req, err := s.client.NewRequest("POST", u, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
26
vendor/github.com/google/go-github/github/event_types.go
generated
vendored
26
vendor/github.com/google/go-github/github/event_types.go
generated
vendored
@ -519,6 +519,7 @@ type PullRequestEvent struct {
|
|||||||
// the pull request was closed with unmerged commits. If the action is "closed"
|
// the pull request was closed with unmerged commits. If the action is "closed"
|
||||||
// and the merged key is true, the pull request was merged.
|
// and the merged key is true, the pull request was merged.
|
||||||
Action *string `json:"action,omitempty"`
|
Action *string `json:"action,omitempty"`
|
||||||
|
Assignee *User `json:"assignee,omitempty"`
|
||||||
Number *int `json:"number,omitempty"`
|
Number *int `json:"number,omitempty"`
|
||||||
PullRequest *PullRequest `json:"pull_request,omitempty"`
|
PullRequest *PullRequest `json:"pull_request,omitempty"`
|
||||||
|
|
||||||
@ -532,6 +533,10 @@ type PullRequestEvent struct {
|
|||||||
Sender *User `json:"sender,omitempty"`
|
Sender *User `json:"sender,omitempty"`
|
||||||
Installation *Installation `json:"installation,omitempty"`
|
Installation *Installation `json:"installation,omitempty"`
|
||||||
Label *Label `json:"label,omitempty"` // Populated in "labeled" event deliveries.
|
Label *Label `json:"label,omitempty"` // Populated in "labeled" event deliveries.
|
||||||
|
|
||||||
|
// The following field is only present when the webhook is triggered on
|
||||||
|
// a repository belonging to an organization.
|
||||||
|
Organization *Organization `json:"organization,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PullRequestReviewEvent is triggered when a review is submitted on a pull
|
// PullRequestReviewEvent is triggered when a review is submitted on a pull
|
||||||
@ -705,6 +710,27 @@ type RepositoryEvent struct {
|
|||||||
Installation *Installation `json:"installation,omitempty"`
|
Installation *Installation `json:"installation,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepositoryVulnerabilityAlertEvent is triggered when a security alert is created, dismissed, or resolved.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositoryvulnerabilityalertevent
|
||||||
|
type RepositoryVulnerabilityAlertEvent struct {
|
||||||
|
// Action is the action that was performed. This can be: "create", "dismiss", "resolve".
|
||||||
|
Action *string `json:"action,omitempty"`
|
||||||
|
|
||||||
|
//The security alert of the vulnerable dependency.
|
||||||
|
Alert *struct {
|
||||||
|
ID *int64 `json:"id,omitempty"`
|
||||||
|
AffectedRange *string `json:"affected_range,omitempty"`
|
||||||
|
AffectedPackageName *string `json:"affected_package_name,omitempty"`
|
||||||
|
ExternalReference *string `json:"external_reference,omitempty"`
|
||||||
|
ExternalIdentifier *string `json:"external_identifier,omitempty"`
|
||||||
|
FixedIn *string `json:"fixed_in,omitempty"`
|
||||||
|
Dismisser *User `json:"dismisser,omitempty"`
|
||||||
|
DismissReason *string `json:"dismiss_reason,omitempty"`
|
||||||
|
DismissedAt *Timestamp `json:"dismissed_at,omitempty"`
|
||||||
|
} `json:"alert,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// StatusEvent is triggered when the status of a Git commit changes.
|
// StatusEvent is triggered when the status of a Git commit changes.
|
||||||
// The Webhook event name is "status".
|
// The Webhook event name is "status".
|
||||||
//
|
//
|
||||||
|
2
vendor/github.com/google/go-github/github/git_commits.go
generated
vendored
2
vendor/github.com/google/go-github/github/git_commits.go
generated
vendored
@ -58,7 +58,7 @@ func (c CommitAuthor) String() string {
|
|||||||
return Stringify(c)
|
return Stringify(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommit fetchs the Commit object for a given SHA.
|
// GetCommit fetches the Commit object for a given SHA.
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/git/commits/#get-a-commit
|
// GitHub API docs: https://developer.github.com/v3/git/commits/#get-a-commit
|
||||||
func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, sha string) (*Commit, *Response, error) {
|
func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, sha string) (*Commit, *Response, error) {
|
||||||
|
2
vendor/github.com/google/go-github/github/git_tags.go
generated
vendored
2
vendor/github.com/google/go-github/github/git_tags.go
generated
vendored
@ -33,7 +33,7 @@ type createTagRequest struct {
|
|||||||
Tagger *CommitAuthor `json:"tagger,omitempty"`
|
Tagger *CommitAuthor `json:"tagger,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTag fetchs a tag from a repo given a SHA.
|
// GetTag fetches a tag from a repo given a SHA.
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/git/tags/#get-a-tag
|
// GitHub API docs: https://developer.github.com/v3/git/tags/#get-a-tag
|
||||||
func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) {
|
func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) {
|
||||||
|
216
vendor/github.com/google/go-github/github/github-accessors.go
generated
vendored
216
vendor/github.com/google/go-github/github/github-accessors.go
generated
vendored
@ -532,6 +532,14 @@ func (c *CheckRun) GetName() string {
|
|||||||
return *c.Name
|
return *c.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise.
|
||||||
|
func (c *CheckRun) GetNodeID() string {
|
||||||
|
if c == nil || c.NodeID == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *c.NodeID
|
||||||
|
}
|
||||||
|
|
||||||
// GetOutput returns the Output field.
|
// GetOutput returns the Output field.
|
||||||
func (c *CheckRun) GetOutput() *CheckRunOutput {
|
func (c *CheckRun) GetOutput() *CheckRunOutput {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
@ -564,6 +572,14 @@ func (c *CheckRun) GetURL() string {
|
|||||||
return *c.URL
|
return *c.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAnnotationLevel returns the AnnotationLevel field if it's non-nil, zero value otherwise.
|
||||||
|
func (c *CheckRunAnnotation) GetAnnotationLevel() string {
|
||||||
|
if c == nil || c.AnnotationLevel == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *c.AnnotationLevel
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlobHRef returns the BlobHRef field if it's non-nil, zero value otherwise.
|
// GetBlobHRef returns the BlobHRef field if it's non-nil, zero value otherwise.
|
||||||
func (c *CheckRunAnnotation) GetBlobHRef() string {
|
func (c *CheckRunAnnotation) GetBlobHRef() string {
|
||||||
if c == nil || c.BlobHRef == nil {
|
if c == nil || c.BlobHRef == nil {
|
||||||
@ -580,14 +596,6 @@ func (c *CheckRunAnnotation) GetEndLine() int {
|
|||||||
return *c.EndLine
|
return *c.EndLine
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFileName returns the FileName field if it's non-nil, zero value otherwise.
|
|
||||||
func (c *CheckRunAnnotation) GetFileName() string {
|
|
||||||
if c == nil || c.FileName == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return *c.FileName
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMessage returns the Message field if it's non-nil, zero value otherwise.
|
// GetMessage returns the Message field if it's non-nil, zero value otherwise.
|
||||||
func (c *CheckRunAnnotation) GetMessage() string {
|
func (c *CheckRunAnnotation) GetMessage() string {
|
||||||
if c == nil || c.Message == nil {
|
if c == nil || c.Message == nil {
|
||||||
@ -596,6 +604,14 @@ func (c *CheckRunAnnotation) GetMessage() string {
|
|||||||
return *c.Message
|
return *c.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPath returns the Path field if it's non-nil, zero value otherwise.
|
||||||
|
func (c *CheckRunAnnotation) GetPath() string {
|
||||||
|
if c == nil || c.Path == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *c.Path
|
||||||
|
}
|
||||||
|
|
||||||
// GetRawDetails returns the RawDetails field if it's non-nil, zero value otherwise.
|
// GetRawDetails returns the RawDetails field if it's non-nil, zero value otherwise.
|
||||||
func (c *CheckRunAnnotation) GetRawDetails() string {
|
func (c *CheckRunAnnotation) GetRawDetails() string {
|
||||||
if c == nil || c.RawDetails == nil {
|
if c == nil || c.RawDetails == nil {
|
||||||
@ -620,14 +636,6 @@ func (c *CheckRunAnnotation) GetTitle() string {
|
|||||||
return *c.Title
|
return *c.Title
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWarningLevel returns the WarningLevel field if it's non-nil, zero value otherwise.
|
|
||||||
func (c *CheckRunAnnotation) GetWarningLevel() string {
|
|
||||||
if c == nil || c.WarningLevel == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return *c.WarningLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAction returns the Action field if it's non-nil, zero value otherwise.
|
// GetAction returns the Action field if it's non-nil, zero value otherwise.
|
||||||
func (c *CheckRunEvent) GetAction() string {
|
func (c *CheckRunEvent) GetAction() string {
|
||||||
if c == nil || c.Action == nil {
|
if c == nil || c.Action == nil {
|
||||||
@ -796,6 +804,14 @@ func (c *CheckSuite) GetID() int64 {
|
|||||||
return *c.ID
|
return *c.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise.
|
||||||
|
func (c *CheckSuite) GetNodeID() string {
|
||||||
|
if c == nil || c.NodeID == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *c.NodeID
|
||||||
|
}
|
||||||
|
|
||||||
// GetRepository returns the Repository field.
|
// GetRepository returns the Repository field.
|
||||||
func (c *CheckSuite) GetRepository() *Repository {
|
func (c *CheckSuite) GetRepository() *Repository {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
@ -2380,6 +2396,14 @@ func (d *DiscussionComment) GetNumber() int {
|
|||||||
return *d.Number
|
return *d.Number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetReactions returns the Reactions field.
|
||||||
|
func (d *DiscussionComment) GetReactions() *Reactions {
|
||||||
|
if d == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.Reactions
|
||||||
|
}
|
||||||
|
|
||||||
// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
|
// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
|
||||||
func (d *DiscussionComment) GetUpdatedAt() Timestamp {
|
func (d *DiscussionComment) GetUpdatedAt() Timestamp {
|
||||||
if d == nil || d.UpdatedAt == nil {
|
if d == nil || d.UpdatedAt == nil {
|
||||||
@ -3116,14 +3140,6 @@ func (h *Hook) GetID() int64 {
|
|||||||
return *h.ID
|
return *h.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the Name field if it's non-nil, zero value otherwise.
|
|
||||||
func (h *Hook) GetName() string {
|
|
||||||
if h == nil || h.Name == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return *h.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
|
// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
|
||||||
func (h *Hook) GetUpdatedAt() time.Time {
|
func (h *Hook) GetUpdatedAt() time.Time {
|
||||||
if h == nil || h.UpdatedAt == nil {
|
if h == nil || h.UpdatedAt == nil {
|
||||||
@ -3860,6 +3876,14 @@ func (i *IssueComment) GetIssueURL() string {
|
|||||||
return *i.IssueURL
|
return *i.IssueURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise.
|
||||||
|
func (i *IssueComment) GetNodeID() string {
|
||||||
|
if i == nil || i.NodeID == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *i.NodeID
|
||||||
|
}
|
||||||
|
|
||||||
// GetReactions returns the Reactions field.
|
// GetReactions returns the Reactions field.
|
||||||
func (i *IssueComment) GetReactions() *Reactions {
|
func (i *IssueComment) GetReactions() *Reactions {
|
||||||
if i == nil {
|
if i == nil {
|
||||||
@ -5524,6 +5548,22 @@ func (o *Organization) GetCreatedAt() time.Time {
|
|||||||
return *o.CreatedAt
|
return *o.CreatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDefaultRepoPermission returns the DefaultRepoPermission field if it's non-nil, zero value otherwise.
|
||||||
|
func (o *Organization) GetDefaultRepoPermission() string {
|
||||||
|
if o == nil || o.DefaultRepoPermission == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *o.DefaultRepoPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultRepoSettings returns the DefaultRepoSettings field if it's non-nil, zero value otherwise.
|
||||||
|
func (o *Organization) GetDefaultRepoSettings() string {
|
||||||
|
if o == nil || o.DefaultRepoSettings == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *o.DefaultRepoSettings
|
||||||
|
}
|
||||||
|
|
||||||
// GetDescription returns the Description field if it's non-nil, zero value otherwise.
|
// GetDescription returns the Description field if it's non-nil, zero value otherwise.
|
||||||
func (o *Organization) GetDescription() string {
|
func (o *Organization) GetDescription() string {
|
||||||
if o == nil || o.Description == nil {
|
if o == nil || o.Description == nil {
|
||||||
@ -5620,6 +5660,14 @@ func (o *Organization) GetLogin() string {
|
|||||||
return *o.Login
|
return *o.Login
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMembersCanCreateRepos returns the MembersCanCreateRepos field if it's non-nil, zero value otherwise.
|
||||||
|
func (o *Organization) GetMembersCanCreateRepos() bool {
|
||||||
|
if o == nil || o.MembersCanCreateRepos == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return *o.MembersCanCreateRepos
|
||||||
|
}
|
||||||
|
|
||||||
// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise.
|
// GetMembersURL returns the MembersURL field if it's non-nil, zero value otherwise.
|
||||||
func (o *Organization) GetMembersURL() string {
|
func (o *Organization) GetMembersURL() string {
|
||||||
if o == nil || o.MembersURL == nil {
|
if o == nil || o.MembersURL == nil {
|
||||||
@ -5708,6 +5756,14 @@ func (o *Organization) GetTotalPrivateRepos() int {
|
|||||||
return *o.TotalPrivateRepos
|
return *o.TotalPrivateRepos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTwoFactorRequirementEnabled returns the TwoFactorRequirementEnabled field if it's non-nil, zero value otherwise.
|
||||||
|
func (o *Organization) GetTwoFactorRequirementEnabled() bool {
|
||||||
|
if o == nil || o.TwoFactorRequirementEnabled == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return *o.TwoFactorRequirementEnabled
|
||||||
|
}
|
||||||
|
|
||||||
// GetType returns the Type field if it's non-nil, zero value otherwise.
|
// GetType returns the Type field if it's non-nil, zero value otherwise.
|
||||||
func (o *Organization) GetType() string {
|
func (o *Organization) GetType() string {
|
||||||
if o == nil || o.Type == nil {
|
if o == nil || o.Type == nil {
|
||||||
@ -6156,6 +6212,78 @@ func (p *PreReceiveHook) GetName() string {
|
|||||||
return *p.Name
|
return *p.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHRef returns the HRef field if it's non-nil, zero value otherwise.
|
||||||
|
func (p *PRLink) GetHRef() string {
|
||||||
|
if p == nil || p.HRef == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *p.HRef
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetComments returns the Comments field.
|
||||||
|
func (p *PRLinks) GetComments() *PRLink {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Comments
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommits returns the Commits field.
|
||||||
|
func (p *PRLinks) GetCommits() *PRLink {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Commits
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHTML returns the HTML field.
|
||||||
|
func (p *PRLinks) GetHTML() *PRLink {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.HTML
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssue returns the Issue field.
|
||||||
|
func (p *PRLinks) GetIssue() *PRLink {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Issue
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReviewComment returns the ReviewComment field.
|
||||||
|
func (p *PRLinks) GetReviewComment() *PRLink {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.ReviewComment
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReviewComments returns the ReviewComments field.
|
||||||
|
func (p *PRLinks) GetReviewComments() *PRLink {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.ReviewComments
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSelf returns the Self field.
|
||||||
|
func (p *PRLinks) GetSelf() *PRLink {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Self
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStatuses returns the Statuses field.
|
||||||
|
func (p *PRLinks) GetStatuses() *PRLink {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Statuses
|
||||||
|
}
|
||||||
|
|
||||||
// GetBody returns the Body field if it's non-nil, zero value otherwise.
|
// GetBody returns the Body field if it's non-nil, zero value otherwise.
|
||||||
func (p *Project) GetBody() string {
|
func (p *Project) GetBody() string {
|
||||||
if p == nil || p.Body == nil {
|
if p == nil || p.Body == nil {
|
||||||
@ -6884,6 +7012,14 @@ func (p *PullRequest) GetIssueURL() string {
|
|||||||
return *p.IssueURL
|
return *p.IssueURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLinks returns the Links field.
|
||||||
|
func (p *PullRequest) GetLinks() *PRLinks {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Links
|
||||||
|
}
|
||||||
|
|
||||||
// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise.
|
// GetMaintainerCanModify returns the MaintainerCanModify field if it's non-nil, zero value otherwise.
|
||||||
func (p *PullRequest) GetMaintainerCanModify() bool {
|
func (p *PullRequest) GetMaintainerCanModify() bool {
|
||||||
if p == nil || p.MaintainerCanModify == nil {
|
if p == nil || p.MaintainerCanModify == nil {
|
||||||
@ -7228,6 +7364,14 @@ func (p *PullRequestEvent) GetAction() string {
|
|||||||
return *p.Action
|
return *p.Action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAssignee returns the Assignee field.
|
||||||
|
func (p *PullRequestEvent) GetAssignee() *User {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Assignee
|
||||||
|
}
|
||||||
|
|
||||||
// GetChanges returns the Changes field.
|
// GetChanges returns the Changes field.
|
||||||
func (p *PullRequestEvent) GetChanges() *EditChange {
|
func (p *PullRequestEvent) GetChanges() *EditChange {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
@ -7260,6 +7404,14 @@ func (p *PullRequestEvent) GetNumber() int {
|
|||||||
return *p.Number
|
return *p.Number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOrganization returns the Organization field.
|
||||||
|
func (p *PullRequestEvent) GetOrganization() *Organization {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Organization
|
||||||
|
}
|
||||||
|
|
||||||
// GetPullRequest returns the PullRequest field.
|
// GetPullRequest returns the PullRequest field.
|
||||||
func (p *PullRequestEvent) GetPullRequest() *PullRequest {
|
func (p *PullRequestEvent) GetPullRequest() *PullRequest {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
@ -9804,6 +9956,14 @@ func (r *RepositoryTag) GetZipballURL() string {
|
|||||||
return *r.ZipballURL
|
return *r.ZipballURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAction returns the Action field if it's non-nil, zero value otherwise.
|
||||||
|
func (r *RepositoryVulnerabilityAlertEvent) GetAction() string {
|
||||||
|
if r == nil || r.Action == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *r.Action
|
||||||
|
}
|
||||||
|
|
||||||
// GetForkRepos returns the ForkRepos field if it's non-nil, zero value otherwise.
|
// GetForkRepos returns the ForkRepos field if it's non-nil, zero value otherwise.
|
||||||
func (r *RepoStats) GetForkRepos() int {
|
func (r *RepoStats) GetForkRepos() int {
|
||||||
if r == nil || r.ForkRepos == nil {
|
if r == nil || r.ForkRepos == nil {
|
||||||
@ -10564,6 +10724,14 @@ func (t *TeamDiscussion) GetPrivate() bool {
|
|||||||
return *t.Private
|
return *t.Private
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetReactions returns the Reactions field.
|
||||||
|
func (t *TeamDiscussion) GetReactions() *Reactions {
|
||||||
|
if t == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return t.Reactions
|
||||||
|
}
|
||||||
|
|
||||||
// GetTeamURL returns the TeamURL field if it's non-nil, zero value otherwise.
|
// GetTeamURL returns the TeamURL field if it's non-nil, zero value otherwise.
|
||||||
func (t *TeamDiscussion) GetTeamURL() string {
|
func (t *TeamDiscussion) GetTeamURL() string {
|
||||||
if t == nil || t.TeamURL == nil {
|
if t == nil || t.TeamURL == nil {
|
||||||
|
31
vendor/github.com/google/go-github/github/github.go
generated
vendored
31
vendor/github.com/google/go-github/github/github.go
generated
vendored
@ -375,7 +375,9 @@ type Response struct {
|
|||||||
FirstPage int
|
FirstPage int
|
||||||
LastPage int
|
LastPage int
|
||||||
|
|
||||||
Rate
|
// Explicitly specify the Rate type so Rate's String() receiver doesn't
|
||||||
|
// propagate to Response.
|
||||||
|
Rate Rate
|
||||||
}
|
}
|
||||||
|
|
||||||
// newResponse creates a new Response for the provided http.Response.
|
// newResponse creates a new Response for the provided http.Response.
|
||||||
@ -500,13 +502,23 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
|
|||||||
|
|
||||||
err = CheckResponse(resp)
|
err = CheckResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Even though there was an error, we still return the response
|
// Special case for AcceptedErrors. If an AcceptedError
|
||||||
// in case the caller wants to inspect it further.
|
// has been encountered, the response's payload will be
|
||||||
// However, if the error is AcceptedError, decode it below before
|
// added to the AcceptedError and returned.
|
||||||
// returning from this function and closing the response body.
|
//
|
||||||
if _, ok := err.(*AcceptedError); !ok {
|
// Issue #1022
|
||||||
return response, err
|
aerr, ok := err.(*AcceptedError)
|
||||||
|
if ok {
|
||||||
|
b, readErr := ioutil.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
return response, readErr
|
||||||
|
}
|
||||||
|
|
||||||
|
aerr.Raw = b
|
||||||
|
return response, aerr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if v != nil {
|
if v != nil {
|
||||||
@ -608,7 +620,10 @@ func (r *RateLimitError) Error() string {
|
|||||||
// Technically, 202 Accepted is not a real error, it's just used to
|
// Technically, 202 Accepted is not a real error, it's just used to
|
||||||
// indicate that results are not ready yet, but should be available soon.
|
// indicate that results are not ready yet, but should be available soon.
|
||||||
// The request can be repeated after some time.
|
// The request can be repeated after some time.
|
||||||
type AcceptedError struct{}
|
type AcceptedError struct {
|
||||||
|
// Raw contains the response body.
|
||||||
|
Raw []byte
|
||||||
|
}
|
||||||
|
|
||||||
func (*AcceptedError) Error() string {
|
func (*AcceptedError) Error() string {
|
||||||
return "job scheduled on GitHub side; try again later"
|
return "job scheduled on GitHub side; try again later"
|
||||||
|
2
vendor/github.com/google/go-github/github/issues.go
generated
vendored
2
vendor/github.com/google/go-github/github/issues.go
generated
vendored
@ -228,7 +228,7 @@ func (s *IssuesService) ListByRepo(ctx context.Context, owner string, repo strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove custom Accept headers when APIs fully launch.
|
// TODO: remove custom Accept headers when APIs fully launch.
|
||||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
|
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeIntegrationPreview}
|
||||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
|
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
|
||||||
|
|
||||||
var issues []*Issue
|
var issues []*Issue
|
||||||
|
1
vendor/github.com/google/go-github/github/issues_comments.go
generated
vendored
1
vendor/github.com/google/go-github/github/issues_comments.go
generated
vendored
@ -14,6 +14,7 @@ import (
|
|||||||
// IssueComment represents a comment left on an issue.
|
// IssueComment represents a comment left on an issue.
|
||||||
type IssueComment struct {
|
type IssueComment struct {
|
||||||
ID *int64 `json:"id,omitempty"`
|
ID *int64 `json:"id,omitempty"`
|
||||||
|
NodeID *string `json:"node_id,omitempty"`
|
||||||
Body *string `json:"body,omitempty"`
|
Body *string `json:"body,omitempty"`
|
||||||
User *User `json:"user,omitempty"`
|
User *User `json:"user,omitempty"`
|
||||||
Reactions *Reactions `json:"reactions,omitempty"`
|
Reactions *Reactions `json:"reactions,omitempty"`
|
||||||
|
79
vendor/github.com/google/go-github/github/messages.go
generated
vendored
79
vendor/github.com/google/go-github/github/messages.go
generated
vendored
@ -41,42 +41,43 @@ const (
|
|||||||
var (
|
var (
|
||||||
// eventTypeMapping maps webhooks types to their corresponding go-github struct types.
|
// eventTypeMapping maps webhooks types to their corresponding go-github struct types.
|
||||||
eventTypeMapping = map[string]string{
|
eventTypeMapping = map[string]string{
|
||||||
"check_run": "CheckRunEvent",
|
"check_run": "CheckRunEvent",
|
||||||
"check_suite": "CheckSuiteEvent",
|
"check_suite": "CheckSuiteEvent",
|
||||||
"commit_comment": "CommitCommentEvent",
|
"commit_comment": "CommitCommentEvent",
|
||||||
"create": "CreateEvent",
|
"create": "CreateEvent",
|
||||||
"delete": "DeleteEvent",
|
"delete": "DeleteEvent",
|
||||||
"deployment": "DeploymentEvent",
|
"deployment": "DeploymentEvent",
|
||||||
"deployment_status": "DeploymentStatusEvent",
|
"deployment_status": "DeploymentStatusEvent",
|
||||||
"fork": "ForkEvent",
|
"fork": "ForkEvent",
|
||||||
"gollum": "GollumEvent",
|
"gollum": "GollumEvent",
|
||||||
"installation": "InstallationEvent",
|
"installation": "InstallationEvent",
|
||||||
"installation_repositories": "InstallationRepositoriesEvent",
|
"installation_repositories": "InstallationRepositoriesEvent",
|
||||||
"issue_comment": "IssueCommentEvent",
|
"issue_comment": "IssueCommentEvent",
|
||||||
"issues": "IssuesEvent",
|
"issues": "IssuesEvent",
|
||||||
"label": "LabelEvent",
|
"label": "LabelEvent",
|
||||||
"marketplace_purchase": "MarketplacePurchaseEvent",
|
"marketplace_purchase": "MarketplacePurchaseEvent",
|
||||||
"member": "MemberEvent",
|
"member": "MemberEvent",
|
||||||
"membership": "MembershipEvent",
|
"membership": "MembershipEvent",
|
||||||
"milestone": "MilestoneEvent",
|
"milestone": "MilestoneEvent",
|
||||||
"organization": "OrganizationEvent",
|
"organization": "OrganizationEvent",
|
||||||
"org_block": "OrgBlockEvent",
|
"org_block": "OrgBlockEvent",
|
||||||
"page_build": "PageBuildEvent",
|
"page_build": "PageBuildEvent",
|
||||||
"ping": "PingEvent",
|
"ping": "PingEvent",
|
||||||
"project": "ProjectEvent",
|
"project": "ProjectEvent",
|
||||||
"project_card": "ProjectCardEvent",
|
"project_card": "ProjectCardEvent",
|
||||||
"project_column": "ProjectColumnEvent",
|
"project_column": "ProjectColumnEvent",
|
||||||
"public": "PublicEvent",
|
"public": "PublicEvent",
|
||||||
"pull_request_review": "PullRequestReviewEvent",
|
"pull_request_review": "PullRequestReviewEvent",
|
||||||
"pull_request_review_comment": "PullRequestReviewCommentEvent",
|
"pull_request_review_comment": "PullRequestReviewCommentEvent",
|
||||||
"pull_request": "PullRequestEvent",
|
"pull_request": "PullRequestEvent",
|
||||||
"push": "PushEvent",
|
"push": "PushEvent",
|
||||||
"repository": "RepositoryEvent",
|
"repository": "RepositoryEvent",
|
||||||
"release": "ReleaseEvent",
|
"repository_vulnerability_alert": "RepositoryVulnerabilityAlertEvent",
|
||||||
"status": "StatusEvent",
|
"release": "ReleaseEvent",
|
||||||
"team": "TeamEvent",
|
"status": "StatusEvent",
|
||||||
"team_add": "TeamAddEvent",
|
"team": "TeamEvent",
|
||||||
"watch": "WatchEvent",
|
"team_add": "TeamAddEvent",
|
||||||
|
"watch": "WatchEvent",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -175,19 +176,19 @@ func ValidatePayload(r *http.Request, secretKey []byte) (payload []byte, err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
sig := r.Header.Get(signatureHeader)
|
sig := r.Header.Get(signatureHeader)
|
||||||
if err := validateSignature(sig, body, secretKey); err != nil {
|
if err := ValidateSignature(sig, body, secretKey); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateSignature validates the signature for the given payload.
|
// ValidateSignature validates the signature for the given payload.
|
||||||
// signature is the GitHub hash signature delivered in the X-Hub-Signature header.
|
// signature is the GitHub hash signature delivered in the X-Hub-Signature header.
|
||||||
// payload is the JSON payload sent by GitHub Webhooks.
|
// payload is the JSON payload sent by GitHub Webhooks.
|
||||||
// secretKey is the GitHub Webhook secret message.
|
// secretKey is the GitHub Webhook secret message.
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
|
// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
|
||||||
func validateSignature(signature string, payload, secretKey []byte) error {
|
func ValidateSignature(signature string, payload, secretKey []byte) error {
|
||||||
messageMAC, hashFunc, err := messageMAC(signature)
|
messageMAC, hashFunc, err := messageMAC(signature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
61
vendor/github.com/google/go-github/github/orgs.go
generated
vendored
61
vendor/github.com/google/go-github/github/orgs.go
generated
vendored
@ -19,31 +19,42 @@ type OrganizationsService service
|
|||||||
|
|
||||||
// Organization represents a GitHub organization account.
|
// Organization represents a GitHub organization account.
|
||||||
type Organization struct {
|
type Organization struct {
|
||||||
Login *string `json:"login,omitempty"`
|
Login *string `json:"login,omitempty"`
|
||||||
ID *int64 `json:"id,omitempty"`
|
ID *int64 `json:"id,omitempty"`
|
||||||
NodeID *string `json:"node_id,omitempty"`
|
NodeID *string `json:"node_id,omitempty"`
|
||||||
AvatarURL *string `json:"avatar_url,omitempty"`
|
AvatarURL *string `json:"avatar_url,omitempty"`
|
||||||
HTMLURL *string `json:"html_url,omitempty"`
|
HTMLURL *string `json:"html_url,omitempty"`
|
||||||
Name *string `json:"name,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
Company *string `json:"company,omitempty"`
|
Company *string `json:"company,omitempty"`
|
||||||
Blog *string `json:"blog,omitempty"`
|
Blog *string `json:"blog,omitempty"`
|
||||||
Location *string `json:"location,omitempty"`
|
Location *string `json:"location,omitempty"`
|
||||||
Email *string `json:"email,omitempty"`
|
Email *string `json:"email,omitempty"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
PublicRepos *int `json:"public_repos,omitempty"`
|
PublicRepos *int `json:"public_repos,omitempty"`
|
||||||
PublicGists *int `json:"public_gists,omitempty"`
|
PublicGists *int `json:"public_gists,omitempty"`
|
||||||
Followers *int `json:"followers,omitempty"`
|
Followers *int `json:"followers,omitempty"`
|
||||||
Following *int `json:"following,omitempty"`
|
Following *int `json:"following,omitempty"`
|
||||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
TotalPrivateRepos *int `json:"total_private_repos,omitempty"`
|
TotalPrivateRepos *int `json:"total_private_repos,omitempty"`
|
||||||
OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"`
|
OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"`
|
||||||
PrivateGists *int `json:"private_gists,omitempty"`
|
PrivateGists *int `json:"private_gists,omitempty"`
|
||||||
DiskUsage *int `json:"disk_usage,omitempty"`
|
DiskUsage *int `json:"disk_usage,omitempty"`
|
||||||
Collaborators *int `json:"collaborators,omitempty"`
|
Collaborators *int `json:"collaborators,omitempty"`
|
||||||
BillingEmail *string `json:"billing_email,omitempty"`
|
BillingEmail *string `json:"billing_email,omitempty"`
|
||||||
Type *string `json:"type,omitempty"`
|
Type *string `json:"type,omitempty"`
|
||||||
Plan *Plan `json:"plan,omitempty"`
|
Plan *Plan `json:"plan,omitempty"`
|
||||||
|
TwoFactorRequirementEnabled *bool `json:"two_factor_requirement_enabled,omitempty"`
|
||||||
|
|
||||||
|
// DefaultRepoPermission can be one of: "read", "write", "admin", or "none". (Default: "read").
|
||||||
|
// It is only used in OrganizationsService.Edit.
|
||||||
|
DefaultRepoPermission *string `json:"default_repository_permission,omitempty"`
|
||||||
|
// DefaultRepoSettings can be one of: "read", "write", "admin", or "none". (Default: "read").
|
||||||
|
// It is only used in OrganizationsService.Get.
|
||||||
|
DefaultRepoSettings *string `json:"default_repository_settings,omitempty"`
|
||||||
|
|
||||||
|
// MembersCanCreateRepos default value is true and is only used in Organizations.Edit.
|
||||||
|
MembersCanCreateRepos *bool `json:"members_can_create_repositories,omitempty"`
|
||||||
|
|
||||||
// API URLs
|
// API URLs
|
||||||
URL *string `json:"url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
|
14
vendor/github.com/google/go-github/github/orgs_hooks.go
generated
vendored
14
vendor/github.com/google/go-github/github/orgs_hooks.go
generated
vendored
@ -49,12 +49,22 @@ func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int64
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateHook creates a Hook for the specified org.
|
// CreateHook creates a Hook for the specified org.
|
||||||
// Name and Config are required fields.
|
// Config is a required field.
|
||||||
|
//
|
||||||
|
// Note that only a subset of the hook fields are used and hook must
|
||||||
|
// not be nil.
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook
|
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook
|
||||||
func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook *Hook) (*Hook, *Response, error) {
|
func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook *Hook) (*Hook, *Response, error) {
|
||||||
u := fmt.Sprintf("orgs/%v/hooks", org)
|
u := fmt.Sprintf("orgs/%v/hooks", org)
|
||||||
req, err := s.client.NewRequest("POST", u, hook)
|
|
||||||
|
hookReq := &createHookRequest{
|
||||||
|
Events: hook.Events,
|
||||||
|
Active: hook.Active,
|
||||||
|
Config: hook.Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, hookReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
26
vendor/github.com/google/go-github/github/pulls.go
generated
vendored
26
vendor/github.com/google/go-github/github/pulls.go
generated
vendored
@ -60,8 +60,13 @@ type PullRequest struct {
|
|||||||
NodeID *string `json:"node_id,omitempty"`
|
NodeID *string `json:"node_id,omitempty"`
|
||||||
RequestedReviewers []*User `json:"requested_reviewers,omitempty"`
|
RequestedReviewers []*User `json:"requested_reviewers,omitempty"`
|
||||||
|
|
||||||
Head *PullRequestBranch `json:"head,omitempty"`
|
// RequestedTeams is populated as part of the PullRequestEvent.
|
||||||
Base *PullRequestBranch `json:"base,omitempty"`
|
// See, https://developer.github.com/v3/activity/events/types/#pullrequestevent for an example.
|
||||||
|
RequestedTeams []*Team `json:"requested_teams,omitempty"`
|
||||||
|
|
||||||
|
Links *PRLinks `json:"_links,omitempty"`
|
||||||
|
Head *PullRequestBranch `json:"head,omitempty"`
|
||||||
|
Base *PullRequestBranch `json:"base,omitempty"`
|
||||||
|
|
||||||
// ActiveLockReason is populated only when LockReason is provided while locking the pull request.
|
// ActiveLockReason is populated only when LockReason is provided while locking the pull request.
|
||||||
// Possible values are: "off-topic", "too heated", "resolved", and "spam".
|
// Possible values are: "off-topic", "too heated", "resolved", and "spam".
|
||||||
@ -72,6 +77,23 @@ func (p PullRequest) String() string {
|
|||||||
return Stringify(p)
|
return Stringify(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PRLink represents a single link object from Github pull request _links.
|
||||||
|
type PRLink struct {
|
||||||
|
HRef *string `json:"href,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRLinks represents the "_links" object in a Github pull request.
|
||||||
|
type PRLinks struct {
|
||||||
|
Self *PRLink `json:"self,omitempty"`
|
||||||
|
HTML *PRLink `json:"html,omitempty"`
|
||||||
|
Issue *PRLink `json:"issue,omitempty"`
|
||||||
|
Comments *PRLink `json:"comments,omitempty"`
|
||||||
|
ReviewComments *PRLink `json:"review_comments,omitempty"`
|
||||||
|
ReviewComment *PRLink `json:"review_comment,omitempty"`
|
||||||
|
Commits *PRLink `json:"commits,omitempty"`
|
||||||
|
Statuses *PRLink `json:"statuses,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// PullRequestBranch represents a base or head branch in a GitHub pull request.
|
// PullRequestBranch represents a base or head branch in a GitHub pull request.
|
||||||
type PullRequestBranch struct {
|
type PullRequestBranch struct {
|
||||||
Label *string `json:"label,omitempty"`
|
Label *string `json:"label,omitempty"`
|
||||||
|
101
vendor/github.com/google/go-github/github/reactions.go
generated
vendored
101
vendor/github.com/google/go-github/github/reactions.go
generated
vendored
@ -74,6 +74,7 @@ func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo
|
|||||||
// CreateCommentReaction creates a reaction for a commit comment.
|
// CreateCommentReaction creates a reaction for a commit comment.
|
||||||
// Note that if you have already created a reaction of type content, the
|
// Note that if you have already created a reaction of type content, the
|
||||||
// previously created reaction will be returned with Status: 200 OK.
|
// previously created reaction will be returned with Status: 200 OK.
|
||||||
|
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment
|
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment
|
||||||
func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
|
func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
|
||||||
@ -127,6 +128,7 @@ func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo s
|
|||||||
// CreateIssueReaction creates a reaction for an issue.
|
// CreateIssueReaction creates a reaction for an issue.
|
||||||
// Note that if you have already created a reaction of type content, the
|
// Note that if you have already created a reaction of type content, the
|
||||||
// previously created reaction will be returned with Status: 200 OK.
|
// previously created reaction will be returned with Status: 200 OK.
|
||||||
|
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue
|
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue
|
||||||
func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) {
|
func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) {
|
||||||
@ -180,6 +182,7 @@ func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner,
|
|||||||
// CreateIssueCommentReaction creates a reaction for an issue comment.
|
// CreateIssueCommentReaction creates a reaction for an issue comment.
|
||||||
// Note that if you have already created a reaction of type content, the
|
// Note that if you have already created a reaction of type content, the
|
||||||
// previously created reaction will be returned with Status: 200 OK.
|
// previously created reaction will be returned with Status: 200 OK.
|
||||||
|
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
|
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
|
||||||
func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
|
func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
|
||||||
@ -233,6 +236,7 @@ func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context,
|
|||||||
// CreatePullRequestCommentReaction creates a reaction for a pull request review comment.
|
// CreatePullRequestCommentReaction creates a reaction for a pull request review comment.
|
||||||
// Note that if you have already created a reaction of type content, the
|
// Note that if you have already created a reaction of type content, the
|
||||||
// previously created reaction will be returned with Status: 200 OK.
|
// previously created reaction will be returned with Status: 200 OK.
|
||||||
|
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
|
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
|
||||||
func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
|
func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
|
||||||
@ -256,6 +260,103 @@ func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context,
|
|||||||
return m, resp, nil
|
return m, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListTeamDiscussionReactions lists the reactions for a team discussion.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion
|
||||||
|
func (s *ReactionsService) ListTeamDiscussionReactions(ctx context.Context, teamID int64, discussionNumber int, opt *ListOptions) ([]*Reaction, *Response, error) {
|
||||||
|
u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber)
|
||||||
|
u, err := addOptions(u, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Accept", mediaTypeReactionsPreview)
|
||||||
|
|
||||||
|
var m []*Reaction
|
||||||
|
resp, err := s.client.Do(ctx, req, &m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTeamDiscussionReaction creates a reaction for a team discussion.
|
||||||
|
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion
|
||||||
|
func (s *ReactionsService) CreateTeamDiscussionReaction(ctx context.Context, teamID int64, discussionNumber int, content string) (*Reaction, *Response, error) {
|
||||||
|
u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber)
|
||||||
|
|
||||||
|
body := &Reaction{Content: String(content)}
|
||||||
|
req, err := s.client.NewRequest("POST", u, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Accept", mediaTypeReactionsPreview)
|
||||||
|
|
||||||
|
m := &Reaction{}
|
||||||
|
resp, err := s.client.Do(ctx, req, m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListTeamDiscussionCommentReactions lists the reactions for a team discussion comment.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion-comment
|
||||||
|
func (s *ReactionsService) ListTeamDiscussionCommentReactions(ctx context.Context, teamID int64, discussionNumber, commentNumber int, opt *ListOptions) ([]*Reaction, *Response, error) {
|
||||||
|
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber)
|
||||||
|
u, err := addOptions(u, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Accept", mediaTypeReactionsPreview)
|
||||||
|
|
||||||
|
var m []*Reaction
|
||||||
|
resp, err := s.client.Do(ctx, req, &m)
|
||||||
|
|
||||||
|
return m, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTeamDiscussionCommentReaction creates a reaction for a team discussion comment.
|
||||||
|
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion-comment
|
||||||
|
func (s *ReactionsService) CreateTeamDiscussionCommentReaction(ctx context.Context, teamID int64, discussionNumber, commentNumber int, content string) (*Reaction, *Response, error) {
|
||||||
|
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber)
|
||||||
|
|
||||||
|
body := &Reaction{Content: String(content)}
|
||||||
|
req, err := s.client.NewRequest("POST", u, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Accept", mediaTypeReactionsPreview)
|
||||||
|
|
||||||
|
m := &Reaction{}
|
||||||
|
resp, err := s.client.Do(ctx, req, m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteReaction deletes a reaction.
|
// DeleteReaction deletes a reaction.
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive
|
// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive
|
||||||
|
51
vendor/github.com/google/go-github/github/repos.go
generated
vendored
51
vendor/github.com/google/go-github/github/repos.go
generated
vendored
@ -56,6 +56,7 @@ type Repository struct {
|
|||||||
AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"`
|
AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"`
|
||||||
AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"`
|
AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"`
|
||||||
Topics []string `json:"topics,omitempty"`
|
Topics []string `json:"topics,omitempty"`
|
||||||
|
Archived *bool `json:"archived,omitempty"`
|
||||||
|
|
||||||
// Only provided when using RepositoriesService.Get while in preview
|
// Only provided when using RepositoriesService.Get while in preview
|
||||||
License *License `json:"license,omitempty"`
|
License *License `json:"license,omitempty"`
|
||||||
@ -69,7 +70,6 @@ type Repository struct {
|
|||||||
HasDownloads *bool `json:"has_downloads,omitempty"`
|
HasDownloads *bool `json:"has_downloads,omitempty"`
|
||||||
LicenseTemplate *string `json:"license_template,omitempty"`
|
LicenseTemplate *string `json:"license_template,omitempty"`
|
||||||
GitignoreTemplate *string `json:"gitignore_template,omitempty"`
|
GitignoreTemplate *string `json:"gitignore_template,omitempty"`
|
||||||
Archived *bool `json:"archived,omitempty"`
|
|
||||||
|
|
||||||
// Creating an organization repository. Required for non-owners.
|
// Creating an organization repository. Required for non-owners.
|
||||||
TeamID *int64 `json:"team_id,omitempty"`
|
TeamID *int64 `json:"team_id,omitempty"`
|
||||||
@ -259,10 +259,40 @@ func (s *RepositoriesService) ListAll(ctx context.Context, opt *RepositoryListAl
|
|||||||
return repos, resp, nil
|
return repos, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createRepoRequest is a subset of Repository and is used internally
|
||||||
|
// by Create to pass only the known fields for the endpoint.
|
||||||
|
//
|
||||||
|
// See https://github.com/google/go-github/issues/1014 for more
|
||||||
|
// information.
|
||||||
|
type createRepoRequest struct {
|
||||||
|
// Name is required when creating a repo.
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
Homepage *string `json:"homepage,omitempty"`
|
||||||
|
|
||||||
|
Private *bool `json:"private,omitempty"`
|
||||||
|
HasIssues *bool `json:"has_issues,omitempty"`
|
||||||
|
HasProjects *bool `json:"has_projects,omitempty"`
|
||||||
|
HasWiki *bool `json:"has_wiki,omitempty"`
|
||||||
|
|
||||||
|
// Creating an organization repository. Required for non-owners.
|
||||||
|
TeamID *int64 `json:"team_id,omitempty"`
|
||||||
|
|
||||||
|
AutoInit *bool `json:"auto_init,omitempty"`
|
||||||
|
GitignoreTemplate *string `json:"gitignore_template,omitempty"`
|
||||||
|
LicenseTemplate *string `json:"license_template,omitempty"`
|
||||||
|
AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"`
|
||||||
|
AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"`
|
||||||
|
AllowRebaseMerge *bool `json:"allow_rebase_merge,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new repository. If an organization is specified, the new
|
// Create a new repository. If an organization is specified, the new
|
||||||
// repository will be created under that org. If the empty string is
|
// repository will be created under that org. If the empty string is
|
||||||
// specified, it will be created for the authenticated user.
|
// specified, it will be created for the authenticated user.
|
||||||
//
|
//
|
||||||
|
// Note that only a subset of the repo fields are used and repo must
|
||||||
|
// not be nil.
|
||||||
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/repos/#create
|
// GitHub API docs: https://developer.github.com/v3/repos/#create
|
||||||
func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repository) (*Repository, *Response, error) {
|
func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repository) (*Repository, *Response, error) {
|
||||||
var u string
|
var u string
|
||||||
@ -272,7 +302,24 @@ func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repo
|
|||||||
u = "user/repos"
|
u = "user/repos"
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := s.client.NewRequest("POST", u, repo)
|
repoReq := &createRepoRequest{
|
||||||
|
Name: repo.Name,
|
||||||
|
Description: repo.Description,
|
||||||
|
Homepage: repo.Homepage,
|
||||||
|
Private: repo.Private,
|
||||||
|
HasIssues: repo.HasIssues,
|
||||||
|
HasProjects: repo.HasProjects,
|
||||||
|
HasWiki: repo.HasWiki,
|
||||||
|
TeamID: repo.TeamID,
|
||||||
|
AutoInit: repo.AutoInit,
|
||||||
|
GitignoreTemplate: repo.GitignoreTemplate,
|
||||||
|
LicenseTemplate: repo.LicenseTemplate,
|
||||||
|
AllowSquashMerge: repo.AllowSquashMerge,
|
||||||
|
AllowMergeCommit: repo.AllowMergeCommit,
|
||||||
|
AllowRebaseMerge: repo.AllowRebaseMerge,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, repoReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
13
vendor/github.com/google/go-github/github/repos_forks.go
generated
vendored
13
vendor/github.com/google/go-github/github/repos_forks.go
generated
vendored
@ -8,6 +8,8 @@ package github
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RepositoryListForksOptions specifies the optional parameters to the
|
// RepositoryListForksOptions specifies the optional parameters to the
|
||||||
@ -78,10 +80,15 @@ func (s *RepositoriesService) CreateFork(ctx context.Context, owner, repo string
|
|||||||
|
|
||||||
fork := new(Repository)
|
fork := new(Repository)
|
||||||
resp, err := s.client.Do(ctx, req, fork)
|
resp, err := s.client.Do(ctx, req, fork)
|
||||||
if _, ok := err.(*AcceptedError); ok {
|
|
||||||
return fork, resp, err
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Persist AcceptedError's metadata to the Repository object.
|
||||||
|
if aerr, ok := err.(*AcceptedError); ok {
|
||||||
|
if err := json.Unmarshal(aerr.Raw, fork); err != nil {
|
||||||
|
return fork, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fork, resp, err
|
||||||
|
}
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
44
vendor/github.com/google/go-github/github/repos_hooks.go
generated
vendored
44
vendor/github.com/google/go-github/github/repos_hooks.go
generated
vendored
@ -69,27 +69,51 @@ func (w WebHookAuthor) String() string {
|
|||||||
|
|
||||||
// Hook represents a GitHub (web and service) hook for a repository.
|
// Hook represents a GitHub (web and service) hook for a repository.
|
||||||
type Hook struct {
|
type Hook struct {
|
||||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
Name *string `json:"name,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
URL *string `json:"url,omitempty"`
|
ID *int64 `json:"id,omitempty"`
|
||||||
Events []string `json:"events,omitempty"`
|
|
||||||
Active *bool `json:"active,omitempty"`
|
// Only the following fields are used when creating a hook.
|
||||||
Config map[string]interface{} `json:"config,omitempty"`
|
// Config is required.
|
||||||
ID *int64 `json:"id,omitempty"`
|
Config map[string]interface{} `json:"config,omitempty"`
|
||||||
|
Events []string `json:"events,omitempty"`
|
||||||
|
Active *bool `json:"active,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Hook) String() string {
|
func (h Hook) String() string {
|
||||||
return Stringify(h)
|
return Stringify(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createHookRequest is a subset of Hook and is used internally
|
||||||
|
// by CreateHook to pass only the known fields for the endpoint.
|
||||||
|
//
|
||||||
|
// See https://github.com/google/go-github/issues/1015 for more
|
||||||
|
// information.
|
||||||
|
type createHookRequest struct {
|
||||||
|
// Config is required.
|
||||||
|
Config map[string]interface{} `json:"config,omitempty"`
|
||||||
|
Events []string `json:"events,omitempty"`
|
||||||
|
Active *bool `json:"active,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// CreateHook creates a Hook for the specified repository.
|
// CreateHook creates a Hook for the specified repository.
|
||||||
// Name and Config are required fields.
|
// Config is a required field.
|
||||||
|
//
|
||||||
|
// Note that only a subset of the hook fields are used and hook must
|
||||||
|
// not be nil.
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#create-a-hook
|
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#create-a-hook
|
||||||
func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string, hook *Hook) (*Hook, *Response, error) {
|
func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string, hook *Hook) (*Hook, *Response, error) {
|
||||||
u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo)
|
u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo)
|
||||||
req, err := s.client.NewRequest("POST", u, hook)
|
|
||||||
|
hookReq := &createHookRequest{
|
||||||
|
Events: hook.Events,
|
||||||
|
Active: hook.Active,
|
||||||
|
Config: hook.Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, hookReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
81
vendor/github.com/google/go-github/github/repos_releases.go
generated
vendored
81
vendor/github.com/google/go-github/github/repos_releases.go
generated
vendored
@ -19,24 +19,26 @@ import (
|
|||||||
|
|
||||||
// RepositoryRelease represents a GitHub release in a repository.
|
// RepositoryRelease represents a GitHub release in a repository.
|
||||||
type RepositoryRelease struct {
|
type RepositoryRelease struct {
|
||||||
ID *int64 `json:"id,omitempty"`
|
TagName *string `json:"tag_name,omitempty"`
|
||||||
TagName *string `json:"tag_name,omitempty"`
|
TargetCommitish *string `json:"target_commitish,omitempty"`
|
||||||
TargetCommitish *string `json:"target_commitish,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
Name *string `json:"name,omitempty"`
|
Body *string `json:"body,omitempty"`
|
||||||
Body *string `json:"body,omitempty"`
|
Draft *bool `json:"draft,omitempty"`
|
||||||
Draft *bool `json:"draft,omitempty"`
|
Prerelease *bool `json:"prerelease,omitempty"`
|
||||||
Prerelease *bool `json:"prerelease,omitempty"`
|
|
||||||
CreatedAt *Timestamp `json:"created_at,omitempty"`
|
// The following fields are not used in CreateRelease or EditRelease:
|
||||||
PublishedAt *Timestamp `json:"published_at,omitempty"`
|
ID *int64 `json:"id,omitempty"`
|
||||||
URL *string `json:"url,omitempty"`
|
CreatedAt *Timestamp `json:"created_at,omitempty"`
|
||||||
HTMLURL *string `json:"html_url,omitempty"`
|
PublishedAt *Timestamp `json:"published_at,omitempty"`
|
||||||
AssetsURL *string `json:"assets_url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
Assets []ReleaseAsset `json:"assets,omitempty"`
|
HTMLURL *string `json:"html_url,omitempty"`
|
||||||
UploadURL *string `json:"upload_url,omitempty"`
|
AssetsURL *string `json:"assets_url,omitempty"`
|
||||||
ZipballURL *string `json:"zipball_url,omitempty"`
|
Assets []ReleaseAsset `json:"assets,omitempty"`
|
||||||
TarballURL *string `json:"tarball_url,omitempty"`
|
UploadURL *string `json:"upload_url,omitempty"`
|
||||||
Author *User `json:"author,omitempty"`
|
ZipballURL *string `json:"zipball_url,omitempty"`
|
||||||
NodeID *string `json:"node_id,omitempty"`
|
TarballURL *string `json:"tarball_url,omitempty"`
|
||||||
|
Author *User `json:"author,omitempty"`
|
||||||
|
NodeID *string `json:"node_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r RepositoryRelease) String() string {
|
func (r RepositoryRelease) String() string {
|
||||||
@ -125,13 +127,40 @@ func (s *RepositoriesService) getSingleRelease(ctx context.Context, url string)
|
|||||||
return release, resp, nil
|
return release, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// repositoryReleaseRequest is a subset of RepositoryRelease and
|
||||||
|
// is used internally by CreateRelease and EditRelease to pass
|
||||||
|
// only the known fields for these endpoints.
|
||||||
|
//
|
||||||
|
// See https://github.com/google/go-github/issues/992 for more
|
||||||
|
// information.
|
||||||
|
type repositoryReleaseRequest struct {
|
||||||
|
TagName *string `json:"tag_name,omitempty"`
|
||||||
|
TargetCommitish *string `json:"target_commitish,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Body *string `json:"body,omitempty"`
|
||||||
|
Draft *bool `json:"draft,omitempty"`
|
||||||
|
Prerelease *bool `json:"prerelease,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// CreateRelease adds a new release for a repository.
|
// CreateRelease adds a new release for a repository.
|
||||||
//
|
//
|
||||||
|
// Note that only a subset of the release fields are used.
|
||||||
|
// See RepositoryRelease for more information.
|
||||||
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#create-a-release
|
// GitHub API docs: https://developer.github.com/v3/repos/releases/#create-a-release
|
||||||
func (s *RepositoriesService) CreateRelease(ctx context.Context, owner, repo string, release *RepositoryRelease) (*RepositoryRelease, *Response, error) {
|
func (s *RepositoriesService) CreateRelease(ctx context.Context, owner, repo string, release *RepositoryRelease) (*RepositoryRelease, *Response, error) {
|
||||||
u := fmt.Sprintf("repos/%s/%s/releases", owner, repo)
|
u := fmt.Sprintf("repos/%s/%s/releases", owner, repo)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("POST", u, release)
|
releaseReq := &repositoryReleaseRequest{
|
||||||
|
TagName: release.TagName,
|
||||||
|
TargetCommitish: release.TargetCommitish,
|
||||||
|
Name: release.Name,
|
||||||
|
Body: release.Body,
|
||||||
|
Draft: release.Draft,
|
||||||
|
Prerelease: release.Prerelease,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, releaseReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -146,11 +175,23 @@ func (s *RepositoriesService) CreateRelease(ctx context.Context, owner, repo str
|
|||||||
|
|
||||||
// EditRelease edits a repository release.
|
// EditRelease edits a repository release.
|
||||||
//
|
//
|
||||||
|
// Note that only a subset of the release fields are used.
|
||||||
|
// See RepositoryRelease for more information.
|
||||||
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release
|
// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release
|
||||||
func (s *RepositoriesService) EditRelease(ctx context.Context, owner, repo string, id int64, release *RepositoryRelease) (*RepositoryRelease, *Response, error) {
|
func (s *RepositoriesService) EditRelease(ctx context.Context, owner, repo string, id int64, release *RepositoryRelease) (*RepositoryRelease, *Response, error) {
|
||||||
u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id)
|
u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("PATCH", u, release)
|
releaseReq := &repositoryReleaseRequest{
|
||||||
|
TagName: release.TagName,
|
||||||
|
TargetCommitish: release.TargetCommitish,
|
||||||
|
Name: release.Name,
|
||||||
|
Body: release.Body,
|
||||||
|
Draft: release.Draft,
|
||||||
|
Prerelease: release.Prerelease,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("PATCH", u, releaseReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
1
vendor/github.com/google/go-github/github/teams_discussion_comments.go
generated
vendored
1
vendor/github.com/google/go-github/github/teams_discussion_comments.go
generated
vendored
@ -24,6 +24,7 @@ type DiscussionComment struct {
|
|||||||
Number *int `json:"number,omitempty"`
|
Number *int `json:"number,omitempty"`
|
||||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
|
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
|
||||||
URL *string `json:"url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
|
Reactions *Reactions `json:"reactions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c DiscussionComment) String() string {
|
func (c DiscussionComment) String() string {
|
||||||
|
1
vendor/github.com/google/go-github/github/teams_discussions.go
generated
vendored
1
vendor/github.com/google/go-github/github/teams_discussions.go
generated
vendored
@ -29,6 +29,7 @@ type TeamDiscussion struct {
|
|||||||
Title *string `json:"title,omitempty"`
|
Title *string `json:"title,omitempty"`
|
||||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
|
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
|
||||||
URL *string `json:"url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
|
Reactions *Reactions `json:"reactions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d TeamDiscussion) String() string {
|
func (d TeamDiscussion) String() string {
|
||||||
|
1
vendor/github.com/google/go-github/github/users.go
generated
vendored
1
vendor/github.com/google/go-github/github/users.go
generated
vendored
@ -76,6 +76,7 @@ func (u User) String() string {
|
|||||||
// user.
|
// user.
|
||||||
//
|
//
|
||||||
// GitHub API docs: https://developer.github.com/v3/users/#get-a-single-user
|
// GitHub API docs: https://developer.github.com/v3/users/#get-a-single-user
|
||||||
|
// and: https://developer.github.com/v3/users/#get-the-authenticated-user
|
||||||
func (s *UsersService) Get(ctx context.Context, user string) (*User, *Response, error) {
|
func (s *UsersService) Get(ctx context.Context, user string) (*User, *Response, error) {
|
||||||
var u string
|
var u string
|
||||||
if user != "" {
|
if user != "" {
|
||||||
|
2
vendor/github.com/olebedev/config/config.go
generated
vendored
2
vendor/github.com/olebedev/config/config.go
generated
vendored
@ -498,7 +498,7 @@ func Set(cfg interface{}, path string, value interface{}) error {
|
|||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Invalid type at %q: expected []interface{} or map[string]interface{}; got %T",
|
"Invalid type at %q: expected []interface{} or map[string]interface{}; got %T",
|
||||||
strings.Join(parts[:pos+1], "."), cfg)
|
strings.Join(parts[:pos+1], "."), c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
vendor/github.com/rivo/tview/README.md
generated
vendored
2
vendor/github.com/rivo/tview/README.md
generated
vendored
@ -65,6 +65,8 @@ Add your issue here on GitHub. Feel free to get in touch if you have any questio
|
|||||||
|
|
||||||
(There are no corresponding tags in the project. I only keep such a history in this README.)
|
(There are no corresponding tags in the project. I only keep such a history in this README.)
|
||||||
|
|
||||||
|
- v0.18 (2018-10-18)
|
||||||
|
- `InputField` elements can now be navigated freely.
|
||||||
- v0.17 (2018-06-20)
|
- v0.17 (2018-06-20)
|
||||||
- Added `TreeView`.
|
- Added `TreeView`.
|
||||||
- v0.15 (2018-05-02)
|
- v0.15 (2018-05-02)
|
||||||
|
47
vendor/github.com/rivo/tview/application.go
generated
vendored
47
vendor/github.com/rivo/tview/application.go
generated
vendored
@ -19,6 +19,9 @@ type Application struct {
|
|||||||
// The application's screen.
|
// The application's screen.
|
||||||
screen tcell.Screen
|
screen tcell.Screen
|
||||||
|
|
||||||
|
// Indicates whether the application's screen is currently active.
|
||||||
|
running bool
|
||||||
|
|
||||||
// The primitive which currently has the keyboard focus.
|
// The primitive which currently has the keyboard focus.
|
||||||
focus Primitive
|
focus Primitive
|
||||||
|
|
||||||
@ -70,22 +73,53 @@ func (a *Application) GetInputCapture() func(event *tcell.EventKey) *tcell.Event
|
|||||||
return a.inputCapture
|
return a.inputCapture
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetScreen allows you to provide your own tcell.Screen object. For most
|
||||||
|
// applications, this is not needed and you should be familiar with
|
||||||
|
// tcell.Screen when using this function. Run() will call Init() and Fini() on
|
||||||
|
// the provided screen object.
|
||||||
|
//
|
||||||
|
// This function is typically called before calling Run(). Calling it while an
|
||||||
|
// application is running will switch the application to the new screen. Fini()
|
||||||
|
// will be called on the old screen and Init() on the new screen (errors
|
||||||
|
// returned by Init() will lead to a panic).
|
||||||
|
//
|
||||||
|
// Note that calling Suspend() will invoke Fini() on your screen object and it
|
||||||
|
// will not be restored when suspended mode ends. Instead, a new default screen
|
||||||
|
// object will be created.
|
||||||
|
func (a *Application) SetScreen(screen tcell.Screen) *Application {
|
||||||
|
a.Lock()
|
||||||
|
defer a.Unlock()
|
||||||
|
if a.running {
|
||||||
|
a.screen.Fini()
|
||||||
|
}
|
||||||
|
a.screen = screen
|
||||||
|
if a.running {
|
||||||
|
if err := a.screen.Init(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
// Run starts the application and thus the event loop. This function returns
|
// Run starts the application and thus the event loop. This function returns
|
||||||
// when Stop() was called.
|
// when Stop() was called.
|
||||||
func (a *Application) Run() error {
|
func (a *Application) Run() error {
|
||||||
var err error
|
var err error
|
||||||
a.Lock()
|
a.Lock()
|
||||||
|
|
||||||
// Make a screen.
|
// Make a screen if there is none yet.
|
||||||
a.screen, err = tcell.NewScreen()
|
if a.screen == nil {
|
||||||
if err != nil {
|
a.screen, err = tcell.NewScreen()
|
||||||
a.Unlock()
|
if err != nil {
|
||||||
return err
|
a.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err = a.screen.Init(); err != nil {
|
if err = a.screen.Init(); err != nil {
|
||||||
a.Unlock()
|
a.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
a.running = true
|
||||||
|
|
||||||
// We catch panics to clean up because they mess up the terminal.
|
// We catch panics to clean up because they mess up the terminal.
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -93,6 +127,7 @@ func (a *Application) Run() error {
|
|||||||
if a.screen != nil {
|
if a.screen != nil {
|
||||||
a.screen.Fini()
|
a.screen.Fini()
|
||||||
}
|
}
|
||||||
|
a.running = false
|
||||||
panic(p)
|
panic(p)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -170,6 +205,7 @@ func (a *Application) Stop() {
|
|||||||
}
|
}
|
||||||
a.screen.Fini()
|
a.screen.Fini()
|
||||||
a.screen = nil
|
a.screen = nil
|
||||||
|
a.running = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suspend temporarily suspends the application by exiting terminal UI mode and
|
// Suspend temporarily suspends the application by exiting terminal UI mode and
|
||||||
@ -217,6 +253,7 @@ func (a *Application) Suspend(f func()) bool {
|
|||||||
a.Unlock()
|
a.Unlock()
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
a.running = true
|
||||||
a.Unlock()
|
a.Unlock()
|
||||||
a.Draw()
|
a.Draw()
|
||||||
|
|
||||||
|
40
vendor/github.com/rivo/tview/box.go
generated
vendored
40
vendor/github.com/rivo/tview/box.go
generated
vendored
@ -51,10 +51,6 @@ type Box struct {
|
|||||||
// Whether or not this box has focus.
|
// Whether or not this box has focus.
|
||||||
hasFocus bool
|
hasFocus bool
|
||||||
|
|
||||||
// If set to true, the inner rect of this box will be within the screen at the
|
|
||||||
// last time the box was drawn.
|
|
||||||
clampToScreen bool
|
|
||||||
|
|
||||||
// An optional capture function which receives a key event and returns the
|
// An optional capture function which receives a key event and returns the
|
||||||
// event to be forwarded to the primitive's default input handler (nil if
|
// event to be forwarded to the primitive's default input handler (nil if
|
||||||
// nothing should be forwarded).
|
// nothing should be forwarded).
|
||||||
@ -74,7 +70,6 @@ func NewBox() *Box {
|
|||||||
borderColor: Styles.BorderColor,
|
borderColor: Styles.BorderColor,
|
||||||
titleColor: Styles.TitleColor,
|
titleColor: Styles.TitleColor,
|
||||||
titleAlign: AlignCenter,
|
titleAlign: AlignCenter,
|
||||||
clampToScreen: true,
|
|
||||||
}
|
}
|
||||||
b.focus = b
|
b.focus = b
|
||||||
return b
|
return b
|
||||||
@ -117,6 +112,7 @@ func (b *Box) SetRect(x, y, width, height int) {
|
|||||||
b.y = y
|
b.y = y
|
||||||
b.width = width
|
b.width = width
|
||||||
b.height = height
|
b.height = height
|
||||||
|
b.innerX = -1 // Mark inner rect as uninitialized.
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDrawFunc sets a callback function which is invoked after the box primitive
|
// SetDrawFunc sets a callback function which is invoked after the box primitive
|
||||||
@ -277,8 +273,8 @@ func (b *Box) Draw(screen tcell.Screen) {
|
|||||||
|
|
||||||
// Draw title.
|
// Draw title.
|
||||||
if b.title != "" && b.width >= 4 {
|
if b.title != "" && b.width >= 4 {
|
||||||
_, printed := Print(screen, b.title, b.x+1, b.y, b.width-2, b.titleAlign, b.titleColor)
|
printed, _ := Print(screen, b.title, b.x+1, b.y, b.width-2, b.titleAlign, b.titleColor)
|
||||||
if StringWidth(b.title)-printed > 0 && printed > 0 {
|
if len(b.title)-printed > 0 && printed > 0 {
|
||||||
_, _, style, _ := screen.GetContent(b.x+b.width-2, b.y)
|
_, _, style, _ := screen.GetContent(b.x+b.width-2, b.y)
|
||||||
fg, _, _ := style.Decompose()
|
fg, _, _ := style.Decompose()
|
||||||
Print(screen, string(SemigraphicsHorizontalEllipsis), b.x+b.width-2, b.y, 1, AlignLeft, fg)
|
Print(screen, string(SemigraphicsHorizontalEllipsis), b.x+b.width-2, b.y, 1, AlignLeft, fg)
|
||||||
@ -296,22 +292,20 @@ func (b *Box) Draw(screen tcell.Screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clamp inner rect to screen.
|
// Clamp inner rect to screen.
|
||||||
if b.clampToScreen {
|
width, height := screen.Size()
|
||||||
width, height := screen.Size()
|
if b.innerX < 0 {
|
||||||
if b.innerX < 0 {
|
b.innerWidth += b.innerX
|
||||||
b.innerWidth += b.innerX
|
b.innerX = 0
|
||||||
b.innerX = 0
|
}
|
||||||
}
|
if b.innerX+b.innerWidth >= width {
|
||||||
if b.innerX+b.innerWidth >= width {
|
b.innerWidth = width - b.innerX
|
||||||
b.innerWidth = width - b.innerX
|
}
|
||||||
}
|
if b.innerY+b.innerHeight >= height {
|
||||||
if b.innerY+b.innerHeight >= height {
|
b.innerHeight = height - b.innerY
|
||||||
b.innerHeight = height - b.innerY
|
}
|
||||||
}
|
if b.innerY < 0 {
|
||||||
if b.innerY < 0 {
|
b.innerHeight += b.innerY
|
||||||
b.innerHeight += b.innerY
|
b.innerY = 0
|
||||||
b.innerY = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
vendor/github.com/rivo/tview/checkbox.go
generated
vendored
6
vendor/github.com/rivo/tview/checkbox.go
generated
vendored
@ -124,9 +124,9 @@ func (c *Checkbox) SetChangedFunc(handler func(checked bool)) *Checkbox {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDoneFunc sets a handler which is called when the user is done entering
|
// SetDoneFunc sets a handler which is called when the user is done using the
|
||||||
// text. The callback function is provided with the key that was pressed, which
|
// checkbox. The callback function is provided with the key that was pressed,
|
||||||
// is one of the following:
|
// which is one of the following:
|
||||||
//
|
//
|
||||||
// - KeyEscape: Abort text input.
|
// - KeyEscape: Abort text input.
|
||||||
// - KeyTab: Move to the next field.
|
// - KeyTab: Move to the next field.
|
||||||
|
12
vendor/github.com/rivo/tview/form.go
generated
vendored
12
vendor/github.com/rivo/tview/form.go
generated
vendored
@ -218,6 +218,13 @@ func (f *Form) AddButton(label string, selected func()) *Form {
|
|||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetButton returns the button at the specified 0-based index. Note that
|
||||||
|
// buttons have been specially prepared for this form and modifying some of
|
||||||
|
// their attributes may have unintended side effects.
|
||||||
|
func (f *Form) GetButton(index int) *Button {
|
||||||
|
return f.buttons[index]
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveButton removes the button at the specified position, starting with 0
|
// RemoveButton removes the button at the specified position, starting with 0
|
||||||
// for the button that was added first.
|
// for the button that was added first.
|
||||||
func (f *Form) RemoveButton(index int) *Form {
|
func (f *Form) RemoveButton(index int) *Form {
|
||||||
@ -225,6 +232,11 @@ func (f *Form) RemoveButton(index int) *Form {
|
|||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetButtonCount returns the number of buttons in this form.
|
||||||
|
func (f *Form) GetButtonCount() int {
|
||||||
|
return len(f.buttons)
|
||||||
|
}
|
||||||
|
|
||||||
// GetButtonIndex returns the index of the button with the given label, starting
|
// GetButtonIndex returns the index of the button with the given label, starting
|
||||||
// with 0 for the button that was added first. If no such label was found, -1
|
// with 0 for the button that was added first. If no such label was found, -1
|
||||||
// is returned.
|
// is returned.
|
||||||
|
200
vendor/github.com/rivo/tview/inputfield.go
generated
vendored
200
vendor/github.com/rivo/tview/inputfield.go
generated
vendored
@ -11,10 +11,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// InputField is a one-line box (three lines if there is a title) where the
|
// InputField is a one-line box (three lines if there is a title) where the
|
||||||
// user can enter text.
|
// user can enter text. Use SetAcceptanceFunc() to accept or reject input,
|
||||||
|
// SetChangedFunc() to listen for changes, and SetMaskCharacter() to hide input
|
||||||
|
// from onlookers (e.g. for password input).
|
||||||
//
|
//
|
||||||
// Use SetMaskCharacter() to hide input from onlookers (e.g. for password
|
// The following keys can be used for navigation and editing:
|
||||||
// input).
|
//
|
||||||
|
// - Left arrow: Move left by one character.
|
||||||
|
// - Right arrow: Move right by one character.
|
||||||
|
// - Home, Ctrl-A, Alt-a: Move to the beginning of the line.
|
||||||
|
// - End, Ctrl-E, Alt-e: Move to the end of the line.
|
||||||
|
// - Alt-left, Alt-b: Move left by one word.
|
||||||
|
// - Alt-right, Alt-f: Move right by one word.
|
||||||
|
// - Backspace: Delete the character before the cursor.
|
||||||
|
// - Delete: Delete the character after the cursor.
|
||||||
|
// - Ctrl-K: Delete from the cursor to the end of the line.
|
||||||
|
// - Ctrl-W: Delete the last word before the cursor.
|
||||||
|
// - Ctrl-U: Delete the entire line.
|
||||||
//
|
//
|
||||||
// See https://github.com/rivo/tview/wiki/InputField for an example.
|
// See https://github.com/rivo/tview/wiki/InputField for an example.
|
||||||
type InputField struct {
|
type InputField struct {
|
||||||
@ -53,6 +66,12 @@ type InputField struct {
|
|||||||
// disables masking.
|
// disables masking.
|
||||||
maskCharacter rune
|
maskCharacter rune
|
||||||
|
|
||||||
|
// The cursor position as a byte index into the text string.
|
||||||
|
cursorPos int
|
||||||
|
|
||||||
|
// The number of bytes of the text string skipped ahead while drawing.
|
||||||
|
offset int
|
||||||
|
|
||||||
// An optional function which may reject the last character that was entered.
|
// An optional function which may reject the last character that was entered.
|
||||||
accept func(text string, ch rune) bool
|
accept func(text string, ch rune) bool
|
||||||
|
|
||||||
@ -174,7 +193,7 @@ func (i *InputField) SetMaskCharacter(mask rune) *InputField {
|
|||||||
// SetAcceptanceFunc sets a handler which may reject the last character that was
|
// SetAcceptanceFunc sets a handler which may reject the last character that was
|
||||||
// entered (by returning false).
|
// entered (by returning false).
|
||||||
//
|
//
|
||||||
// This package defines a number of variables Prefixed with InputField which may
|
// This package defines a number of variables prefixed with InputField which may
|
||||||
// be used for common input (e.g. numbers, maximum text length).
|
// be used for common input (e.g. numbers, maximum text length).
|
||||||
func (i *InputField) SetAcceptanceFunc(handler func(textToCheck string, lastChar rune) bool) *InputField {
|
func (i *InputField) SetAcceptanceFunc(handler func(textToCheck string, lastChar rune) bool) *InputField {
|
||||||
i.accept = handler
|
i.accept = handler
|
||||||
@ -244,56 +263,69 @@ func (i *InputField) Draw(screen tcell.Screen) {
|
|||||||
screen.SetContent(x+index, y, ' ', nil, fieldStyle)
|
screen.SetContent(x+index, y, ' ', nil, fieldStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw placeholder text.
|
// Text.
|
||||||
|
var cursorScreenPos int
|
||||||
text := i.text
|
text := i.text
|
||||||
if text == "" && i.placeholder != "" {
|
if text == "" && i.placeholder != "" {
|
||||||
Print(screen, i.placeholder, x, y, fieldWidth, AlignLeft, i.placeholderTextColor)
|
// Draw placeholder text.
|
||||||
|
Print(screen, Escape(i.placeholder), x, y, fieldWidth, AlignLeft, i.placeholderTextColor)
|
||||||
|
i.offset = 0
|
||||||
} else {
|
} else {
|
||||||
// Draw entered text.
|
// Draw entered text.
|
||||||
if i.maskCharacter > 0 {
|
if i.maskCharacter > 0 {
|
||||||
text = strings.Repeat(string(i.maskCharacter), utf8.RuneCountInString(i.text))
|
text = strings.Repeat(string(i.maskCharacter), utf8.RuneCountInString(i.text))
|
||||||
} else {
|
|
||||||
text = Escape(text)
|
|
||||||
}
|
}
|
||||||
fieldWidth-- // We need one cell for the cursor.
|
stringWidth := runewidth.StringWidth(text)
|
||||||
if fieldWidth < runewidth.StringWidth(text) {
|
if fieldWidth >= stringWidth {
|
||||||
Print(screen, text, x, y, fieldWidth, AlignRight, i.fieldTextColor)
|
// We have enough space for the full text.
|
||||||
|
Print(screen, Escape(text), x, y, fieldWidth, AlignLeft, i.fieldTextColor)
|
||||||
|
i.offset = 0
|
||||||
|
iterateString(text, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
|
if textPos >= i.cursorPos {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
cursorScreenPos += screenWidth
|
||||||
|
return false
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Print(screen, text, x, y, fieldWidth, AlignLeft, i.fieldTextColor)
|
// The text doesn't fit. Where is the cursor?
|
||||||
|
if i.cursorPos < 0 {
|
||||||
|
i.cursorPos = 0
|
||||||
|
} else if i.cursorPos > len(text) {
|
||||||
|
i.cursorPos = len(text)
|
||||||
|
}
|
||||||
|
// Shift the text so the cursor is inside the field.
|
||||||
|
var shiftLeft int
|
||||||
|
if i.offset > i.cursorPos {
|
||||||
|
i.offset = i.cursorPos
|
||||||
|
} else if subWidth := runewidth.StringWidth(text[i.offset:i.cursorPos]); subWidth > fieldWidth-1 {
|
||||||
|
shiftLeft = subWidth - fieldWidth + 1
|
||||||
|
}
|
||||||
|
currentOffset := i.offset
|
||||||
|
iterateString(text, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
|
if textPos >= currentOffset {
|
||||||
|
if shiftLeft > 0 {
|
||||||
|
i.offset = textPos + textWidth
|
||||||
|
shiftLeft -= screenWidth
|
||||||
|
} else {
|
||||||
|
if textPos+textWidth > i.cursorPos {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
cursorScreenPos += screenWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
Print(screen, Escape(text[i.offset:]), x, y, fieldWidth, AlignLeft, i.fieldTextColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set cursor.
|
// Set cursor.
|
||||||
if i.focus.HasFocus() {
|
if i.focus.HasFocus() {
|
||||||
i.setCursor(screen)
|
screen.ShowCursor(x+cursorScreenPos, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setCursor sets the cursor position.
|
|
||||||
func (i *InputField) setCursor(screen tcell.Screen) {
|
|
||||||
x := i.x
|
|
||||||
y := i.y
|
|
||||||
rightLimit := x + i.width
|
|
||||||
if i.border {
|
|
||||||
x++
|
|
||||||
y++
|
|
||||||
rightLimit -= 2
|
|
||||||
}
|
|
||||||
fieldWidth := runewidth.StringWidth(i.text)
|
|
||||||
if i.fieldWidth > 0 && fieldWidth > i.fieldWidth-1 {
|
|
||||||
fieldWidth = i.fieldWidth - 1
|
|
||||||
}
|
|
||||||
if i.labelWidth > 0 {
|
|
||||||
x += i.labelWidth + fieldWidth
|
|
||||||
} else {
|
|
||||||
x += StringWidth(i.label) + fieldWidth
|
|
||||||
}
|
|
||||||
if x >= rightLimit {
|
|
||||||
x = rightLimit - 1
|
|
||||||
}
|
|
||||||
screen.ShowCursor(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputHandler returns the handler for this primitive.
|
// InputHandler returns the handler for this primitive.
|
||||||
func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return i.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
return i.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
@ -305,27 +337,95 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Movement functions.
|
||||||
|
home := func() { i.cursorPos = 0 }
|
||||||
|
end := func() { i.cursorPos = len(i.text) }
|
||||||
|
moveLeft := func() {
|
||||||
|
iterateStringReverse(i.text[:i.cursorPos], func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
|
i.cursorPos -= textWidth
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
moveRight := func() {
|
||||||
|
iterateString(i.text[i.cursorPos:], func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
|
i.cursorPos += textWidth
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
moveWordLeft := func() {
|
||||||
|
i.cursorPos = len(regexp.MustCompile(`\S+\s*$`).ReplaceAllString(i.text[:i.cursorPos], ""))
|
||||||
|
}
|
||||||
|
moveWordRight := func() {
|
||||||
|
i.cursorPos = len(i.text) - len(regexp.MustCompile(`^\s*\S+\s*`).ReplaceAllString(i.text[i.cursorPos:], ""))
|
||||||
|
}
|
||||||
|
|
||||||
// Process key event.
|
// Process key event.
|
||||||
switch key := event.Key(); key {
|
switch key := event.Key(); key {
|
||||||
case tcell.KeyRune: // Regular character.
|
case tcell.KeyRune: // Regular character.
|
||||||
newText := i.text + string(event.Rune())
|
modifiers := event.Modifiers()
|
||||||
if i.accept != nil {
|
if modifiers == tcell.ModNone {
|
||||||
if !i.accept(newText, event.Rune()) {
|
ch := string(event.Rune())
|
||||||
break
|
newText := i.text[:i.cursorPos] + ch + i.text[i.cursorPos:]
|
||||||
|
if i.accept != nil {
|
||||||
|
if !i.accept(newText, event.Rune()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i.text = newText
|
||||||
|
i.cursorPos += len(ch)
|
||||||
|
} else if modifiers&tcell.ModAlt > 0 {
|
||||||
|
// We accept some Alt- key combinations.
|
||||||
|
switch event.Rune() {
|
||||||
|
case 'a': // Home.
|
||||||
|
home()
|
||||||
|
case 'e': // End.
|
||||||
|
end()
|
||||||
|
case 'b': // Move word left.
|
||||||
|
moveWordLeft()
|
||||||
|
case 'f': // Move word right.
|
||||||
|
moveWordRight()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.text = newText
|
|
||||||
case tcell.KeyCtrlU: // Delete all.
|
case tcell.KeyCtrlU: // Delete all.
|
||||||
i.text = ""
|
i.text = ""
|
||||||
|
i.cursorPos = 0
|
||||||
|
case tcell.KeyCtrlK: // Delete until the end of the line.
|
||||||
|
i.text = i.text[:i.cursorPos]
|
||||||
case tcell.KeyCtrlW: // Delete last word.
|
case tcell.KeyCtrlW: // Delete last word.
|
||||||
lastWord := regexp.MustCompile(`\s*\S+\s*$`)
|
lastWord := regexp.MustCompile(`\S+\s*$`)
|
||||||
i.text = lastWord.ReplaceAllString(i.text, "")
|
newText := lastWord.ReplaceAllString(i.text[:i.cursorPos], "") + i.text[i.cursorPos:]
|
||||||
case tcell.KeyBackspace, tcell.KeyBackspace2: // Delete last character.
|
i.cursorPos -= len(i.text) - len(newText)
|
||||||
if len(i.text) == 0 {
|
i.text = newText
|
||||||
break
|
case tcell.KeyBackspace, tcell.KeyBackspace2: // Delete character before the cursor.
|
||||||
|
iterateStringReverse(i.text[:i.cursorPos], func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
|
i.text = i.text[:textPos] + i.text[textPos+textWidth:]
|
||||||
|
i.cursorPos -= textWidth
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if i.offset >= i.cursorPos {
|
||||||
|
i.offset = 0
|
||||||
}
|
}
|
||||||
runes := []rune(i.text)
|
case tcell.KeyDelete: // Delete character after the cursor.
|
||||||
i.text = string(runes[:len(runes)-1])
|
iterateString(i.text[i.cursorPos:], func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
|
i.text = i.text[:i.cursorPos] + i.text[i.cursorPos+textWidth:]
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
case tcell.KeyLeft:
|
||||||
|
if event.Modifiers()&tcell.ModAlt > 0 {
|
||||||
|
moveWordLeft()
|
||||||
|
} else {
|
||||||
|
moveLeft()
|
||||||
|
}
|
||||||
|
case tcell.KeyRight:
|
||||||
|
if event.Modifiers()&tcell.ModAlt > 0 {
|
||||||
|
moveWordRight()
|
||||||
|
} else {
|
||||||
|
moveRight()
|
||||||
|
}
|
||||||
|
case tcell.KeyHome, tcell.KeyCtrlA:
|
||||||
|
home()
|
||||||
|
case tcell.KeyEnd, tcell.KeyCtrlE:
|
||||||
|
end()
|
||||||
case tcell.KeyEnter, tcell.KeyTab, tcell.KeyBacktab, tcell.KeyEscape: // We're done.
|
case tcell.KeyEnter, tcell.KeyTab, tcell.KeyBacktab, tcell.KeyEscape: // We're done.
|
||||||
if i.done != nil {
|
if i.done != nil {
|
||||||
i.done(key)
|
i.done(key)
|
||||||
|
15
vendor/github.com/rivo/tview/list.go
generated
vendored
15
vendor/github.com/rivo/tview/list.go
generated
vendored
@ -85,6 +85,19 @@ func (l *List) GetCurrentItem() int {
|
|||||||
return l.currentItem
|
return l.currentItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveItem removes the item with the given index (starting at 0) from the
|
||||||
|
// list. Does nothing if the index is out of range.
|
||||||
|
func (l *List) RemoveItem(index int) *List {
|
||||||
|
if index < 0 || index >= len(l.items) {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
l.items = append(l.items[:index], l.items[index+1:]...)
|
||||||
|
if l.currentItem >= len(l.items) {
|
||||||
|
l.currentItem = len(l.items) - 1
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
// SetMainTextColor sets the color of the items' main text.
|
// SetMainTextColor sets the color of the items' main text.
|
||||||
func (l *List) SetMainTextColor(color tcell.Color) *List {
|
func (l *List) SetMainTextColor(color tcell.Color) *List {
|
||||||
l.mainTextColor = color
|
l.mainTextColor = color
|
||||||
@ -127,7 +140,7 @@ func (l *List) ShowSecondaryText(show bool) *List {
|
|||||||
//
|
//
|
||||||
// This function is also called when the first item is added or when
|
// This function is also called when the first item is added or when
|
||||||
// SetCurrentItem() is called.
|
// SetCurrentItem() is called.
|
||||||
func (l *List) SetChangedFunc(handler func(int, string, string, rune)) *List {
|
func (l *List) SetChangedFunc(handler func(index int, mainText string, secondaryText string, shortcut rune)) *List {
|
||||||
l.changed = handler
|
l.changed = handler
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
10
vendor/github.com/rivo/tview/modal.go
generated
vendored
10
vendor/github.com/rivo/tview/modal.go
generated
vendored
@ -86,6 +86,16 @@ func (m *Modal) AddButtons(labels []string) *Modal {
|
|||||||
m.done(i, l)
|
m.done(i, l)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
button := m.form.GetButton(m.form.GetButtonCount() - 1)
|
||||||
|
button.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
switch event.Key() {
|
||||||
|
case tcell.KeyDown, tcell.KeyRight:
|
||||||
|
return tcell.NewEventKey(tcell.KeyTab, 0, tcell.ModNone)
|
||||||
|
case tcell.KeyUp, tcell.KeyLeft:
|
||||||
|
return tcell.NewEventKey(tcell.KeyBacktab, 0, tcell.ModNone)
|
||||||
|
}
|
||||||
|
return event
|
||||||
|
})
|
||||||
}(index, label)
|
}(index, label)
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
|
59
vendor/github.com/rivo/tview/table.go
generated
vendored
59
vendor/github.com/rivo/tview/table.go
generated
vendored
@ -231,6 +231,10 @@ type Table struct {
|
|||||||
// The number of visible rows the last time the table was drawn.
|
// The number of visible rows the last time the table was drawn.
|
||||||
visibleRows int
|
visibleRows int
|
||||||
|
|
||||||
|
// The style of the selected rows. If this value is 0, selected rows are
|
||||||
|
// simply inverted.
|
||||||
|
selectedStyle tcell.Style
|
||||||
|
|
||||||
// An optional function which gets called when the user presses Enter on a
|
// An optional function which gets called when the user presses Enter on a
|
||||||
// selected cell. If entire rows selected, the column value is undefined.
|
// selected cell. If entire rows selected, the column value is undefined.
|
||||||
// Likewise for entire columns.
|
// Likewise for entire columns.
|
||||||
@ -276,6 +280,18 @@ func (t *Table) SetBordersColor(color tcell.Color) *Table {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetSelectedStyle sets a specific style for selected cells. If no such style
|
||||||
|
// is set, per default, selected cells are inverted (i.e. their foreground and
|
||||||
|
// background colors are swapped).
|
||||||
|
//
|
||||||
|
// To reset a previous setting to its default, make the following call:
|
||||||
|
//
|
||||||
|
// table.SetSelectedStyle(tcell.ColorDefault, tcell.ColorDefault, 0)
|
||||||
|
func (t *Table) SetSelectedStyle(foregroundColor, backgroundColor tcell.Color, attributes tcell.AttrMask) *Table {
|
||||||
|
t.selectedStyle = tcell.StyleDefault.Foreground(foregroundColor).Background(backgroundColor) | tcell.Style(attributes)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
// SetSeparator sets the character used to fill the space between two
|
// SetSeparator sets the character used to fill the space between two
|
||||||
// neighboring cells. This is a space character ' ' per default but you may
|
// neighboring cells. This is a space character ' ' per default but you may
|
||||||
// want to set it to Borders.Vertical (or any other rune) if the column
|
// want to set it to Borders.Vertical (or any other rune) if the column
|
||||||
@ -743,12 +759,17 @@ ColumnLoop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function which colors the background of a box.
|
// Helper function which colors the background of a box.
|
||||||
colorBackground := func(fromX, fromY, w, h int, backgroundColor, textColor tcell.Color, selected bool) {
|
// backgroundColor == tcell.ColorDefault => Don't color the background.
|
||||||
|
// textColor == tcell.ColorDefault => Don't change the text color.
|
||||||
|
// attr == 0 => Don't change attributes.
|
||||||
|
// invert == true => Ignore attr, set text to backgroundColor or t.backgroundColor;
|
||||||
|
// set background to textColor.
|
||||||
|
colorBackground := func(fromX, fromY, w, h int, backgroundColor, textColor tcell.Color, attr tcell.AttrMask, invert bool) {
|
||||||
for by := 0; by < h && fromY+by < y+height; by++ {
|
for by := 0; by < h && fromY+by < y+height; by++ {
|
||||||
for bx := 0; bx < w && fromX+bx < x+width; bx++ {
|
for bx := 0; bx < w && fromX+bx < x+width; bx++ {
|
||||||
m, c, style, _ := screen.GetContent(fromX+bx, fromY+by)
|
m, c, style, _ := screen.GetContent(fromX+bx, fromY+by)
|
||||||
if selected {
|
fg, bg, a := style.Decompose()
|
||||||
fg, _, _ := style.Decompose()
|
if invert {
|
||||||
if fg == textColor || fg == t.bordersColor {
|
if fg == textColor || fg == t.bordersColor {
|
||||||
fg = backgroundColor
|
fg = backgroundColor
|
||||||
}
|
}
|
||||||
@ -757,10 +778,16 @@ ColumnLoop:
|
|||||||
}
|
}
|
||||||
style = style.Background(textColor).Foreground(fg)
|
style = style.Background(textColor).Foreground(fg)
|
||||||
} else {
|
} else {
|
||||||
if backgroundColor == tcell.ColorDefault {
|
if backgroundColor != tcell.ColorDefault {
|
||||||
continue
|
bg = backgroundColor
|
||||||
}
|
}
|
||||||
style = style.Background(backgroundColor)
|
if textColor != tcell.ColorDefault {
|
||||||
|
fg = textColor
|
||||||
|
}
|
||||||
|
if attr != 0 {
|
||||||
|
a = attr
|
||||||
|
}
|
||||||
|
style = style.Background(bg).Foreground(fg) | tcell.Style(a)
|
||||||
}
|
}
|
||||||
screen.SetContent(fromX+bx, fromY+by, m, c, style)
|
screen.SetContent(fromX+bx, fromY+by, m, c, style)
|
||||||
}
|
}
|
||||||
@ -769,11 +796,12 @@ ColumnLoop:
|
|||||||
|
|
||||||
// Color the cell backgrounds. To avoid undesirable artefacts, we combine
|
// Color the cell backgrounds. To avoid undesirable artefacts, we combine
|
||||||
// the drawing of a cell by background color, selected cells last.
|
// the drawing of a cell by background color, selected cells last.
|
||||||
cellsByBackgroundColor := make(map[tcell.Color][]*struct {
|
type cellInfo struct {
|
||||||
x, y, w, h int
|
x, y, w, h int
|
||||||
text tcell.Color
|
text tcell.Color
|
||||||
selected bool
|
selected bool
|
||||||
})
|
}
|
||||||
|
cellsByBackgroundColor := make(map[tcell.Color][]*cellInfo)
|
||||||
var backgroundColors []tcell.Color
|
var backgroundColors []tcell.Color
|
||||||
for rowY, row := range rows {
|
for rowY, row := range rows {
|
||||||
columnX := 0
|
columnX := 0
|
||||||
@ -793,11 +821,7 @@ ColumnLoop:
|
|||||||
columnSelected := t.columnsSelectable && !t.rowsSelectable && column == t.selectedColumn
|
columnSelected := t.columnsSelectable && !t.rowsSelectable && column == t.selectedColumn
|
||||||
cellSelected := !cell.NotSelectable && (columnSelected || rowSelected || t.rowsSelectable && t.columnsSelectable && column == t.selectedColumn && row == t.selectedRow)
|
cellSelected := !cell.NotSelectable && (columnSelected || rowSelected || t.rowsSelectable && t.columnsSelectable && column == t.selectedColumn && row == t.selectedRow)
|
||||||
entries, ok := cellsByBackgroundColor[cell.BackgroundColor]
|
entries, ok := cellsByBackgroundColor[cell.BackgroundColor]
|
||||||
cellsByBackgroundColor[cell.BackgroundColor] = append(entries, &struct {
|
cellsByBackgroundColor[cell.BackgroundColor] = append(entries, &cellInfo{
|
||||||
x, y, w, h int
|
|
||||||
text tcell.Color
|
|
||||||
selected bool
|
|
||||||
}{
|
|
||||||
x: bx,
|
x: bx,
|
||||||
y: by,
|
y: by,
|
||||||
w: bw,
|
w: bw,
|
||||||
@ -821,13 +845,18 @@ ColumnLoop:
|
|||||||
_, _, lj := c.Hcl()
|
_, _, lj := c.Hcl()
|
||||||
return li < lj
|
return li < lj
|
||||||
})
|
})
|
||||||
|
selFg, selBg, selAttr := t.selectedStyle.Decompose()
|
||||||
for _, bgColor := range backgroundColors {
|
for _, bgColor := range backgroundColors {
|
||||||
entries := cellsByBackgroundColor[bgColor]
|
entries := cellsByBackgroundColor[bgColor]
|
||||||
for _, cell := range entries {
|
for _, cell := range entries {
|
||||||
if cell.selected {
|
if cell.selected {
|
||||||
defer colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, cell.text, true)
|
if t.selectedStyle != 0 {
|
||||||
|
defer colorBackground(cell.x, cell.y, cell.w, cell.h, selBg, selFg, selAttr, false)
|
||||||
|
} else {
|
||||||
|
defer colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, cell.text, 0, true)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, cell.text, false)
|
colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, tcell.ColorDefault, 0, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
126
vendor/github.com/rivo/tview/textview.go
generated
vendored
126
vendor/github.com/rivo/tview/textview.go
generated
vendored
@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
@ -549,12 +548,6 @@ func (t *TextView) reindexBuffer(width int) {
|
|||||||
strippedStr = regionPattern.ReplaceAllString(strippedStr, "")
|
strippedStr = regionPattern.ReplaceAllString(strippedStr, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all escape tags in this line. Escape them.
|
|
||||||
if t.dynamicColors || t.regions {
|
|
||||||
escapeIndices = escapePattern.FindAllStringIndex(str, -1)
|
|
||||||
strippedStr = escapePattern.ReplaceAllString(strippedStr, "[$1$2]")
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't need the original string anymore for now.
|
// We don't need the original string anymore for now.
|
||||||
str = strippedStr
|
str = strippedStr
|
||||||
|
|
||||||
@ -810,8 +803,9 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
|||||||
colorTags [][]string
|
colorTags [][]string
|
||||||
escapeIndices [][]int
|
escapeIndices [][]int
|
||||||
)
|
)
|
||||||
|
strippedText := text
|
||||||
if t.dynamicColors {
|
if t.dynamicColors {
|
||||||
colorTagIndices, colorTags, escapeIndices, _, _ = decomposeString(text)
|
colorTagIndices, colorTags, escapeIndices, strippedText, _ = decomposeString(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get regions.
|
// Get regions.
|
||||||
@ -822,8 +816,10 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
|||||||
if t.regions {
|
if t.regions {
|
||||||
regionIndices = regionPattern.FindAllStringIndex(text, -1)
|
regionIndices = regionPattern.FindAllStringIndex(text, -1)
|
||||||
regions = regionPattern.FindAllStringSubmatch(text, -1)
|
regions = regionPattern.FindAllStringSubmatch(text, -1)
|
||||||
|
strippedText = regionPattern.ReplaceAllString(strippedText, "")
|
||||||
if !t.dynamicColors {
|
if !t.dynamicColors {
|
||||||
escapeIndices = escapePattern.FindAllStringIndex(text, -1)
|
escapeIndices = escapePattern.FindAllStringIndex(text, -1)
|
||||||
|
strippedText = string(escapePattern.ReplaceAllString(strippedText, "[$1$2]"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -842,11 +838,26 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print the line.
|
// Print the line.
|
||||||
var currentTag, currentRegion, currentEscapeTag, skipped, runeSeqWidth int
|
var colorPos, regionPos, escapePos, tagOffset, skipped int
|
||||||
runeSequence := make([]rune, 0, 10)
|
iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
flush := func() {
|
// Get the color.
|
||||||
if len(runeSequence) == 0 {
|
if colorPos < len(colorTags) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] {
|
||||||
return
|
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colorTags[colorPos])
|
||||||
|
tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0]
|
||||||
|
colorPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the region.
|
||||||
|
if regionPos < len(regionIndices) && textPos+tagOffset >= regionIndices[regionPos][0] && textPos+tagOffset < regionIndices[regionPos][1] {
|
||||||
|
regionID = regions[regionPos][1]
|
||||||
|
tagOffset += regionIndices[regionPos][1] - regionIndices[regionPos][0]
|
||||||
|
regionPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the second-to-last character of an escape tag.
|
||||||
|
if escapePos < len(escapeIndices) && textPos+tagOffset == escapeIndices[escapePos][1]-2 {
|
||||||
|
tagOffset++
|
||||||
|
escapePos++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mix the existing style with the new style.
|
// Mix the existing style with the new style.
|
||||||
@ -876,87 +887,30 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
|||||||
style = style.Background(fg).Foreground(bg)
|
style = style.Background(fg).Foreground(bg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the character.
|
|
||||||
var comb []rune
|
|
||||||
if len(runeSequence) > 1 && !unicode.IsControl(runeSequence[1]) {
|
|
||||||
// Allocate space for the combining characters only when necessary.
|
|
||||||
comb = make([]rune, len(runeSequence)-1)
|
|
||||||
copy(comb, runeSequence[1:])
|
|
||||||
}
|
|
||||||
for offset := 0; offset < runeSeqWidth; offset++ {
|
|
||||||
screen.SetContent(x+posX+offset, y+line-t.lineOffset, runeSequence[0], comb, style)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance.
|
|
||||||
posX += runeSeqWidth
|
|
||||||
runeSequence = runeSequence[:0]
|
|
||||||
runeSeqWidth = 0
|
|
||||||
}
|
|
||||||
for pos, ch := range text {
|
|
||||||
// Get the color.
|
|
||||||
if currentTag < len(colorTags) && pos >= colorTagIndices[currentTag][0] && pos < colorTagIndices[currentTag][1] {
|
|
||||||
flush()
|
|
||||||
if pos == colorTagIndices[currentTag][1]-1 {
|
|
||||||
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colorTags[currentTag])
|
|
||||||
currentTag++
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the region.
|
|
||||||
if currentRegion < len(regionIndices) && pos >= regionIndices[currentRegion][0] && pos < regionIndices[currentRegion][1] {
|
|
||||||
flush()
|
|
||||||
if pos == regionIndices[currentRegion][1]-1 {
|
|
||||||
regionID = regions[currentRegion][1]
|
|
||||||
currentRegion++
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the second-to-last character of an escape tag.
|
|
||||||
if currentEscapeTag < len(escapeIndices) && pos >= escapeIndices[currentEscapeTag][0] && pos < escapeIndices[currentEscapeTag][1] {
|
|
||||||
flush()
|
|
||||||
if pos == escapeIndices[currentEscapeTag][1]-1 {
|
|
||||||
currentEscapeTag++
|
|
||||||
} else if pos == escapeIndices[currentEscapeTag][1]-2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the width of this rune.
|
|
||||||
chWidth := runewidth.RuneWidth(ch)
|
|
||||||
if chWidth == 0 {
|
|
||||||
// If this is not a modifier, we treat it as a space character.
|
|
||||||
if len(runeSequence) == 0 {
|
|
||||||
ch = ' '
|
|
||||||
chWidth = 1
|
|
||||||
} else {
|
|
||||||
runeSequence = append(runeSequence, ch)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip to the right.
|
// Skip to the right.
|
||||||
if !t.wrap && skipped < skip {
|
if !t.wrap && skipped < skip {
|
||||||
skipped += chWidth
|
skipped += screenWidth
|
||||||
continue
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop at the right border.
|
// Stop at the right border.
|
||||||
if posX+runeSeqWidth+chWidth > width {
|
if posX+screenWidth >= width {
|
||||||
break
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush the rune sequence.
|
// Draw the character.
|
||||||
flush()
|
for offset := screenWidth - 1; offset >= 0; offset-- {
|
||||||
|
if offset == 0 {
|
||||||
|
screen.SetContent(x+posX+offset, y+line-t.lineOffset, main, comb, style)
|
||||||
|
} else {
|
||||||
|
screen.SetContent(x+posX+offset, y+line-t.lineOffset, ' ', nil, style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Queue this rune.
|
// Advance.
|
||||||
runeSequence = append(runeSequence, ch)
|
posX += screenWidth
|
||||||
runeSeqWidth += chWidth
|
return false
|
||||||
}
|
})
|
||||||
if posX+runeSeqWidth <= width {
|
|
||||||
flush()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this view is not scrollable, we'll purge the buffer of lines that have
|
// If this view is not scrollable, we'll purge the buffer of lines that have
|
||||||
|
546
vendor/github.com/rivo/tview/util.go
generated
vendored
546
vendor/github.com/rivo/tview/util.go
generated
vendored
@ -1,11 +1,9 @@
|
|||||||
package tview
|
package tview
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
@ -25,7 +23,7 @@ var (
|
|||||||
regionPattern = regexp.MustCompile(`\["([a-zA-Z0-9_,;: \-\.]*)"\]`)
|
regionPattern = regexp.MustCompile(`\["([a-zA-Z0-9_,;: \-\.]*)"\]`)
|
||||||
escapePattern = regexp.MustCompile(`\[([a-zA-Z0-9_,;: \-\."#]+)\[(\[*)\]`)
|
escapePattern = regexp.MustCompile(`\[([a-zA-Z0-9_,;: \-\."#]+)\[(\[*)\]`)
|
||||||
nonEscapePattern = regexp.MustCompile(`(\[[a-zA-Z0-9_,;: \-\."#]+\[*)\]`)
|
nonEscapePattern = regexp.MustCompile(`(\[[a-zA-Z0-9_,;: \-\."#]+\[*)\]`)
|
||||||
boundaryPattern = regexp.MustCompile("([[:punct:]]\\s*|\\s+)")
|
boundaryPattern = regexp.MustCompile(`(([[:punct:]]|\n)[ \t\f\r]*|(\s+))`)
|
||||||
spacePattern = regexp.MustCompile(`\s+`)
|
spacePattern = regexp.MustCompile(`\s+`)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -203,8 +201,8 @@ func decomposeString(text string) (colorIndices [][]int, colors [][]string, esca
|
|||||||
// You can change the colors and text styles mid-text by inserting a color tag.
|
// You can change the colors and text styles mid-text by inserting a color tag.
|
||||||
// See the package description for details.
|
// See the package description for details.
|
||||||
//
|
//
|
||||||
// Returns the number of actual runes printed (not including color tags) and the
|
// Returns the number of actual bytes of the text printed (including color tags)
|
||||||
// actual width used for the printed runes.
|
// and the actual width used for the printed runes.
|
||||||
func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tcell.Color) (int, int) {
|
func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tcell.Color) (int, int) {
|
||||||
return printWithStyle(screen, text, x, y, maxWidth, align, tcell.StyleDefault.Foreground(color))
|
return printWithStyle(screen, text, x, y, maxWidth, align, tcell.StyleDefault.Foreground(color))
|
||||||
}
|
}
|
||||||
@ -217,115 +215,136 @@ func printWithStyle(screen tcell.Screen, text string, x, y, maxWidth, align int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decompose the text.
|
// Decompose the text.
|
||||||
colorIndices, colors, escapeIndices, strippedText, _ := decomposeString(text)
|
colorIndices, colors, escapeIndices, strippedText, strippedWidth := decomposeString(text)
|
||||||
|
|
||||||
// We deal with runes, not with bytes.
|
// We want to reduce all alignments to AlignLeft.
|
||||||
runes := []rune(strippedText)
|
if align == AlignRight {
|
||||||
|
if strippedWidth <= maxWidth {
|
||||||
// This helper function takes positions for a substring of "runes" and returns
|
// There's enough space for the entire text.
|
||||||
// a new string corresponding to this substring, making sure printing that
|
return printWithStyle(screen, text, x+maxWidth-strippedWidth, y, maxWidth, AlignLeft, style)
|
||||||
// substring will observe color tags.
|
}
|
||||||
substring := func(from, to int) string {
|
// Trim characters off the beginning.
|
||||||
var (
|
var (
|
||||||
colorPos, escapePos, runePos, startPos int
|
bytes, width, colorPos, escapePos, tagOffset int
|
||||||
foregroundColor, backgroundColor, attributes string
|
foregroundColor, backgroundColor, attributes string
|
||||||
)
|
)
|
||||||
if from >= len(runes) {
|
_, originalBackground, _ := style.Decompose()
|
||||||
return ""
|
iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
}
|
// Update color/escape tag offset and style.
|
||||||
for pos := range text {
|
if colorPos < len(colorIndices) && textPos+tagOffset >= colorIndices[colorPos][0] && textPos+tagOffset < colorIndices[colorPos][1] {
|
||||||
// Handle color tags.
|
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colors[colorPos])
|
||||||
if colorPos < len(colorIndices) && pos >= colorIndices[colorPos][0] && pos < colorIndices[colorPos][1] {
|
style = overlayStyle(originalBackground, style, foregroundColor, backgroundColor, attributes)
|
||||||
if pos == colorIndices[colorPos][1]-1 {
|
tagOffset += colorIndices[colorPos][1] - colorIndices[colorPos][0]
|
||||||
if runePos <= from {
|
colorPos++
|
||||||
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colors[colorPos])
|
}
|
||||||
}
|
if escapePos < len(escapeIndices) && textPos+tagOffset >= escapeIndices[escapePos][0] && textPos+tagOffset < escapeIndices[escapePos][1] {
|
||||||
colorPos++
|
tagOffset++
|
||||||
|
escapePos++
|
||||||
|
}
|
||||||
|
if strippedWidth-screenPos < maxWidth {
|
||||||
|
// We chopped off enough.
|
||||||
|
if escapePos > 0 && textPos+tagOffset-1 >= escapeIndices[escapePos-1][0] && textPos+tagOffset-1 < escapeIndices[escapePos-1][1] {
|
||||||
|
// Unescape open escape sequences.
|
||||||
|
escapeCharPos := escapeIndices[escapePos-1][1] - 2
|
||||||
|
text = text[:escapeCharPos] + text[escapeCharPos+1:]
|
||||||
}
|
}
|
||||||
continue
|
// Print and return.
|
||||||
|
bytes, width = printWithStyle(screen, text[textPos+tagOffset:], x, y, maxWidth, AlignLeft, style)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
// Handle escape tags.
|
})
|
||||||
if escapePos < len(escapeIndices) && pos >= escapeIndices[escapePos][0] && pos < escapeIndices[escapePos][1] {
|
return bytes, width
|
||||||
if pos == escapeIndices[escapePos][1]-1 {
|
|
||||||
escapePos++
|
|
||||||
} else if pos == escapeIndices[escapePos][1]-2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check boundaries.
|
|
||||||
if runePos == from {
|
|
||||||
startPos = pos
|
|
||||||
} else if runePos >= to {
|
|
||||||
return fmt.Sprintf(`[%s:%s:%s]%s`, foregroundColor, backgroundColor, attributes, text[startPos:pos])
|
|
||||||
}
|
|
||||||
|
|
||||||
runePos++
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(`[%s:%s:%s]%s`, foregroundColor, backgroundColor, attributes, text[startPos:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want to reduce everything to AlignLeft.
|
|
||||||
if align == AlignRight {
|
|
||||||
width := 0
|
|
||||||
start := len(runes)
|
|
||||||
for index := start - 1; index >= 0; index-- {
|
|
||||||
w := runewidth.RuneWidth(runes[index])
|
|
||||||
if width+w > maxWidth {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
width += w
|
|
||||||
start = index
|
|
||||||
}
|
|
||||||
for start < len(runes) && runewidth.RuneWidth(runes[start]) == 0 {
|
|
||||||
start++
|
|
||||||
}
|
|
||||||
return printWithStyle(screen, substring(start, len(runes)), x+maxWidth-width, y, width, AlignLeft, style)
|
|
||||||
} else if align == AlignCenter {
|
} else if align == AlignCenter {
|
||||||
width := runewidth.StringWidth(strippedText)
|
if strippedWidth == maxWidth {
|
||||||
if width == maxWidth {
|
|
||||||
// Use the exact space.
|
// Use the exact space.
|
||||||
return printWithStyle(screen, text, x, y, maxWidth, AlignLeft, style)
|
return printWithStyle(screen, text, x, y, maxWidth, AlignLeft, style)
|
||||||
} else if width < maxWidth {
|
} else if strippedWidth < maxWidth {
|
||||||
// We have more space than we need.
|
// We have more space than we need.
|
||||||
half := (maxWidth - width) / 2
|
half := (maxWidth - strippedWidth) / 2
|
||||||
return printWithStyle(screen, text, x+half, y, maxWidth-half, AlignLeft, style)
|
return printWithStyle(screen, text, x+half, y, maxWidth-half, AlignLeft, style)
|
||||||
} else {
|
} else {
|
||||||
// Chop off runes until we have a perfect fit.
|
// Chop off runes until we have a perfect fit.
|
||||||
var choppedLeft, choppedRight, leftIndex, rightIndex int
|
var choppedLeft, choppedRight, leftIndex, rightIndex int
|
||||||
rightIndex = len(runes) - 1
|
rightIndex = len(strippedText)
|
||||||
for rightIndex > leftIndex && width-choppedLeft-choppedRight > maxWidth {
|
for rightIndex-1 > leftIndex && strippedWidth-choppedLeft-choppedRight > maxWidth {
|
||||||
if choppedLeft < choppedRight {
|
if choppedLeft < choppedRight {
|
||||||
leftWidth := runewidth.RuneWidth(runes[leftIndex])
|
// Iterate on the left by one character.
|
||||||
choppedLeft += leftWidth
|
iterateString(strippedText[leftIndex:], func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
leftIndex++
|
choppedLeft += screenWidth
|
||||||
for leftIndex < len(runes) && leftIndex < rightIndex && runewidth.RuneWidth(runes[leftIndex]) == 0 {
|
leftIndex += textWidth
|
||||||
leftIndex++
|
return true
|
||||||
}
|
})
|
||||||
} else {
|
} else {
|
||||||
rightWidth := runewidth.RuneWidth(runes[rightIndex])
|
// Iterate on the right by one character.
|
||||||
choppedRight += rightWidth
|
iterateStringReverse(strippedText[leftIndex:rightIndex], func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
rightIndex--
|
choppedRight += screenWidth
|
||||||
|
rightIndex -= textWidth
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return printWithStyle(screen, substring(leftIndex, rightIndex), x, y, maxWidth, AlignLeft, style)
|
|
||||||
|
// Add tag offsets and determine start style.
|
||||||
|
var (
|
||||||
|
colorPos, escapePos, tagOffset int
|
||||||
|
foregroundColor, backgroundColor, attributes string
|
||||||
|
)
|
||||||
|
_, originalBackground, _ := style.Decompose()
|
||||||
|
for index := range strippedText {
|
||||||
|
// We only need the offset of the left index.
|
||||||
|
if index > leftIndex {
|
||||||
|
// We're done.
|
||||||
|
if escapePos > 0 && leftIndex+tagOffset-1 >= escapeIndices[escapePos-1][0] && leftIndex+tagOffset-1 < escapeIndices[escapePos-1][1] {
|
||||||
|
// Unescape open escape sequences.
|
||||||
|
escapeCharPos := escapeIndices[escapePos-1][1] - 2
|
||||||
|
text = text[:escapeCharPos] + text[escapeCharPos+1:]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update color/escape tag offset.
|
||||||
|
if colorPos < len(colorIndices) && index+tagOffset >= colorIndices[colorPos][0] && index+tagOffset < colorIndices[colorPos][1] {
|
||||||
|
if index <= leftIndex {
|
||||||
|
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colors[colorPos])
|
||||||
|
style = overlayStyle(originalBackground, style, foregroundColor, backgroundColor, attributes)
|
||||||
|
}
|
||||||
|
tagOffset += colorIndices[colorPos][1] - colorIndices[colorPos][0]
|
||||||
|
colorPos++
|
||||||
|
}
|
||||||
|
if escapePos < len(escapeIndices) && index+tagOffset >= escapeIndices[escapePos][0] && index+tagOffset < escapeIndices[escapePos][1] {
|
||||||
|
tagOffset++
|
||||||
|
escapePos++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return printWithStyle(screen, text[leftIndex+tagOffset:], x, y, maxWidth, AlignLeft, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw text.
|
// Draw text.
|
||||||
drawn := 0
|
|
||||||
drawnWidth := 0
|
|
||||||
var (
|
var (
|
||||||
colorPos, escapePos int
|
drawn, drawnWidth, colorPos, escapePos, tagOffset int
|
||||||
foregroundColor, backgroundColor, attributes string
|
foregroundColor, backgroundColor, attributes string
|
||||||
)
|
)
|
||||||
runeSequence := make([]rune, 0, 10)
|
iterateString(strippedText, func(main rune, comb []rune, textPos, length, screenPos, screenWidth int) bool {
|
||||||
runeSeqWidth := 0
|
// Only continue if there is still space.
|
||||||
flush := func() {
|
if drawnWidth+screenWidth > maxWidth {
|
||||||
if len(runeSequence) == 0 {
|
return true
|
||||||
return // Nothing to flush.
|
}
|
||||||
|
|
||||||
|
// Handle color tags.
|
||||||
|
if colorPos < len(colorIndices) && textPos+tagOffset >= colorIndices[colorPos][0] && textPos+tagOffset < colorIndices[colorPos][1] {
|
||||||
|
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colors[colorPos])
|
||||||
|
tagOffset += colorIndices[colorPos][1] - colorIndices[colorPos][0]
|
||||||
|
colorPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle scape tags.
|
||||||
|
if escapePos < len(escapeIndices) && textPos+tagOffset >= escapeIndices[escapePos][0] && textPos+tagOffset < escapeIndices[escapePos][1] {
|
||||||
|
if textPos+tagOffset == escapeIndices[escapePos][1]-2 {
|
||||||
|
tagOffset++
|
||||||
|
escapePos++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the rune sequence.
|
// Print the rune sequence.
|
||||||
@ -333,69 +352,23 @@ func printWithStyle(screen tcell.Screen, text string, x, y, maxWidth, align int,
|
|||||||
_, _, finalStyle, _ := screen.GetContent(finalX, y)
|
_, _, finalStyle, _ := screen.GetContent(finalX, y)
|
||||||
_, background, _ := finalStyle.Decompose()
|
_, background, _ := finalStyle.Decompose()
|
||||||
finalStyle = overlayStyle(background, style, foregroundColor, backgroundColor, attributes)
|
finalStyle = overlayStyle(background, style, foregroundColor, backgroundColor, attributes)
|
||||||
var comb []rune
|
for offset := screenWidth - 1; offset >= 0; offset-- {
|
||||||
if len(runeSequence) > 1 && !unicode.IsControl(runeSequence[1]) {
|
// To avoid undesired effects, we populate all cells.
|
||||||
// Allocate space for the combining characters only when necessary.
|
if offset == 0 {
|
||||||
comb = make([]rune, len(runeSequence)-1)
|
screen.SetContent(finalX+offset, y, main, comb, finalStyle)
|
||||||
copy(comb, runeSequence[1:])
|
} else {
|
||||||
}
|
screen.SetContent(finalX+offset, y, ' ', nil, finalStyle)
|
||||||
for offset := 0; offset < runeSeqWidth; offset++ {
|
|
||||||
// To avoid undesired effects, we place the same character in all cells.
|
|
||||||
screen.SetContent(finalX+offset, y, runeSequence[0], comb, finalStyle)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance and reset.
|
|
||||||
drawn += len(runeSequence)
|
|
||||||
drawnWidth += runeSeqWidth
|
|
||||||
runeSequence = runeSequence[:0]
|
|
||||||
runeSeqWidth = 0
|
|
||||||
}
|
|
||||||
for pos, ch := range text {
|
|
||||||
// Handle color tags.
|
|
||||||
if colorPos < len(colorIndices) && pos >= colorIndices[colorPos][0] && pos < colorIndices[colorPos][1] {
|
|
||||||
flush()
|
|
||||||
if pos == colorIndices[colorPos][1]-1 {
|
|
||||||
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colors[colorPos])
|
|
||||||
colorPos++
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle escape tags.
|
|
||||||
if escapePos < len(escapeIndices) && pos >= escapeIndices[escapePos][0] && pos < escapeIndices[escapePos][1] {
|
|
||||||
flush()
|
|
||||||
if pos == escapeIndices[escapePos][1]-1 {
|
|
||||||
escapePos++
|
|
||||||
} else if pos == escapeIndices[escapePos][1]-2 {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have enough space for this rune.
|
// Advance.
|
||||||
chWidth := runewidth.RuneWidth(ch)
|
drawn += length
|
||||||
if drawnWidth+chWidth > maxWidth {
|
drawnWidth += screenWidth
|
||||||
break // No. We're done then.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put this rune in the queue.
|
return false
|
||||||
if chWidth == 0 {
|
})
|
||||||
// If this is not a modifier, we treat it as a space character.
|
|
||||||
if len(runeSequence) == 0 {
|
|
||||||
ch = ' '
|
|
||||||
chWidth = 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We have a character. Flush all previous runes.
|
|
||||||
flush()
|
|
||||||
}
|
|
||||||
runeSequence = append(runeSequence, ch)
|
|
||||||
runeSeqWidth += chWidth
|
|
||||||
}
|
|
||||||
if drawnWidth+runeSeqWidth <= maxWidth {
|
|
||||||
flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
return drawn, drawnWidth
|
return drawn + tagOffset + len(escapeIndices), drawnWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintSimple prints white text to the screen at the given position.
|
// PrintSimple prints white text to the screen at the given position.
|
||||||
@ -421,102 +394,83 @@ func WordWrap(text string, width int) (lines []string) {
|
|||||||
colorTagIndices, _, escapeIndices, strippedText, _ := decomposeString(text)
|
colorTagIndices, _, escapeIndices, strippedText, _ := decomposeString(text)
|
||||||
|
|
||||||
// Find candidate breakpoints.
|
// Find candidate breakpoints.
|
||||||
breakPoints := boundaryPattern.FindAllStringIndex(strippedText, -1)
|
breakpoints := boundaryPattern.FindAllStringSubmatchIndex(strippedText, -1)
|
||||||
|
// Results in one entry for each candidate. Each entry is an array a of
|
||||||
|
// indices into strippedText where a[6] < 0 for newline/punctuation matches
|
||||||
|
// and a[4] < 0 for whitespace matches.
|
||||||
|
|
||||||
// This helper function adds a new line to the result slice. The provided
|
// Process stripped text one character at a time.
|
||||||
// positions are in stripped index space.
|
var (
|
||||||
addLine := func(from, to int) {
|
colorPos, escapePos, breakpointPos, tagOffset int
|
||||||
// Shift indices back to original index space.
|
lastBreakpoint, lastContinuation, currentLineStart int
|
||||||
var colorTagIndex, escapeIndex int
|
lineWidth, continuationWidth int
|
||||||
for colorTagIndex < len(colorTagIndices) && to >= colorTagIndices[colorTagIndex][0] ||
|
newlineBreakpoint bool
|
||||||
escapeIndex < len(escapeIndices) && to >= escapeIndices[escapeIndex][0] {
|
)
|
||||||
past := 0
|
unescape := func(substr string, startIndex int) string {
|
||||||
if colorTagIndex < len(colorTagIndices) {
|
// A helper function to unescape escaped tags.
|
||||||
tagWidth := colorTagIndices[colorTagIndex][1] - colorTagIndices[colorTagIndex][0]
|
for index := escapePos; index >= 0; index-- {
|
||||||
if colorTagIndices[colorTagIndex][0] < from {
|
if index < len(escapeIndices) && startIndex > escapeIndices[index][0] && startIndex < escapeIndices[index][1]-1 {
|
||||||
from += tagWidth
|
pos := escapeIndices[index][1] - 2 - startIndex
|
||||||
to += tagWidth
|
return substr[:pos] + substr[pos+1:]
|
||||||
colorTagIndex++
|
|
||||||
} else if colorTagIndices[colorTagIndex][0] < to {
|
|
||||||
to += tagWidth
|
|
||||||
colorTagIndex++
|
|
||||||
} else {
|
|
||||||
past++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
past++
|
|
||||||
}
|
|
||||||
if escapeIndex < len(escapeIndices) {
|
|
||||||
tagWidth := escapeIndices[escapeIndex][1] - escapeIndices[escapeIndex][0]
|
|
||||||
if escapeIndices[escapeIndex][0] < from {
|
|
||||||
from += tagWidth
|
|
||||||
to += tagWidth
|
|
||||||
escapeIndex++
|
|
||||||
} else if escapeIndices[escapeIndex][0] < to {
|
|
||||||
to += tagWidth
|
|
||||||
escapeIndex++
|
|
||||||
} else {
|
|
||||||
past++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
past++
|
|
||||||
}
|
|
||||||
if past == 2 {
|
|
||||||
break // All other indices are beyond the requested string.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lines = append(lines, text[from:to])
|
return substr
|
||||||
}
|
}
|
||||||
|
iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
|
||||||
// Determine final breakpoints.
|
// Handle colour tags.
|
||||||
var start, lastEnd, newStart, breakPoint int
|
if colorPos < len(colorTagIndices) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] {
|
||||||
for {
|
tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0]
|
||||||
// What's our candidate string?
|
colorPos++
|
||||||
var candidate string
|
|
||||||
if breakPoint < len(breakPoints) {
|
|
||||||
candidate = text[start:breakPoints[breakPoint][1]]
|
|
||||||
} else {
|
|
||||||
candidate = text[start:]
|
|
||||||
}
|
}
|
||||||
candidate = strings.TrimRightFunc(candidate, unicode.IsSpace)
|
|
||||||
|
|
||||||
if runewidth.StringWidth(candidate) >= width {
|
// Handle escape tags.
|
||||||
// We're past the available width.
|
if escapePos < len(escapeIndices) && textPos+tagOffset == escapeIndices[escapePos][1]-2 {
|
||||||
if lastEnd > start {
|
tagOffset++
|
||||||
// Use the previous candidate.
|
escapePos++
|
||||||
addLine(start, lastEnd)
|
|
||||||
start = newStart
|
|
||||||
} else {
|
|
||||||
// We have no previous candidate. Make a hard break.
|
|
||||||
var lineWidth int
|
|
||||||
for index, ch := range text {
|
|
||||||
if index < start {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
chWidth := runewidth.RuneWidth(ch)
|
|
||||||
if lineWidth > 0 && lineWidth+chWidth >= width {
|
|
||||||
addLine(start, index)
|
|
||||||
start = index
|
|
||||||
break
|
|
||||||
}
|
|
||||||
lineWidth += chWidth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We haven't hit the right border yet.
|
|
||||||
if breakPoint >= len(breakPoints) {
|
|
||||||
// It's the last line. We're done.
|
|
||||||
if len(candidate) > 0 {
|
|
||||||
addLine(start, len(strippedText))
|
|
||||||
}
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
// We have a new candidate.
|
|
||||||
lastEnd = start + len(candidate)
|
|
||||||
newStart = breakPoints[breakPoint][1]
|
|
||||||
breakPoint++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if a break is warranted.
|
||||||
|
afterContinuation := lastContinuation > 0 && textPos+tagOffset >= lastContinuation
|
||||||
|
noBreakpoint := lastContinuation == 0
|
||||||
|
beyondWidth := lineWidth > 0 && lineWidth > width
|
||||||
|
if beyondWidth && noBreakpoint {
|
||||||
|
// We need a hard break without a breakpoint.
|
||||||
|
lines = append(lines, unescape(text[currentLineStart:textPos+tagOffset], currentLineStart))
|
||||||
|
currentLineStart = textPos + tagOffset
|
||||||
|
lineWidth = continuationWidth
|
||||||
|
} else if afterContinuation && (beyondWidth || newlineBreakpoint) {
|
||||||
|
// Break at last breakpoint or at newline.
|
||||||
|
lines = append(lines, unescape(text[currentLineStart:lastBreakpoint], currentLineStart))
|
||||||
|
currentLineStart = lastContinuation
|
||||||
|
lineWidth = continuationWidth
|
||||||
|
lastBreakpoint, lastContinuation, newlineBreakpoint = 0, 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this a breakpoint?
|
||||||
|
if breakpointPos < len(breakpoints) && textPos == breakpoints[breakpointPos][0] {
|
||||||
|
// Yes, it is. Set up breakpoint infos depending on its type.
|
||||||
|
lastBreakpoint = breakpoints[breakpointPos][0] + tagOffset
|
||||||
|
lastContinuation = breakpoints[breakpointPos][1] + tagOffset
|
||||||
|
newlineBreakpoint = main == '\n'
|
||||||
|
if breakpoints[breakpointPos][6] < 0 && !newlineBreakpoint {
|
||||||
|
lastBreakpoint++ // Don't skip punctuation.
|
||||||
|
}
|
||||||
|
breakpointPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once we hit the continuation point, we start buffering widths.
|
||||||
|
if textPos+tagOffset < lastContinuation {
|
||||||
|
continuationWidth = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
lineWidth += screenWidth
|
||||||
|
continuationWidth += screenWidth
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
// Flush the rest.
|
||||||
|
if currentLineStart < len(text) {
|
||||||
|
lines = append(lines, unescape(text[currentLineStart:], currentLineStart))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -531,3 +485,121 @@ func WordWrap(text string, width int) (lines []string) {
|
|||||||
func Escape(text string) string {
|
func Escape(text string) string {
|
||||||
return nonEscapePattern.ReplaceAllString(text, "$1[]")
|
return nonEscapePattern.ReplaceAllString(text, "$1[]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// iterateString iterates through the given string one printed character at a
|
||||||
|
// time. For each such character, the callback function is called with the
|
||||||
|
// Unicode code points of the character (the first rune and any combining runes
|
||||||
|
// which may be nil if there aren't any), the starting position (in bytes)
|
||||||
|
// within the original string, its length in bytes, the screen position of the
|
||||||
|
// character, and the screen width of it. The iteration stops if the callback
|
||||||
|
// returns true. This function returns true if the iteration was stopped before
|
||||||
|
// the last character.
|
||||||
|
func iterateString(text string, callback func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool) bool {
|
||||||
|
var (
|
||||||
|
runes []rune
|
||||||
|
lastZeroWidthJoiner bool
|
||||||
|
startIndex int
|
||||||
|
startPos int
|
||||||
|
pos int
|
||||||
|
)
|
||||||
|
|
||||||
|
// Helper function which invokes the callback.
|
||||||
|
flush := func(index int) bool {
|
||||||
|
var comb []rune
|
||||||
|
if len(runes) > 1 {
|
||||||
|
comb = runes[1:]
|
||||||
|
}
|
||||||
|
return callback(runes[0], comb, startIndex, index-startIndex, startPos, pos-startPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
for index, r := range text {
|
||||||
|
if unicode.In(r, unicode.Lm, unicode.M) || r == '\u200d' {
|
||||||
|
lastZeroWidthJoiner = r == '\u200d'
|
||||||
|
} else {
|
||||||
|
// We have a rune that's not a modifier. It could be the beginning of a
|
||||||
|
// new character.
|
||||||
|
if !lastZeroWidthJoiner {
|
||||||
|
if len(runes) > 0 {
|
||||||
|
// It is. Invoke callback.
|
||||||
|
if flush(index) {
|
||||||
|
return true // We're done.
|
||||||
|
}
|
||||||
|
// Reset rune store.
|
||||||
|
runes = runes[:0]
|
||||||
|
startIndex = index
|
||||||
|
startPos = pos
|
||||||
|
}
|
||||||
|
pos += runewidth.RuneWidth(r)
|
||||||
|
} else {
|
||||||
|
lastZeroWidthJoiner = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runes = append(runes, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush any remaining runes.
|
||||||
|
if len(runes) > 0 {
|
||||||
|
flush(len(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterateStringReverse iterates through the given string in reverse, starting
|
||||||
|
// from the end of the string, one printed character at a time. For each such
|
||||||
|
// character, the callback function is called with the Unicode code points of
|
||||||
|
// the character (the first rune and any combining runes which may be nil if
|
||||||
|
// there aren't any), the starting position (in bytes) within the original
|
||||||
|
// string, its length in bytes, the screen position of the character, and the
|
||||||
|
// screen width of it. The iteration stops if the callback returns true. This
|
||||||
|
// function returns true if the iteration was stopped before the last character.
|
||||||
|
func iterateStringReverse(text string, callback func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool) bool {
|
||||||
|
type runePos struct {
|
||||||
|
r rune
|
||||||
|
pos int // The byte position of the rune in the original string.
|
||||||
|
width int // The screen width of the rune.
|
||||||
|
mod bool // Modifier or zero-width-joiner.
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use the following:
|
||||||
|
// len(text) >= number of runes in text.
|
||||||
|
|
||||||
|
// Put all runes into a runePos slice in reverse.
|
||||||
|
runesReverse := make([]runePos, len(text))
|
||||||
|
index := len(text) - 1
|
||||||
|
for pos, ch := range text {
|
||||||
|
runesReverse[index].r = ch
|
||||||
|
runesReverse[index].pos = pos
|
||||||
|
runesReverse[index].width = runewidth.RuneWidth(ch)
|
||||||
|
runesReverse[index].mod = unicode.In(ch, unicode.Lm, unicode.M) || ch == '\u200d'
|
||||||
|
index--
|
||||||
|
}
|
||||||
|
runesReverse = runesReverse[index+1:]
|
||||||
|
|
||||||
|
// Parse reverse runes.
|
||||||
|
var screenWidth int
|
||||||
|
buffer := make([]rune, len(text)) // We fill this up from the back so it's forward again.
|
||||||
|
bufferPos := len(text)
|
||||||
|
stringWidth := runewidth.StringWidth(text)
|
||||||
|
for index, r := range runesReverse {
|
||||||
|
// Put this rune into the buffer.
|
||||||
|
bufferPos--
|
||||||
|
buffer[bufferPos] = r.r
|
||||||
|
|
||||||
|
// Do we need to flush the buffer?
|
||||||
|
if r.pos == 0 || !r.mod && runesReverse[index+1].r != '\u200d' {
|
||||||
|
// Yes, invoke callback.
|
||||||
|
var comb []rune
|
||||||
|
if len(text)-bufferPos > 1 {
|
||||||
|
comb = buffer[bufferPos+1:]
|
||||||
|
}
|
||||||
|
if callback(r.r, comb, r.pos, len(text)-r.pos, stringWidth-screenWidth, r.width) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
screenWidth += r.width
|
||||||
|
bufferPos = len(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
674
vendor/github.com/sticreations/spotigopher/LICENCE.md
generated
vendored
Normal file
674
vendor/github.com/sticreations/spotigopher/LICENCE.md
generated
vendored
Normal file
@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
131
vendor/github.com/sticreations/spotigopher/spotigopher/spotigopher.go
generated
vendored
131
vendor/github.com/sticreations/spotigopher/spotigopher/spotigopher.go
generated
vendored
@ -3,6 +3,10 @@ package spotigopher
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/godbus/dbus"
|
"github.com/godbus/dbus"
|
||||||
)
|
)
|
||||||
@ -51,29 +55,44 @@ func getSpotifyBus() dbus.BusObject {
|
|||||||
PlayPause sends a PlayPause Command on the DBus
|
PlayPause sends a PlayPause Command on the DBus
|
||||||
*/
|
*/
|
||||||
func (s *SpotifyClient) PlayPause() {
|
func (s *SpotifyClient) PlayPause() {
|
||||||
sendAction("org.mpris.MediaPlayer2.Player.PlayPause")
|
if runtime.GOOS == "darwin" {
|
||||||
|
sendDarwinAction("playpause")
|
||||||
|
} else {
|
||||||
|
sendAction("org.mpris.MediaPlayer2.Player.PlayPause")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Next sends a Next Command on the DBus
|
Next sends a Next Command on the DBus
|
||||||
*/
|
*/
|
||||||
func (s *SpotifyClient) Next() {
|
func (s *SpotifyClient) Next() {
|
||||||
sendAction("org.mpris.MediaPlayer2.Player.Next")
|
if runtime.GOOS == "darwin" {
|
||||||
|
sendDarwinAction("next")
|
||||||
|
} else {
|
||||||
|
sendAction("org.mpris.MediaPlayer2.Player.Next")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Previous sends a Previous Command on the DBus
|
Previous sends a Previous Command on the DBus
|
||||||
*/
|
*/
|
||||||
func (s *SpotifyClient) Previous() {
|
func (s *SpotifyClient) Previous() {
|
||||||
sendAction("org.mpris.MediaPlayer2.Player.Previous")
|
if runtime.GOOS == "darwin" {
|
||||||
|
sendDarwinAction("previous")
|
||||||
|
} else {
|
||||||
|
sendAction("org.mpris.MediaPlayer2.Player.Previous")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Stop sends a Stop Command on the DBus
|
Stop sends a Stop Command on the DBus
|
||||||
*/
|
*/
|
||||||
func (s *SpotifyClient) Stop() {
|
func (s *SpotifyClient) Stop() {
|
||||||
sendAction("org.mpris.MediaPlayer2.Player.Stop")
|
if runtime.GOOS == "darwin" {
|
||||||
|
sendDarwinAction("stop")
|
||||||
|
} else {
|
||||||
|
sendAction("org.mpris.MediaPlayer2.Player.Stop")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -82,29 +101,97 @@ GetInfo returns all Spotify related Information, when Spotify is running
|
|||||||
func (s *SpotifyClient) GetInfo() (Info, error) {
|
func (s *SpotifyClient) GetInfo() (Info, error) {
|
||||||
info := Info{}
|
info := Info{}
|
||||||
|
|
||||||
spotifyBus := getSpotifyBus()
|
if runtime.GOOS == "linux" {
|
||||||
props, err := spotifyBus.GetProperty("org.mpris.MediaPlayer2.Player.Metadata")
|
spotifyBus := getSpotifyBus()
|
||||||
if err != nil {
|
props, err := spotifyBus.GetProperty("org.mpris.MediaPlayer2.Player.Metadata")
|
||||||
return Info{}, errors.New("Could not get any Info from Spotify. Are you sure Spotify is running?")
|
if err != nil {
|
||||||
}
|
return Info{}, errors.New("Could not get any Info from Spotify. Are you sure Spotify is running?")
|
||||||
songData := props.Value().(map[string]dbus.Variant)
|
}
|
||||||
info.TrackID = songData["mpris:trackid"].Value().(string)
|
songData := props.Value().(map[string]dbus.Variant)
|
||||||
info.Artist = songData["xesam:artist"].Value().([]string)
|
info.TrackID = songData["mpris:trackid"].Value().(string)
|
||||||
info.Title = songData["xesam:title"].Value().(string)
|
info.Artist = songData["xesam:artist"].Value().([]string)
|
||||||
info.Album = songData["xesam:album"].Value().(string)
|
info.Title = songData["xesam:title"].Value().(string)
|
||||||
info.TrackNumber = songData["xesam:trackNumber"].Value().(int32)
|
info.Album = songData["xesam:album"].Value().(string)
|
||||||
info.URL = songData["xesam:url"].Value().(string)
|
info.TrackNumber = songData["xesam:trackNumber"].Value().(int32)
|
||||||
info.ArtworkURL = songData["mpris:artUrl"].Value().(string)
|
info.URL = songData["xesam:url"].Value().(string)
|
||||||
|
info.ArtworkURL = songData["mpris:artUrl"].Value().(string)
|
||||||
|
|
||||||
status, err := spotifyBus.GetProperty("org.mpris.MediaPlayer2.Player.PlaybackStatus")
|
status, err := spotifyBus.GetProperty("org.mpris.MediaPlayer2.Player.PlaybackStatus")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Could not get Playback Status : %v", err)
|
log.Fatalf("Could not get Playback Status : %v", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
info.Status = status.Value().(string)
|
||||||
|
} else if runtime.GOOS == "darwin" {
|
||||||
|
info.TrackID = getDarwinInfo("trackid")
|
||||||
|
info.Artist = strings.Split(getDarwinInfo("artist"), ",")
|
||||||
|
info.Album = getDarwinInfo("album")
|
||||||
|
info.Title = getDarwinInfo("track")
|
||||||
|
tmpTrackNumber, err := strconv.ParseInt(getDarwinInfo("tracknumber"), 0, 32)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not get track number: %s", err)
|
||||||
|
}
|
||||||
|
info.TrackNumber = int32(tmpTrackNumber)
|
||||||
|
info.URL = getDarwinInfo("url")
|
||||||
|
info.ArtworkURL = getDarwinInfo("artworkurl")
|
||||||
|
info.Status = getDarwinInfo("status")
|
||||||
}
|
}
|
||||||
info.Status = status.Value().(string)
|
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDarwinInfo(infoType string) string {
|
||||||
|
args := []string{`-etell application "Spotify" to name of current track as string`}
|
||||||
|
switch infoType {
|
||||||
|
case "trackid":
|
||||||
|
args = []string{`-etell application "Spotify" to id of current track as string`}
|
||||||
|
case "artist":
|
||||||
|
args = []string{`-etell application "Spotify" to artist of current track as string`}
|
||||||
|
case "title":
|
||||||
|
args = []string{`-etell application "Spotify" to name of current track as string`}
|
||||||
|
case "album":
|
||||||
|
args = []string{`-etell application "Spotify" to album of current track as string`}
|
||||||
|
case "tracknumber":
|
||||||
|
args = []string{`-etell application "Spotify" to track number of current track as string`}
|
||||||
|
case "url":
|
||||||
|
args = []string{`-etell application "Spotify" to spotify url of current track as string`}
|
||||||
|
case "artworkurl":
|
||||||
|
args = []string{`-etell application "Spotify" to artwork url of current track as string`}
|
||||||
|
case "status":
|
||||||
|
args = []string{`-etell application "Spotify" to player state as string`}
|
||||||
|
default:
|
||||||
|
args = []string{`-etell application "Spotify" to name of current track as string`}
|
||||||
|
}
|
||||||
|
info, err := exec.Command("osascript", args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not get info: %s", infoType)
|
||||||
|
}
|
||||||
|
return strings.Trim(string(info), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendDarwinAction(action string) {
|
||||||
|
args := []string{`-etell application "Spotify" to pause`}
|
||||||
|
switch action {
|
||||||
|
case "play":
|
||||||
|
args = []string{`-etell application "Spotify" to play`}
|
||||||
|
case "pause":
|
||||||
|
args = []string{`-etell application "Spotify" to pause`}
|
||||||
|
case "stop":
|
||||||
|
args = []string{`-etell application "Spotify" to pause`}
|
||||||
|
case "playpause":
|
||||||
|
args = []string{`-etell application "Spotify" to playpause`}
|
||||||
|
case "next":
|
||||||
|
args = []string{`-etell application "Spotify" to next track`}
|
||||||
|
case "previous":
|
||||||
|
args = []string{`-etell application "Spotify" to previous track`}
|
||||||
|
default:
|
||||||
|
args = []string{`-etell application "Spotify" to pause`}
|
||||||
|
}
|
||||||
|
err := exec.Command("osascript", args...).Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not completed action: %s", action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func sendAction(method string) error {
|
func sendAction(method string) error {
|
||||||
sdbus := getSpotifyBus()
|
sdbus := getSpotifyBus()
|
||||||
call := sdbus.Call(method, 0)
|
call := sdbus.Call(method, 0)
|
||||||
|
4
vendor/github.com/xanzy/go-gitlab/.travis.yml
generated
vendored
4
vendor/github.com/xanzy/go-gitlab/.travis.yml
generated
vendored
@ -1,9 +1,9 @@
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.8.x
|
|
||||||
- 1.9.x
|
- 1.9.x
|
||||||
- 1.10.x
|
- 1.10.x
|
||||||
|
- 1.11.x
|
||||||
- master
|
- master
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
@ -14,7 +14,7 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- stage: lint
|
- stage: lint
|
||||||
script:
|
script:
|
||||||
- go get github.com/golang/lint/golint
|
- go get golang.org/x/lint/golint
|
||||||
- golint -set_exit_status
|
- golint -set_exit_status
|
||||||
- go vet -v
|
- go vet -v
|
||||||
- stage: test
|
- stage: test
|
||||||
|
20
vendor/github.com/xanzy/go-gitlab/README.md
generated
vendored
20
vendor/github.com/xanzy/go-gitlab/README.md
generated
vendored
@ -26,7 +26,7 @@ to add new and/or missing endpoints. Currently the following services are suppor
|
|||||||
- [x] Project-level Variables
|
- [x] Project-level Variables
|
||||||
- [x] Group-level Variables
|
- [x] Group-level Variables
|
||||||
- [x] Commits
|
- [x] Commits
|
||||||
- [ ] Custom Attributes
|
- [x] Custom Attributes
|
||||||
- [x] Deployments
|
- [x] Deployments
|
||||||
- [x] Deploy Keys
|
- [x] Deploy Keys
|
||||||
- [x] Environments
|
- [x] Environments
|
||||||
@ -36,13 +36,13 @@ to add new and/or missing endpoints. Currently the following services are suppor
|
|||||||
- [x] Feature flags
|
- [x] Feature flags
|
||||||
- [ ] Geo Nodes
|
- [ ] Geo Nodes
|
||||||
- [x] Gitignores templates
|
- [x] Gitignores templates
|
||||||
- [ ] GitLab CI Config templates
|
- [x] GitLab CI Config templates
|
||||||
- [x] Groups
|
- [x] Groups
|
||||||
- [ ] Group Access Requests
|
- [x] Group Access Requests
|
||||||
- [x] Group Members
|
- [x] Group Members
|
||||||
- [x] Issues
|
- [x] Issues
|
||||||
- [x] Issue Boards
|
- [x] Issue Boards
|
||||||
- [x] Group Issue Boards
|
- [x] Group Issue Boards
|
||||||
- [x] Jobs
|
- [x] Jobs
|
||||||
- [x] Keys
|
- [x] Keys
|
||||||
- [x] Labels
|
- [x] Labels
|
||||||
@ -50,19 +50,19 @@ to add new and/or missing endpoints. Currently the following services are suppor
|
|||||||
- [x] Merge Requests
|
- [x] Merge Requests
|
||||||
- [x] Merge Request Approvals
|
- [x] Merge Request Approvals
|
||||||
- [x] Project Milestones
|
- [x] Project Milestones
|
||||||
- [ ] Group Milestones
|
- [x] Group Milestones
|
||||||
- [x] Namespaces
|
- [x] Namespaces
|
||||||
- [x] Notes (comments)
|
- [x] Notes (comments)
|
||||||
- [ ] Discussions (threaded comments)
|
- [ ] Discussions (threaded comments)
|
||||||
- [x] Notification settings
|
- [x] Notification settings
|
||||||
- [ ] Open source license templates
|
- [x] Open source license templates
|
||||||
- [x] Pages Domains
|
- [x] Pages Domains
|
||||||
- [x] Pipelines
|
- [x] Pipelines
|
||||||
- [x] Pipeline Triggers
|
- [x] Pipeline Triggers
|
||||||
- [x] Pipeline Schedules
|
- [x] Pipeline Schedules
|
||||||
- [x] Projects (including setting Webhooks)
|
- [x] Projects (including setting Webhooks)
|
||||||
- [ ] Project Access Requests
|
- [x] Project Access Requests
|
||||||
- [ ] Project badges
|
- [x] Project badges
|
||||||
- [ ] Project import/export
|
- [ ] Project import/export
|
||||||
- [x] Project Members
|
- [x] Project Members
|
||||||
- [x] Project Snippets
|
- [x] Project Snippets
|
||||||
@ -70,11 +70,10 @@ to add new and/or missing endpoints. Currently the following services are suppor
|
|||||||
- [x] Repositories
|
- [x] Repositories
|
||||||
- [x] Repository Files
|
- [x] Repository Files
|
||||||
- [x] Runners
|
- [x] Runners
|
||||||
- [ ] Search
|
- [x] Search
|
||||||
- [x] Services
|
- [x] Services
|
||||||
- [x] Settings
|
- [x] Settings
|
||||||
- [x] Sidekiq metrics
|
- [x] Sidekiq metrics
|
||||||
- [x] Session
|
|
||||||
- [x] System Hooks
|
- [x] System Hooks
|
||||||
- [x] Tags
|
- [x] Tags
|
||||||
- [x] Todos
|
- [x] Todos
|
||||||
@ -150,7 +149,6 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For complete usage of go-gitlab, see the full [package docs](https://godoc.org/github.com/xanzy/go-gitlab).
|
For complete usage of go-gitlab, see the full [package docs](https://godoc.org/github.com/xanzy/go-gitlab).
|
||||||
|
237
vendor/github.com/xanzy/go-gitlab/access_requests.go
generated
vendored
Normal file
237
vendor/github.com/xanzy/go-gitlab/access_requests.go
generated
vendored
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccessRequest represents a access request for a group or project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html
|
||||||
|
type AccessRequest struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
RequestedAt *time.Time `json:"requested_at"`
|
||||||
|
AccessLevel AccessLevelValue `json:"access_level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccessRequestsService handles communication with the project/group
|
||||||
|
// access requests related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/access_requests.html
|
||||||
|
type AccessRequestsService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAccessRequestsOptions represents the available
|
||||||
|
// ListProjectAccessRequests() or ListGroupAccessRequests() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project
|
||||||
|
type ListAccessRequestsOptions ListOptions
|
||||||
|
|
||||||
|
// ListProjectAccessRequests gets a list of access requests
|
||||||
|
// viewable by the authenticated user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project
|
||||||
|
func (s *AccessRequestsService) ListProjectAccessRequests(pid interface{}, opt *ListAccessRequestsOptions, options ...OptionFunc) ([]*AccessRequest, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/access_requests", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ars []*AccessRequest
|
||||||
|
resp, err := s.client.Do(req, &ars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ars, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupAccessRequests gets a list of access requests
|
||||||
|
// viewable by the authenticated user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#list-access-requests-for-a-group-or-project
|
||||||
|
func (s *AccessRequestsService) ListGroupAccessRequests(gid interface{}, opt *ListAccessRequestsOptions, options ...OptionFunc) ([]*AccessRequest, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/access_requests", url.QueryEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ars []*AccessRequest
|
||||||
|
resp, err := s.client.Do(req, &ars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ars, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestProjectAccess requests access for the authenticated user
|
||||||
|
// to a group or project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#request-access-to-a-group-or-project
|
||||||
|
func (s *AccessRequestsService) RequestProjectAccess(pid interface{}, options ...OptionFunc) (*AccessRequest, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/access_requests", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := new(AccessRequest)
|
||||||
|
resp, err := s.client.Do(req, ar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestGroupAccess requests access for the authenticated user
|
||||||
|
// to a group or project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#request-access-to-a-group-or-project
|
||||||
|
func (s *AccessRequestsService) RequestGroupAccess(gid interface{}, options ...OptionFunc) (*AccessRequest, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/access_requests", url.QueryEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := new(AccessRequest)
|
||||||
|
resp, err := s.client.Do(req, ar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApproveAccessRequestOptions represents the available
|
||||||
|
// ApproveProjectAccessRequest() and ApproveGroupAccessRequest() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request
|
||||||
|
type ApproveAccessRequestOptions struct {
|
||||||
|
AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApproveProjectAccessRequest approves an access request for the given user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request
|
||||||
|
func (s *AccessRequestsService) ApproveProjectAccessRequest(pid interface{}, user int, opt *ApproveAccessRequestOptions, options ...OptionFunc) (*AccessRequest, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/access_requests/%d/approve", url.QueryEscape(project), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := new(AccessRequest)
|
||||||
|
resp, err := s.client.Do(req, ar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApproveGroupAccessRequest approves an access request for the given user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#approve-an-access-request
|
||||||
|
func (s *AccessRequestsService) ApproveGroupAccessRequest(gid interface{}, user int, opt *ApproveAccessRequestOptions, options ...OptionFunc) (*AccessRequest, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/access_requests/%d/approve", url.QueryEscape(group), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := new(AccessRequest)
|
||||||
|
resp, err := s.client.Do(req, ar)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DenyProjectAccessRequest denies an access request for the given user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#deny-an-access-request
|
||||||
|
func (s *AccessRequestsService) DenyProjectAccessRequest(pid interface{}, user int, options ...OptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/access_requests/%d", url.QueryEscape(project), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DenyGroupAccessRequest denies an access request for the given user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/access_requests.html#deny-an-access-request
|
||||||
|
func (s *AccessRequestsService) DenyGroupAccessRequest(gid interface{}, user int, options ...OptionFunc) (*Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/access_requests/%d", url.QueryEscape(group), user)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
70
vendor/github.com/xanzy/go-gitlab/ci_yml_templates.go
generated
vendored
Normal file
70
vendor/github.com/xanzy/go-gitlab/ci_yml_templates.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CIYMLTemplatesService handles communication with the gitlab
|
||||||
|
// CI YML templates related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html
|
||||||
|
type CIYMLTemplatesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// CIYMLTemplate represents a GitLab CI YML template.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html
|
||||||
|
type CIYMLTemplate struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCIYMLTemplatesOptions represents the available ListAllTemplates() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates
|
||||||
|
type ListCIYMLTemplatesOptions ListOptions
|
||||||
|
|
||||||
|
// ListAllTemplates get all GitLab CI YML templates.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html#list-gitlab-ci-yml-templates
|
||||||
|
func (s *CIYMLTemplatesService) ListAllTemplates(opt *ListCIYMLTemplatesOptions, options ...OptionFunc) ([]*CIYMLTemplate, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest("GET", "templates/gitlab_ci_ymls", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cts []*CIYMLTemplate
|
||||||
|
resp, err := s.client.Do(req, &cts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cts, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTemplate get a single GitLab CI YML template.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/gitlab_ci_ymls.html#single-gitlab-ci-yml-template
|
||||||
|
func (s *CIYMLTemplatesService) GetTemplate(key string, options ...OptionFunc) (*CIYMLTemplate, *Response, error) {
|
||||||
|
u := fmt.Sprintf("templates/gitlab_ci_ymls/%s", url.QueryEscape(key))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ct := new(CIYMLTemplate)
|
||||||
|
resp, err := s.client.Do(req, ct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ct, resp, err
|
||||||
|
}
|
171
vendor/github.com/xanzy/go-gitlab/custom_attributes.go
generated
vendored
Normal file
171
vendor/github.com/xanzy/go-gitlab/custom_attributes.go
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CustomAttributesService handles communication with the group, project and
|
||||||
|
// user custom attributes related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/custom_attributes.html
|
||||||
|
type CustomAttributesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomAttribute struct is used to unmarshal response to api calls.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/custom_attributes.html
|
||||||
|
type CustomAttribute struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCustomUserAttributes lists the custom attributes of the specified user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes
|
||||||
|
func (s *CustomAttributesService) ListCustomUserAttributes(user int, options ...OptionFunc) ([]*CustomAttribute, *Response, error) {
|
||||||
|
return s.listCustomAttributes("users", user, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCustomGroupAttributes lists the custom attributes of the specified group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes
|
||||||
|
func (s *CustomAttributesService) ListCustomGroupAttributes(group int, options ...OptionFunc) ([]*CustomAttribute, *Response, error) {
|
||||||
|
return s.listCustomAttributes("groups", group, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCustomProjectAttributes lists the custom attributes of the specified project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#list-custom-attributes
|
||||||
|
func (s *CustomAttributesService) ListCustomProjectAttributes(project int, options ...OptionFunc) ([]*CustomAttribute, *Response, error) {
|
||||||
|
return s.listCustomAttributes("projects", project, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CustomAttributesService) listCustomAttributes(resource string, id int, options ...OptionFunc) ([]*CustomAttribute, *Response, error) {
|
||||||
|
u := fmt.Sprintf("%s/%d/custom_attributes", resource, id)
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cas []*CustomAttribute
|
||||||
|
resp, err := s.client.Do(req, &cas)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return cas, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomUserAttribute returns the user attribute with a speciifc key.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute
|
||||||
|
func (s *CustomAttributesService) GetCustomUserAttribute(user int, key string, options ...OptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.getCustomAttribute("users", user, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomGroupAttribute returns the group attribute with a speciifc key.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute
|
||||||
|
func (s *CustomAttributesService) GetCustomGroupAttribute(group int, key string, options ...OptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.getCustomAttribute("groups", group, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomProjectAttribute returns the project attribute with a speciifc key.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#single-custom-attribute
|
||||||
|
func (s *CustomAttributesService) GetCustomProjectAttribute(project int, key string, options ...OptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.getCustomAttribute("projects", project, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CustomAttributesService) getCustomAttribute(resource string, id int, key string, options ...OptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, key)
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ca *CustomAttribute
|
||||||
|
resp, err := s.client.Do(req, &ca)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return ca, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCustomUserAttribute sets the custom attributes of the specified user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute
|
||||||
|
func (s *CustomAttributesService) SetCustomUserAttribute(user int, c CustomAttribute, options ...OptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.setCustomAttribute("users", user, c, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCustomGroupAttribute sets the custom attributes of the specified group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute
|
||||||
|
func (s *CustomAttributesService) SetCustomGroupAttribute(group int, c CustomAttribute, options ...OptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.setCustomAttribute("groups", group, c, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCustomProjectAttribute sets the custom attributes of the specified project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#set-custom-attribute
|
||||||
|
func (s *CustomAttributesService) SetCustomProjectAttribute(project int, c CustomAttribute, options ...OptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
return s.setCustomAttribute("projects", project, c, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CustomAttributesService) setCustomAttribute(resource string, id int, c CustomAttribute, options ...OptionFunc) (*CustomAttribute, *Response, error) {
|
||||||
|
u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, c.Key)
|
||||||
|
req, err := s.client.NewRequest("PUT", u, c, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ca := new(CustomAttribute)
|
||||||
|
resp, err := s.client.Do(req, ca)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return ca, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCustomUserAttribute removes the custom attribute of the specified user.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute
|
||||||
|
func (s *CustomAttributesService) DeleteCustomUserAttribute(user int, key string, options ...OptionFunc) (*Response, error) {
|
||||||
|
return s.deleteCustomAttribute("users", user, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCustomGroupAttribute removes the custom attribute of the specified group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute
|
||||||
|
func (s *CustomAttributesService) DeleteCustomGroupAttribute(group int, key string, options ...OptionFunc) (*Response, error) {
|
||||||
|
return s.deleteCustomAttribute("groups", group, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCustomProjectAttribute removes the custom attribute of the specified project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/custom_attributes.html#delete-custom-attribute
|
||||||
|
func (s *CustomAttributesService) DeleteCustomProjectAttribute(project int, key string, options ...OptionFunc) (*Response, error) {
|
||||||
|
return s.deleteCustomAttribute("projects", project, key, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CustomAttributesService) deleteCustomAttribute(resource string, id int, key string, options ...OptionFunc) (*Response, error) {
|
||||||
|
u := fmt.Sprintf("%s/%d/custom_attributes/%s", resource, id, key)
|
||||||
|
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
1112
vendor/github.com/xanzy/go-gitlab/discussions.go
generated
vendored
Normal file
1112
vendor/github.com/xanzy/go-gitlab/discussions.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
vendor/github.com/xanzy/go-gitlab/event_types.go
generated
vendored
19
vendor/github.com/xanzy/go-gitlab/event_types.go
generated
vendored
@ -477,6 +477,7 @@ type MergeEvent struct {
|
|||||||
WorkInProgress bool `json:"work_in_progress"`
|
WorkInProgress bool `json:"work_in_progress"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
|
OldRev string `json:"oldrev"`
|
||||||
Assignee struct {
|
Assignee struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@ -489,6 +490,24 @@ type MergeEvent struct {
|
|||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
AvatarURL string `json:"avatar_url"`
|
AvatarURL string `json:"avatar_url"`
|
||||||
} `json:"assignee"`
|
} `json:"assignee"`
|
||||||
|
Changes struct {
|
||||||
|
AssigneeID struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"assignee_id"`
|
||||||
|
Description struct {
|
||||||
|
Previous string `json:"previous"`
|
||||||
|
Current string `json:"current"`
|
||||||
|
} `json:"description"`
|
||||||
|
Labels struct {
|
||||||
|
Previous []Label `json:"previous"`
|
||||||
|
Current []Label `json:"current"`
|
||||||
|
} `json:"labels"`
|
||||||
|
UpdatedByID struct {
|
||||||
|
Previous int `json:"previous"`
|
||||||
|
Current int `json:"current"`
|
||||||
|
} `json:"updated_by_id"`
|
||||||
|
} `json:"changes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// WikiPageEvent represents a wiki page event.
|
// WikiPageEvent represents a wiki page event.
|
||||||
|
63
vendor/github.com/xanzy/go-gitlab/gitlab.go
generated
vendored
63
vendor/github.com/xanzy/go-gitlab/gitlab.go
generated
vendored
@ -64,12 +64,16 @@ type AccessLevelValue int
|
|||||||
//
|
//
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html
|
// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html
|
||||||
const (
|
const (
|
||||||
NoPermissions AccessLevelValue = 0
|
NoPermissions AccessLevelValue = 0
|
||||||
GuestPermissions AccessLevelValue = 10
|
GuestPermissions AccessLevelValue = 10
|
||||||
ReporterPermissions AccessLevelValue = 20
|
ReporterPermissions AccessLevelValue = 20
|
||||||
DeveloperPermissions AccessLevelValue = 30
|
DeveloperPermissions AccessLevelValue = 30
|
||||||
MasterPermissions AccessLevelValue = 40
|
MaintainerPermissions AccessLevelValue = 40
|
||||||
OwnerPermission AccessLevelValue = 50
|
OwnerPermissions AccessLevelValue = 50
|
||||||
|
|
||||||
|
// These are deprecated and should be removed in a future version
|
||||||
|
MasterPermissions AccessLevelValue = 40
|
||||||
|
OwnerPermission AccessLevelValue = 50
|
||||||
)
|
)
|
||||||
|
|
||||||
// BuildStateValue represents a GitLab build state.
|
// BuildStateValue represents a GitLab build state.
|
||||||
@ -273,13 +277,17 @@ type Client struct {
|
|||||||
UserAgent string
|
UserAgent string
|
||||||
|
|
||||||
// Services used for talking to different parts of the GitLab API.
|
// Services used for talking to different parts of the GitLab API.
|
||||||
|
AccessRequests *AccessRequestsService
|
||||||
AwardEmoji *AwardEmojiService
|
AwardEmoji *AwardEmojiService
|
||||||
Branches *BranchesService
|
Branches *BranchesService
|
||||||
BuildVariables *BuildVariablesService
|
BuildVariables *BuildVariablesService
|
||||||
BroadcastMessage *BroadcastMessagesService
|
BroadcastMessage *BroadcastMessagesService
|
||||||
|
CIYMLTemplate *CIYMLTemplatesService
|
||||||
Commits *CommitsService
|
Commits *CommitsService
|
||||||
|
CustomAttribute *CustomAttributesService
|
||||||
DeployKeys *DeployKeysService
|
DeployKeys *DeployKeysService
|
||||||
Deployments *DeploymentsService
|
Deployments *DeploymentsService
|
||||||
|
Discussions *DiscussionsService
|
||||||
Environments *EnvironmentsService
|
Environments *EnvironmentsService
|
||||||
Events *EventsService
|
Events *EventsService
|
||||||
Features *FeaturesService
|
Features *FeaturesService
|
||||||
@ -295,6 +303,7 @@ type Client struct {
|
|||||||
Keys *KeysService
|
Keys *KeysService
|
||||||
Boards *IssueBoardsService
|
Boards *IssueBoardsService
|
||||||
Labels *LabelsService
|
Labels *LabelsService
|
||||||
|
LicenseTemplates *LicenseTemplatesService
|
||||||
MergeRequests *MergeRequestsService
|
MergeRequests *MergeRequestsService
|
||||||
MergeRequestApprovals *MergeRequestApprovalsService
|
MergeRequestApprovals *MergeRequestApprovalsService
|
||||||
Milestones *MilestonesService
|
Milestones *MilestonesService
|
||||||
@ -307,6 +316,7 @@ type Client struct {
|
|||||||
PipelineTriggers *PipelineTriggersService
|
PipelineTriggers *PipelineTriggersService
|
||||||
Projects *ProjectsService
|
Projects *ProjectsService
|
||||||
ProjectMembers *ProjectMembersService
|
ProjectMembers *ProjectMembersService
|
||||||
|
ProjectBadges *ProjectBadgesService
|
||||||
ProjectSnippets *ProjectSnippetsService
|
ProjectSnippets *ProjectSnippetsService
|
||||||
ProjectVariables *ProjectVariablesService
|
ProjectVariables *ProjectVariablesService
|
||||||
ProtectedBranches *ProtectedBranchesService
|
ProtectedBranches *ProtectedBranchesService
|
||||||
@ -315,7 +325,6 @@ type Client struct {
|
|||||||
Runners *RunnersService
|
Runners *RunnersService
|
||||||
Search *SearchService
|
Search *SearchService
|
||||||
Services *ServicesService
|
Services *ServicesService
|
||||||
Session *SessionService
|
|
||||||
Settings *SettingsService
|
Settings *SettingsService
|
||||||
Sidekiq *SidekiqService
|
Sidekiq *SidekiqService
|
||||||
Snippets *SnippetsService
|
Snippets *SnippetsService
|
||||||
@ -407,13 +416,17 @@ func newClient(httpClient *http.Client) *Client {
|
|||||||
timeStats := &timeStatsService{client: c}
|
timeStats := &timeStatsService{client: c}
|
||||||
|
|
||||||
// Create all the public services.
|
// Create all the public services.
|
||||||
|
c.AccessRequests = &AccessRequestsService{client: c}
|
||||||
c.AwardEmoji = &AwardEmojiService{client: c}
|
c.AwardEmoji = &AwardEmojiService{client: c}
|
||||||
c.Branches = &BranchesService{client: c}
|
c.Branches = &BranchesService{client: c}
|
||||||
c.BuildVariables = &BuildVariablesService{client: c}
|
c.BuildVariables = &BuildVariablesService{client: c}
|
||||||
c.BroadcastMessage = &BroadcastMessagesService{client: c}
|
c.BroadcastMessage = &BroadcastMessagesService{client: c}
|
||||||
|
c.CIYMLTemplate = &CIYMLTemplatesService{client: c}
|
||||||
c.Commits = &CommitsService{client: c}
|
c.Commits = &CommitsService{client: c}
|
||||||
|
c.CustomAttribute = &CustomAttributesService{client: c}
|
||||||
c.DeployKeys = &DeployKeysService{client: c}
|
c.DeployKeys = &DeployKeysService{client: c}
|
||||||
c.Deployments = &DeploymentsService{client: c}
|
c.Deployments = &DeploymentsService{client: c}
|
||||||
|
c.Discussions = &DiscussionsService{client: c}
|
||||||
c.Environments = &EnvironmentsService{client: c}
|
c.Environments = &EnvironmentsService{client: c}
|
||||||
c.Events = &EventsService{client: c}
|
c.Events = &EventsService{client: c}
|
||||||
c.Features = &FeaturesService{client: c}
|
c.Features = &FeaturesService{client: c}
|
||||||
@ -429,6 +442,7 @@ func newClient(httpClient *http.Client) *Client {
|
|||||||
c.Keys = &KeysService{client: c}
|
c.Keys = &KeysService{client: c}
|
||||||
c.Boards = &IssueBoardsService{client: c}
|
c.Boards = &IssueBoardsService{client: c}
|
||||||
c.Labels = &LabelsService{client: c}
|
c.Labels = &LabelsService{client: c}
|
||||||
|
c.LicenseTemplates = &LicenseTemplatesService{client: c}
|
||||||
c.MergeRequests = &MergeRequestsService{client: c, timeStats: timeStats}
|
c.MergeRequests = &MergeRequestsService{client: c, timeStats: timeStats}
|
||||||
c.MergeRequestApprovals = &MergeRequestApprovalsService{client: c}
|
c.MergeRequestApprovals = &MergeRequestApprovalsService{client: c}
|
||||||
c.Milestones = &MilestonesService{client: c}
|
c.Milestones = &MilestonesService{client: c}
|
||||||
@ -441,6 +455,7 @@ func newClient(httpClient *http.Client) *Client {
|
|||||||
c.PipelineTriggers = &PipelineTriggersService{client: c}
|
c.PipelineTriggers = &PipelineTriggersService{client: c}
|
||||||
c.Projects = &ProjectsService{client: c}
|
c.Projects = &ProjectsService{client: c}
|
||||||
c.ProjectMembers = &ProjectMembersService{client: c}
|
c.ProjectMembers = &ProjectMembersService{client: c}
|
||||||
|
c.ProjectBadges = &ProjectBadgesService{client: c}
|
||||||
c.ProjectSnippets = &ProjectSnippetsService{client: c}
|
c.ProjectSnippets = &ProjectSnippetsService{client: c}
|
||||||
c.ProjectVariables = &ProjectVariablesService{client: c}
|
c.ProjectVariables = &ProjectVariablesService{client: c}
|
||||||
c.ProtectedBranches = &ProtectedBranchesService{client: c}
|
c.ProtectedBranches = &ProtectedBranchesService{client: c}
|
||||||
@ -449,7 +464,6 @@ func newClient(httpClient *http.Client) *Client {
|
|||||||
c.Runners = &RunnersService{client: c}
|
c.Runners = &RunnersService{client: c}
|
||||||
c.Services = &ServicesService{client: c}
|
c.Services = &ServicesService{client: c}
|
||||||
c.Search = &SearchService{client: c}
|
c.Search = &SearchService{client: c}
|
||||||
c.Session = &SessionService{client: c}
|
|
||||||
c.Settings = &SettingsService{client: c}
|
c.Settings = &SettingsService{client: c}
|
||||||
c.Sidekiq = &SidekiqService{client: c}
|
c.Sidekiq = &SidekiqService{client: c}
|
||||||
c.Snippets = &SnippetsService{client: c}
|
c.Snippets = &SnippetsService{client: c}
|
||||||
@ -500,8 +514,14 @@ func (c *Client) SetBaseURL(urlStr string) error {
|
|||||||
// request body.
|
// request body.
|
||||||
func (c *Client) NewRequest(method, path string, opt interface{}, options []OptionFunc) (*http.Request, error) {
|
func (c *Client) NewRequest(method, path string, opt interface{}, options []OptionFunc) (*http.Request, error) {
|
||||||
u := *c.baseURL
|
u := *c.baseURL
|
||||||
// Set the encoded opaque data
|
unescaped, err := url.PathUnescape(path)
|
||||||
u.Opaque = c.baseURL.Path + path
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the encoded path data
|
||||||
|
u.RawPath = c.baseURL.Path + path
|
||||||
|
u.Path = c.baseURL.Path + unescaped
|
||||||
|
|
||||||
if opt != nil {
|
if opt != nil {
|
||||||
q, err := query.Values(opt)
|
q, err := query.Values(opt)
|
||||||
@ -681,7 +701,7 @@ type ErrorResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorResponse) Error() string {
|
func (e *ErrorResponse) Error() string {
|
||||||
path, _ := url.QueryUnescape(e.Response.Request.URL.Opaque)
|
path, _ := url.QueryUnescape(e.Response.Request.URL.Path)
|
||||||
u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, path)
|
u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, path)
|
||||||
return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message)
|
return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message)
|
||||||
}
|
}
|
||||||
@ -842,3 +862,24 @@ func MergeMethod(v MergeMethodValue) *MergeMethodValue {
|
|||||||
*p = v
|
*p = v
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BoolValue is a boolean value with advanced json unmarshaling features.
|
||||||
|
type BoolValue bool
|
||||||
|
|
||||||
|
// UnmarshalJSON allows 1 and 0 to be considered as boolean values
|
||||||
|
// Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/50122
|
||||||
|
func (t *BoolValue) UnmarshalJSON(b []byte) error {
|
||||||
|
switch string(b) {
|
||||||
|
case `"1"`:
|
||||||
|
*t = true
|
||||||
|
return nil
|
||||||
|
case `"0"`:
|
||||||
|
*t = false
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
var v bool
|
||||||
|
err := json.Unmarshal(b, &v)
|
||||||
|
*t = BoolValue(v)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
32
vendor/github.com/xanzy/go-gitlab/group_members.go
generated
vendored
32
vendor/github.com/xanzy/go-gitlab/group_members.go
generated
vendored
@ -44,8 +44,8 @@ type GroupMember struct {
|
|||||||
ExpiresAt *ISOTime `json:"expires_at"`
|
ExpiresAt *ISOTime `json:"expires_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListGroupMembersOptions represents the available ListGroupMembers()
|
// ListGroupMembersOptions represents the available ListGroupMembers() and
|
||||||
// options.
|
// ListAllGroupMembers() options.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
||||||
@ -55,7 +55,7 @@ type ListGroupMembersOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListGroupMembers get a list of group members viewable by the authenticated
|
// ListGroupMembers get a list of group members viewable by the authenticated
|
||||||
// user.
|
// user. Returns a list including inherited members through ancestor groups.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
||||||
@ -80,6 +80,32 @@ func (s *GroupsService) ListGroupMembers(gid interface{}, opt *ListGroupMembersO
|
|||||||
return gm, resp, err
|
return gm, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListAllGroupMembers get a list of group members viewable by the authenticated
|
||||||
|
// user. Returns a list including inherited members through ancestor groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members
|
||||||
|
func (s *GroupsService) ListAllGroupMembers(gid interface{}, opt *ListGroupMembersOptions, options ...OptionFunc) ([]*GroupMember, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/members/all", url.QueryEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gm []*GroupMember
|
||||||
|
resp, err := s.client.Do(req, &gm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gm, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// AddGroupMemberOptions represents the available AddGroupMember() options.
|
// AddGroupMemberOptions represents the available AddGroupMember() options.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
|
57
vendor/github.com/xanzy/go-gitlab/issues.go
generated
vendored
57
vendor/github.com/xanzy/go-gitlab/issues.go
generated
vendored
@ -305,7 +305,7 @@ func (s *IssuesService) CreateIssue(pid interface{}, opt *CreateIssueOptions, op
|
|||||||
|
|
||||||
// UpdateIssueOptions represents the available UpdateIssue() options.
|
// UpdateIssueOptions represents the available UpdateIssue() options.
|
||||||
//
|
//
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues
|
// GitLab API docs: https://docs.gitlab.com/ee/api/issues.html#edit-issue
|
||||||
type UpdateIssueOptions struct {
|
type UpdateIssueOptions struct {
|
||||||
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
@ -316,6 +316,7 @@ type UpdateIssueOptions struct {
|
|||||||
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
||||||
UpdatedAt *time.Time `url:"updated_at,omitempty" json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `url:"updated_at,omitempty" json:"updated_at,omitempty"`
|
||||||
DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"`
|
DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"`
|
||||||
|
Weight *int `url:"weight,omitempty" json:"weight,omitempty"`
|
||||||
DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"`
|
DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,6 +363,60 @@ func (s *IssuesService) DeleteIssue(pid interface{}, issue int, options ...Optio
|
|||||||
return s.client.Do(req, nil)
|
return s.client.Do(req, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubscribeToIssue subscribes the authenticated user to the given issue to
|
||||||
|
// receive notifications. If the user is already subscribed to the issue, the
|
||||||
|
// status code 304 is returned.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/merge_requests.html#subscribe-to-a-merge-request
|
||||||
|
func (s *IssuesService) SubscribeToIssue(pid interface{}, issue int, options ...OptionFunc) (*Issue, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/issues/%d/subscribe", url.QueryEscape(project), issue)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
i := new(Issue)
|
||||||
|
resp, err := s.client.Do(req, i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnsubscribeFromIssue unsubscribes the authenticated user from the given
|
||||||
|
// issue to not receive notifications from that merge request. If the user
|
||||||
|
// is not subscribed to the issue, status code 304 is returned.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request
|
||||||
|
func (s *IssuesService) UnsubscribeFromIssue(pid interface{}, issue int, options ...OptionFunc) (*Issue, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/issues/%d/unsubscribe", url.QueryEscape(project), issue)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
i := new(Issue)
|
||||||
|
resp, err := s.client.Do(req, i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// ListMergeRequestsClosingIssueOptions represents the available
|
// ListMergeRequestsClosingIssueOptions represents the available
|
||||||
// ListMergeRequestsClosingIssue() options.
|
// ListMergeRequestsClosingIssue() options.
|
||||||
//
|
//
|
||||||
|
35
vendor/github.com/xanzy/go-gitlab/jobs.go
generated
vendored
35
vendor/github.com/xanzy/go-gitlab/jobs.go
generated
vendored
@ -59,6 +59,7 @@ type Job struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Tag bool `json:"tag"`
|
Tag bool `json:"tag"`
|
||||||
User *User `json:"user"`
|
User *User `json:"user"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListJobsOptions are options for two list apis
|
// ListJobsOptions are options for two list apis
|
||||||
@ -197,6 +198,40 @@ func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, job
|
|||||||
return artifactsBuf, resp, err
|
return artifactsBuf, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DownloadSingleArtifactsFile download a file from the artifacts from the
|
||||||
|
// given reference name and job provided the job finished successfully.
|
||||||
|
// Only a single file is going to be extracted from the archive and streamed
|
||||||
|
// to a client.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/jobs.html#download-a-single-artifact-file
|
||||||
|
func (s *JobsService) DownloadSingleArtifactsFile(pid interface{}, jobID int, artifactPath string, options ...OptionFunc) (io.Reader, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
u := fmt.Sprintf(
|
||||||
|
"projects/%s/jobs/%d/artifacts/%s",
|
||||||
|
url.QueryEscape(project),
|
||||||
|
jobID,
|
||||||
|
artifactPath,
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
artifactBuf := new(bytes.Buffer)
|
||||||
|
resp, err := s.client.Do(req, artifactBuf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return artifactBuf, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetTraceFile gets a trace of a specific job of a project
|
// GetTraceFile gets a trace of a specific job of a project
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
|
21
vendor/github.com/xanzy/go-gitlab/labels.go
generated
vendored
21
vendor/github.com/xanzy/go-gitlab/labels.go
generated
vendored
@ -17,6 +17,7 @@
|
|||||||
package gitlab
|
package gitlab
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
@ -44,6 +45,26 @@ type Label struct {
|
|||||||
Priority int `json:"priority"`
|
Priority int `json:"priority"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (l *Label) UnmarshalJSON(data []byte) error {
|
||||||
|
type alias Label
|
||||||
|
if err := json.Unmarshal(data, (*alias)(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Name == "" {
|
||||||
|
var raw map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if title, ok := raw["title"].(string); ok {
|
||||||
|
l.Name = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (l Label) String() string {
|
func (l Label) String() string {
|
||||||
return Stringify(l)
|
return Stringify(l)
|
||||||
}
|
}
|
||||||
|
92
vendor/github.com/xanzy/go-gitlab/license_templates.go
generated
vendored
Normal file
92
vendor/github.com/xanzy/go-gitlab/license_templates.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LicenseTemplate represents a license template.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/licenses.html
|
||||||
|
type LicenseTemplate struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Nickname string `json:"nickname"`
|
||||||
|
Featured bool `json:"featured"`
|
||||||
|
HTMLURL string `json:"html_url"`
|
||||||
|
SourceURL string `json:"source_url"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Conditions []string `json:"conditions"`
|
||||||
|
Permissions []string `json:"permissions"`
|
||||||
|
Limitations []string `json:"limitations"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LicenseTemplatesService handles communication with the license templates
|
||||||
|
// related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/templates/licenses.html
|
||||||
|
type LicenseTemplatesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListLicenseTemplatesOptions represents the available
|
||||||
|
// ListLicenseTemplates() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/licenses.html#list-license-templates
|
||||||
|
type ListLicenseTemplatesOptions struct {
|
||||||
|
ListOptions
|
||||||
|
Popular *bool `url:"popular,omitempty" json:"popular,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListLicenseTemplates get all license templates.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/licenses.html#list-license-templates
|
||||||
|
func (s *LicenseTemplatesService) ListLicenseTemplates(opt *ListLicenseTemplatesOptions, options ...OptionFunc) ([]*LicenseTemplate, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest("GET", "templates/licenses", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var lts []*LicenseTemplate
|
||||||
|
resp, err := s.client.Do(req, <s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return lts, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLicenseTemplateOptions represents the available
|
||||||
|
// GetLicenseTemplate() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/licenses.html#single-license-template
|
||||||
|
type GetLicenseTemplateOptions struct {
|
||||||
|
Project *string `url:"project,omitempty" json:"project,omitempty"`
|
||||||
|
Fullname *string `url:"fullname,omitempty" json:"fullname,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLicenseTemplate get a single license template. You can pass parameters
|
||||||
|
// to replace the license placeholder.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/templates/licenses.html#single-license-template
|
||||||
|
func (s *LicenseTemplatesService) GetLicenseTemplate(template string, opt *GetLicenseTemplateOptions, options ...OptionFunc) (*LicenseTemplate, *Response, error) {
|
||||||
|
u := fmt.Sprintf("templates/licenses/%s", template)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
lt := new(LicenseTemplate)
|
||||||
|
resp, err := s.client.Do(req, lt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return lt, resp, err
|
||||||
|
}
|
23
vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go
generated
vendored
23
vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go
generated
vendored
@ -20,17 +20,18 @@ type MergeRequestApprovalsService struct {
|
|||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals
|
// https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals
|
||||||
type MergeRequestApprovals struct {
|
type MergeRequestApprovals struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
ProjectID int `json:"project_id"`
|
ProjectID int `json:"project_id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
State string `json:"state"`
|
State string `json:"state"`
|
||||||
CreatedAt *time.Time `json:"created_at"`
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at"`
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
MergeStatus string `json:"merge_status"`
|
MergeStatus string `json:"merge_status"`
|
||||||
ApprovalsRequired int `json:"approvals_required"`
|
ApprovalsBeforeMerge int `json:"approvals_before_merge"`
|
||||||
ApprovalsLeft int `json:"approvals_left"`
|
ApprovalsRequired int `json:"approvals_required"`
|
||||||
ApprovedBy []struct {
|
ApprovalsLeft int `json:"approvals_left"`
|
||||||
|
ApprovedBy []struct {
|
||||||
User struct {
|
User struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
97
vendor/github.com/xanzy/go-gitlab/merge_requests.go
generated
vendored
97
vendor/github.com/xanzy/go-gitlab/merge_requests.go
generated
vendored
@ -153,10 +153,15 @@ type ListMergeRequestsOptions struct {
|
|||||||
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
||||||
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
||||||
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
||||||
|
UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
|
||||||
|
UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
|
||||||
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||||
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||||
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
||||||
|
SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
|
||||||
|
TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMergeRequests gets all merge requests. The state parameter can be used
|
// ListMergeRequests gets all merge requests. The state parameter can be used
|
||||||
@ -181,6 +186,57 @@ func (s *MergeRequestsService) ListMergeRequests(opt *ListMergeRequestsOptions,
|
|||||||
return m, resp, err
|
return m, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListGroupMergeRequestsOptions represents the available ListGroupMergeRequests()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/merge_requests.html#list-group-merge-requests
|
||||||
|
type ListGroupMergeRequestsOptions struct {
|
||||||
|
ListOptions
|
||||||
|
State *string `url:"state,omitempty" json:"state,omitempty"`
|
||||||
|
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||||
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
|
Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"`
|
||||||
|
View *string `url:"view,omitempty" json:"view,omitempty"`
|
||||||
|
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
||||||
|
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
||||||
|
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
||||||
|
UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
|
||||||
|
UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
|
||||||
|
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||||
|
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||||
|
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||||
|
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
||||||
|
SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
|
||||||
|
TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupMergeRequests gets all merge requests for this group.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/merge_requests.html#list-group-merge-requests
|
||||||
|
func (s *MergeRequestsService) ListGroupMergeRequests(gid interface{}, opt *ListGroupMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
|
||||||
|
group, err := parseID(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("groups/%s/merge_requests", url.QueryEscape(group))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var m []*MergeRequest
|
||||||
|
resp, err := s.client.Do(req, &m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// ListProjectMergeRequestsOptions represents the available ListMergeRequests()
|
// ListProjectMergeRequestsOptions represents the available ListMergeRequests()
|
||||||
// options.
|
// options.
|
||||||
//
|
//
|
||||||
@ -197,19 +253,21 @@ type ListProjectMergeRequestsOptions struct {
|
|||||||
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
Labels Labels `url:"labels,omitempty" json:"labels,omitempty"`
|
||||||
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
|
||||||
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
|
||||||
|
UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
|
||||||
|
UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
|
||||||
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||||
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"`
|
||||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||||
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
|
||||||
|
SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
|
||||||
|
TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
|
||||||
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListProjectMergeRequests gets all merge requests for this project. The state
|
// ListProjectMergeRequests gets all merge requests for this project.
|
||||||
// parameter can be used to get only merge requests with a given state (opened,
|
|
||||||
// closed, or merged) or all of them (all). The pagination parameters page and
|
|
||||||
// per_page can be used to restrict the list of merge requests.
|
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests
|
// https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests
|
||||||
func (s *MergeRequestsService) ListProjectMergeRequests(pid interface{}, opt *ListProjectMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
|
func (s *MergeRequestsService) ListProjectMergeRequests(pid interface{}, opt *ListProjectMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
|
||||||
project, err := parseID(pid)
|
project, err := parseID(pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -447,13 +505,17 @@ func (s *MergeRequestsService) CreateMergeRequest(pid interface{}, opt *CreateMe
|
|||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr
|
// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr
|
||||||
type UpdateMergeRequestOptions struct {
|
type UpdateMergeRequestOptions struct {
|
||||||
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
Title *string `url:"title,omitempty" json:"title,omitempty"`
|
||||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
|
TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
|
||||||
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
|
||||||
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
|
||||||
MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
|
MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
|
||||||
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"`
|
||||||
|
RemoveSourceBranch *bool `url:"remove_source_branch,omitempty" json:"remove_source_branch,omitempty"`
|
||||||
|
Squash *bool `url:"squash,omitempty" json:"squash,omitempty"`
|
||||||
|
DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"`
|
||||||
|
AllowCollaboration *bool `url:"allow_collaboration,omitempty" json:"allow_collaboration,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateMergeRequest updates an existing project milestone.
|
// UpdateMergeRequest updates an existing project milestone.
|
||||||
@ -626,8 +688,8 @@ func (s *MergeRequestsService) GetSingleMergeRequestDiffVersion(pid interface{},
|
|||||||
return v, resp, err
|
return v, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeToMergeRequest subscribes the authenticated user to the given merge request
|
// SubscribeToMergeRequest subscribes the authenticated user to the given merge
|
||||||
// to receive notifications. If the user is already subscribed to the
|
// request to receive notifications. If the user is already subscribed to the
|
||||||
// merge request, the status code 304 is returned.
|
// merge request, the status code 304 is returned.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
@ -653,9 +715,10 @@ func (s *MergeRequestsService) SubscribeToMergeRequest(pid interface{}, mergeReq
|
|||||||
return m, resp, err
|
return m, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsubscribeFromMergeRequest unsubscribes the authenticated user from the given merge request
|
// UnsubscribeFromMergeRequest unsubscribes the authenticated user from the
|
||||||
// to not receive notifications from that merge request. If the user is
|
// given merge request to not receive notifications from that merge request.
|
||||||
// not subscribed to the merge request, status code 304 is returned.
|
// If the user is not subscribed to the merge request, status code 304 is
|
||||||
|
// returned.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request
|
// https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request
|
||||||
|
63
vendor/github.com/xanzy/go-gitlab/notes.go
generated
vendored
63
vendor/github.com/xanzy/go-gitlab/notes.go
generated
vendored
@ -40,22 +40,49 @@ type Note struct {
|
|||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
FileName string `json:"file_name"`
|
FileName string `json:"file_name"`
|
||||||
Author struct {
|
Author struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
State string `json:"state"`
|
State string `json:"state"`
|
||||||
CreatedAt *time.Time `json:"created_at"`
|
AvatarURL string `json:"avatar_url"`
|
||||||
AvatarURL string `json:"avatar_url"`
|
WebURL string `json:"web_url"`
|
||||||
WebURL string `json:"web_url"`
|
|
||||||
} `json:"author"`
|
} `json:"author"`
|
||||||
System bool `json:"system"`
|
System bool `json:"system"`
|
||||||
ExpiresAt *time.Time `json:"expires_at"`
|
ExpiresAt *time.Time `json:"expires_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at"`
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
CreatedAt *time.Time `json:"created_at"`
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
NoteableID int `json:"noteable_id"`
|
NoteableID int `json:"noteable_id"`
|
||||||
NoteableType string `json:"noteable_type"`
|
NoteableType string `json:"noteable_type"`
|
||||||
NoteableIID int `json:"noteable_iid"`
|
Position *NotePosition `json:"position"`
|
||||||
|
Resolvable bool `json:"resolvable"`
|
||||||
|
Resolved bool `json:"resolved"`
|
||||||
|
ResolvedBy struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
WebURL string `json:"web_url"`
|
||||||
|
} `json:"resolved_by"`
|
||||||
|
NoteableIID int `json:"noteable_iid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotePosition represents the position attributes of a note.
|
||||||
|
type NotePosition struct {
|
||||||
|
BaseSHA string `json:"base_sha"`
|
||||||
|
StartSHA string `json:"start_sha"`
|
||||||
|
HeadSHA string `json:"head_sha"`
|
||||||
|
PositionType string `json:"position_type"`
|
||||||
|
NewPath string `json:"new_path,omitempty"`
|
||||||
|
NewLine int `json:"new_line,omitempty"`
|
||||||
|
OldPath string `json:"old_path,omitempty"`
|
||||||
|
OldLine int `json:"old_line,omitempty"`
|
||||||
|
Width int `json:"width,omitempty"`
|
||||||
|
Height int `json:"height,omitempty"`
|
||||||
|
X int `json:"x,omitempty"`
|
||||||
|
Y int `json:"y,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Note) String() string {
|
func (n Note) String() string {
|
||||||
@ -66,7 +93,11 @@ func (n Note) String() string {
|
|||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes
|
// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes
|
||||||
type ListIssueNotesOptions ListOptions
|
type ListIssueNotesOptions struct {
|
||||||
|
ListOptions
|
||||||
|
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||||
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// ListIssueNotes gets a list of all notes for a single issue.
|
// ListIssueNotes gets a list of all notes for a single issue.
|
||||||
//
|
//
|
||||||
|
19
vendor/github.com/xanzy/go-gitlab/pages_domains.go
generated
vendored
19
vendor/github.com/xanzy/go-gitlab/pages_domains.go
generated
vendored
@ -61,6 +61,25 @@ func (s *PagesDomainsService) ListPagesDomains(pid interface{}, opt *ListPagesDo
|
|||||||
return pd, resp, err
|
return pd, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListAllPagesDomains gets a list of all pages domains.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/pages_domains.html#list-all-pages-domains
|
||||||
|
func (s *PagesDomainsService) ListAllPagesDomains(options ...OptionFunc) ([]*PagesDomain, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest("GET", "pages/domains", nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pd []*PagesDomain
|
||||||
|
resp, err := s.client.Do(req, &pd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pd, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetPagesDomain get a specific pages domain for a project.
|
// GetPagesDomain get a specific pages domain for a project.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
|
9
vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go
generated
vendored
9
vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go
generated
vendored
@ -30,15 +30,6 @@ type PipelineSchedulesService struct {
|
|||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// PipelineVariable represents a pipeline schedule variable.
|
|
||||||
//
|
|
||||||
// GitLab API docs:
|
|
||||||
// https://docs.gitlab.com/ce/api/pipeline_schedules.html#pipeline-schedule-variable
|
|
||||||
type PipelineVariable struct {
|
|
||||||
Key string `json:"key"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PipelineSchedule represents a pipeline schedule.
|
// PipelineSchedule represents a pipeline schedule.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
|
12
vendor/github.com/xanzy/go-gitlab/pipelines.go
generated
vendored
12
vendor/github.com/xanzy/go-gitlab/pipelines.go
generated
vendored
@ -30,6 +30,14 @@ type PipelinesService struct {
|
|||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PipelineVariable represents a pipeline variable.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html
|
||||||
|
type PipelineVariable struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
// Pipeline represents a GitLab pipeline.
|
// Pipeline represents a GitLab pipeline.
|
||||||
//
|
//
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html
|
// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html
|
||||||
@ -84,6 +92,7 @@ type ListProjectPipelinesOptions struct {
|
|||||||
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
|
||||||
Status *BuildStateValue `url:"status,omitempty" json:"status,omitempty"`
|
Status *BuildStateValue `url:"status,omitempty" json:"status,omitempty"`
|
||||||
Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
|
Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
|
||||||
|
SHA *string `url:"sha,omitempty" json:"sha,omitempty"`
|
||||||
YamlErrors *bool `url:"yaml_errors,omitempty" json:"yaml_errors,omitempty"`
|
YamlErrors *bool `url:"yaml_errors,omitempty" json:"yaml_errors,omitempty"`
|
||||||
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
Username *string `url:"username,omitempty" json:"username,omitempty"`
|
Username *string `url:"username,omitempty" json:"username,omitempty"`
|
||||||
@ -142,7 +151,8 @@ func (s *PipelinesService) GetPipeline(pid interface{}, pipeline int, options ..
|
|||||||
//
|
//
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#create-a-new-pipeline
|
// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#create-a-new-pipeline
|
||||||
type CreatePipelineOptions struct {
|
type CreatePipelineOptions struct {
|
||||||
Ref *string `url:"ref,omitempty" json:"ref"`
|
Ref *string `url:"ref" json:"ref"`
|
||||||
|
Variables []*PipelineVariable `url:"variables,omitempty" json:"variables,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePipeline creates a new project pipeline.
|
// CreatePipeline creates a new project pipeline.
|
||||||
|
208
vendor/github.com/xanzy/go-gitlab/project_badges.go
generated
vendored
Normal file
208
vendor/github.com/xanzy/go-gitlab/project_badges.go
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProjectBadge represents a project badge.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project
|
||||||
|
type ProjectBadge struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
LinkURL string `json:"link_url"`
|
||||||
|
ImageURL string `json:"image_url"`
|
||||||
|
RenderedLinkURL string `json:"rendered_link_url"`
|
||||||
|
RenderedImageURL string `json:"rendered_image_url"`
|
||||||
|
// Kind represents a project badge kind. Can be empty, when used PreviewProjectBadge().
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectBadgesService handles communication with the project badges
|
||||||
|
// related methods of the GitLab API.
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ee/api/project_badges.html
|
||||||
|
type ProjectBadgesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListProjectBadgesOptions represents the available ListProjectBadges()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project
|
||||||
|
type ListProjectBadgesOptions ListOptions
|
||||||
|
|
||||||
|
// ListProjectBadges gets a list of a project's badges and its group badges.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#list-all-badges-of-a-project
|
||||||
|
func (s *ProjectBadgesService) ListProjectBadges(pid interface{}, opt *ListProjectBadgesOptions, options ...OptionFunc) ([]*ProjectBadge, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/badges", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pb []*ProjectBadge
|
||||||
|
resp, err := s.client.Do(req, &pb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectBadge gets a project badge.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#get-a-badge-of-a-project
|
||||||
|
func (s *ProjectBadgesService) GetProjectBadge(pid interface{}, badge int, options ...OptionFunc) (*ProjectBadge, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/badges/%d", url.QueryEscape(project), badge)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pb := new(ProjectBadge)
|
||||||
|
resp, err := s.client.Do(req, pb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddProjectBadgeOptions represents the available AddProjectBadge() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#add-a-badge-to-a-project
|
||||||
|
type AddProjectBadgeOptions struct {
|
||||||
|
LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"`
|
||||||
|
ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddProjectBadge adds a badge to a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#add-a-badge-to-a-project
|
||||||
|
func (s *ProjectBadgesService) AddProjectBadge(pid interface{}, opt *AddProjectBadgeOptions, options ...OptionFunc) (*ProjectBadge, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/badges", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pb := new(ProjectBadge)
|
||||||
|
resp, err := s.client.Do(req, pb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditProjectBadgeOptions represents the available EditProjectBadge() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#edit-a-badge-of-a-project
|
||||||
|
type EditProjectBadgeOptions struct {
|
||||||
|
LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"`
|
||||||
|
ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditProjectBadge updates a badge of a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#edit-a-badge-of-a-project
|
||||||
|
func (s *ProjectBadgesService) EditProjectBadge(pid interface{}, badge int, opt *EditProjectBadgeOptions, options ...OptionFunc) (*ProjectBadge, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/badges/%d", url.QueryEscape(project), badge)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pb := new(ProjectBadge)
|
||||||
|
resp, err := s.client.Do(req, pb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteProjectBadge removes a badge from a project. Only project's
|
||||||
|
// badges will be removed by using this endpoint.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#remove-a-badge-from-a-project
|
||||||
|
func (s *ProjectBadgesService) DeleteProjectBadge(pid interface{}, badge int, options ...OptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/badges/%d", url.QueryEscape(project), badge)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectBadgePreviewOptions represents the available PreviewProjectBadge() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#preview-a-badge-from-a-project
|
||||||
|
type ProjectBadgePreviewOptions struct {
|
||||||
|
LinkURL *string `url:"link_url,omitempty" json:"link_url,omitempty"`
|
||||||
|
ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreviewProjectBadge returns how the link_url and image_url final URLs would be after
|
||||||
|
// resolving the placeholder interpolation.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ee/api/project_badges.html#preview-a-badge-from-a-project
|
||||||
|
func (s *ProjectBadgesService) PreviewProjectBadge(pid interface{}, opt *ProjectBadgePreviewOptions, options ...OptionFunc) (*ProjectBadge, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/badges/render", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pb := new(ProjectBadge)
|
||||||
|
resp, err := s.client.Do(req, &pb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb, resp, err
|
||||||
|
}
|
35
vendor/github.com/xanzy/go-gitlab/project_members.go
generated
vendored
35
vendor/github.com/xanzy/go-gitlab/project_members.go
generated
vendored
@ -29,8 +29,8 @@ type ProjectMembersService struct {
|
|||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListProjectMembersOptions represents the available ListProjectMembers()
|
// ListProjectMembersOptions represents the available ListProjectMembers() and
|
||||||
// options.
|
// ListAllProjectMembers() options.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
||||||
@ -39,7 +39,9 @@ type ListProjectMembersOptions struct {
|
|||||||
Query *string `url:"query,omitempty" json:"query,omitempty"`
|
Query *string `url:"query,omitempty" json:"query,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListProjectMembers gets a list of a project's team members.
|
// ListProjectMembers gets a list of a project's team members viewable by the
|
||||||
|
// authenticated user. Returns only direct members and not inherited members
|
||||||
|
// through ancestors groups.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
|
||||||
@ -64,6 +66,33 @@ func (s *ProjectMembersService) ListProjectMembers(pid interface{}, opt *ListPro
|
|||||||
return pm, resp, err
|
return pm, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListAllProjectMembers gets a list of a project's team members viewable by the
|
||||||
|
// authenticated user. Returns a list including inherited members through
|
||||||
|
// ancestor groups.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project-including-inherited-members
|
||||||
|
func (s *ProjectMembersService) ListAllProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...OptionFunc) ([]*ProjectMember, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/members/all", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pm []*ProjectMember
|
||||||
|
resp, err := s.client.Do(req, &pm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pm, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetProjectMember gets a project team member.
|
// GetProjectMember gets a project team member.
|
||||||
//
|
//
|
||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
|
57
vendor/github.com/xanzy/go-gitlab/projects.go
generated
vendored
57
vendor/github.com/xanzy/go-gitlab/projects.go
generated
vendored
@ -182,18 +182,19 @@ func (s Project) String() string {
|
|||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects
|
// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects
|
||||||
type ListProjectsOptions struct {
|
type ListProjectsOptions struct {
|
||||||
ListOptions
|
ListOptions
|
||||||
Archived *bool `url:"archived,omitempty" json:"archived,omitempty"`
|
Archived *bool `url:"archived,omitempty" json:"archived,omitempty"`
|
||||||
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
|
||||||
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
Sort *string `url:"sort,omitempty" json:"sort,omitempty"`
|
||||||
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
Search *string `url:"search,omitempty" json:"search,omitempty"`
|
||||||
Simple *bool `url:"simple,omitempty" json:"simple,omitempty"`
|
Simple *bool `url:"simple,omitempty" json:"simple,omitempty"`
|
||||||
Owned *bool `url:"owned,omitempty" json:"owned,omitempty"`
|
Owned *bool `url:"owned,omitempty" json:"owned,omitempty"`
|
||||||
Membership *bool `url:"membership,omitempty" json:"membership,omitempty"`
|
Membership *bool `url:"membership,omitempty" json:"membership,omitempty"`
|
||||||
Starred *bool `url:"starred,omitempty" json:"starred,omitempty"`
|
Starred *bool `url:"starred,omitempty" json:"starred,omitempty"`
|
||||||
Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"`
|
Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"`
|
||||||
Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
|
Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"`
|
||||||
WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"`
|
WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"`
|
||||||
WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"`
|
WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"`
|
||||||
|
MinAccessLevel *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListProjects gets a list of projects accessible by the authenticated user.
|
// ListProjects gets a list of projects accessible by the authenticated user.
|
||||||
@ -282,6 +283,35 @@ func (s *ProjectsService) ListProjectsUsers(pid interface{}, opt *ListProjectUse
|
|||||||
return p, resp, err
|
return p, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectLanguages is a map of strings because the response is arbitrary
|
||||||
|
//
|
||||||
|
// Gitlab API docs: https://docs.gitlab.com/ce/api/projects.html#languages
|
||||||
|
type ProjectLanguages map[string]float32
|
||||||
|
|
||||||
|
// GetProjectLanguages gets a list of languages used by the project
|
||||||
|
//
|
||||||
|
// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#languages
|
||||||
|
func (s *ProjectsService) GetProjectLanguages(pid interface{}, options ...OptionFunc) (*ProjectLanguages, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/languages", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p := new(ProjectLanguages)
|
||||||
|
resp, err := s.client.Do(req, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetProject gets a specific project, identified by project ID or
|
// GetProject gets a specific project, identified by project ID or
|
||||||
// NAMESPACE/PROJECT_NAME, which is owned by the authenticated user.
|
// NAMESPACE/PROJECT_NAME, which is owned by the authenticated user.
|
||||||
//
|
//
|
||||||
@ -371,7 +401,7 @@ func (s *ProjectsService) GetProjectEvents(pid interface{}, opt *GetProjectEvent
|
|||||||
|
|
||||||
// CreateProjectOptions represents the available CreateProjects() options.
|
// CreateProjectOptions represents the available CreateProjects() options.
|
||||||
//
|
//
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project
|
// GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#create-project
|
||||||
type CreateProjectOptions struct {
|
type CreateProjectOptions struct {
|
||||||
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
Name *string `url:"name,omitempty" json:"name,omitempty"`
|
||||||
Path *string `url:"path,omitempty" json:"path,omitempty"`
|
Path *string `url:"path,omitempty" json:"path,omitempty"`
|
||||||
@ -397,6 +427,7 @@ type CreateProjectOptions struct {
|
|||||||
TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"`
|
TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"`
|
||||||
PrintingMergeRequestLinkEnabled *bool `url:"printing_merge_request_link_enabled,omitempty" json:"printing_merge_request_link_enabled,omitempty"`
|
PrintingMergeRequestLinkEnabled *bool `url:"printing_merge_request_link_enabled,omitempty" json:"printing_merge_request_link_enabled,omitempty"`
|
||||||
CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"`
|
CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"`
|
||||||
|
ApprovalsBeforeMerge *int `url:"approvals_before_merge" json:"approvals_before_merge"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateProject creates a new project owned by the authenticated user.
|
// CreateProject creates a new project owned by the authenticated user.
|
||||||
|
10
vendor/github.com/xanzy/go-gitlab/repository_files.go
generated
vendored
10
vendor/github.com/xanzy/go-gitlab/repository_files.go
generated
vendored
@ -66,7 +66,7 @@ func (s *RepositoryFilesService) GetFile(pid interface{}, fileName string, opt *
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.QueryEscape(fileName))
|
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.PathEscape(fileName))
|
||||||
|
|
||||||
req, err := s.client.NewRequest("GET", u, opt, options)
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -99,7 +99,7 @@ func (s *RepositoryFilesService) GetRawFile(pid interface{}, fileName string, op
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
u := fmt.Sprintf("projects/%s/repository/files/%s/raw", url.QueryEscape(project), url.QueryEscape(fileName))
|
u := fmt.Sprintf("projects/%s/repository/files/%s/raw", url.QueryEscape(project), url.PathEscape(fileName))
|
||||||
|
|
||||||
req, err := s.client.NewRequest("GET", u, opt, options)
|
req, err := s.client.NewRequest("GET", u, opt, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -149,7 +149,7 @@ func (s *RepositoryFilesService) CreateFile(pid interface{}, fileName string, op
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.QueryEscape(fileName))
|
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.PathEscape(fileName))
|
||||||
|
|
||||||
req, err := s.client.NewRequest("POST", u, opt, options)
|
req, err := s.client.NewRequest("POST", u, opt, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -188,7 +188,7 @@ func (s *RepositoryFilesService) UpdateFile(pid interface{}, fileName string, op
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.QueryEscape(fileName))
|
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.PathEscape(fileName))
|
||||||
|
|
||||||
req, err := s.client.NewRequest("PUT", u, opt, options)
|
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -224,7 +224,7 @@ func (s *RepositoryFilesService) DeleteFile(pid interface{}, fileName string, op
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.QueryEscape(fileName))
|
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.PathEscape(fileName))
|
||||||
|
|
||||||
req, err := s.client.NewRequest("DELETE", u, opt, options)
|
req, err := s.client.NewRequest("DELETE", u, opt, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
124
vendor/github.com/xanzy/go-gitlab/runners.go
generated
vendored
124
vendor/github.com/xanzy/go-gitlab/runners.go
generated
vendored
@ -18,6 +18,7 @@ package gitlab
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -34,13 +35,15 @@ type RunnersService struct {
|
|||||||
//
|
//
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html
|
// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html
|
||||||
type Runner struct {
|
type Runner struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Active bool `json:"active"`
|
Active bool `json:"active"`
|
||||||
IsShared bool `json:"is_shared"`
|
IsShared bool `json:"is_shared"`
|
||||||
Name string `json:"name"`
|
IPAddress *net.IP `json:"ip_address"`
|
||||||
Online bool `json:"online"`
|
Name string `json:"name"`
|
||||||
Status string `json:"status"`
|
Online bool `json:"online"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Token string `json:"token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunnerDetails represents the GitLab CI runner details.
|
// RunnerDetails represents the GitLab CI runner details.
|
||||||
@ -52,11 +55,11 @@ type RunnerDetails struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
IsShared bool `json:"is_shared"`
|
IsShared bool `json:"is_shared"`
|
||||||
ContactedAt *time.Time `json:"contacted_at,omitempty"`
|
ContactedAt *time.Time `json:"contacted_at"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Online bool `json:"online"`
|
Online bool `json:"online"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Platform string `json:"platform,omitempty"`
|
Platform string `json:"platform"`
|
||||||
Projects []struct {
|
Projects []struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -64,11 +67,12 @@ type RunnerDetails struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
PathWithNamespace string `json:"path_with_namespace"`
|
PathWithNamespace string `json:"path_with_namespace"`
|
||||||
} `json:"projects"`
|
} `json:"projects"`
|
||||||
Token string `json:"Token"`
|
Token string `json:"token"`
|
||||||
Revision string `json:"revision,omitempty"`
|
Revision string `json:"revision"`
|
||||||
TagList []string `json:"tag_list"`
|
TagList []string `json:"tag_list"`
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version"`
|
||||||
AccessLevel string `json:"access_level"`
|
AccessLevel string `json:"access_level"`
|
||||||
|
MaximumTimeout int `json:"maximum_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListRunnersOptions represents the available ListRunners() options.
|
// ListRunnersOptions represents the available ListRunners() options.
|
||||||
@ -149,12 +153,13 @@ func (s *RunnersService) GetRunnerDetails(rid interface{}, options ...OptionFunc
|
|||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details
|
// https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details
|
||||||
type UpdateRunnerDetailsOptions struct {
|
type UpdateRunnerDetailsOptions struct {
|
||||||
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
Active *bool `url:"active,omitempty" json:"active,omitempty"`
|
Active *bool `url:"active,omitempty" json:"active,omitempty"`
|
||||||
TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"`
|
TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"`
|
||||||
RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"`
|
RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"`
|
||||||
Locked *bool `url:"locked,omitempty" json:"locked,omitempty"`
|
Locked *bool `url:"locked,omitempty" json:"locked,omitempty"`
|
||||||
AccessLevel *string `url:"access_level,omitempty" json:"access_level,omitempty"`
|
AccessLevel *string `url:"access_level,omitempty" json:"access_level,omitempty"`
|
||||||
|
MaximumTimeout *int `url:"maximum_timeout,omitempty" json:"maximum_timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRunnerDetails updates details for a given runner.
|
// UpdateRunnerDetails updates details for a given runner.
|
||||||
@ -324,3 +329,82 @@ func (s *RunnersService) DisableProjectRunner(pid interface{}, rid interface{},
|
|||||||
|
|
||||||
return s.client.Do(req, nil)
|
return s.client.Do(req, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterNewRunnerOptions represents the available RegisterNewRunner()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/runners.html#register-a-new-runner
|
||||||
|
type RegisterNewRunnerOptions struct {
|
||||||
|
Token *string `url:"token" json:"token"`
|
||||||
|
Description *string `url:"description,omitempty" json:"description,omitempty"`
|
||||||
|
Info *string `url:"info,omitempty" json:"info,omitempty"`
|
||||||
|
Active *bool `url:"active,omitempty" json:"active,omitempty"`
|
||||||
|
Locked *bool `url:"locked,omitempty" json:"locked,omitempty"`
|
||||||
|
RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"`
|
||||||
|
TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"`
|
||||||
|
MaximumTimeout *int `url:"maximum_timeout,omitempty" json:"maximum_timeout,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterNewRunner registers a new Runner for the instance.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/runners.html#register-a-new-runner
|
||||||
|
func (s *RunnersService) RegisterNewRunner(opt *RegisterNewRunnerOptions, options ...OptionFunc) (*Runner, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest("POST", "runners", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r *Runner
|
||||||
|
resp, err := s.client.Do(req, &r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRegisteredRunnerOptions represents the available
|
||||||
|
// DeleteRegisteredRunner() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/runners.html#delete-a-registered-runner
|
||||||
|
type DeleteRegisteredRunnerOptions struct {
|
||||||
|
Token *string `url:"token" json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRegisteredRunner registers a new Runner for the instance.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/runners.html#delete-a-registered-runner
|
||||||
|
func (s *RunnersService) DeleteRegisteredRunner(opt *DeleteRegisteredRunnerOptions, options ...OptionFunc) (*Response, error) {
|
||||||
|
req, err := s.client.NewRequest("DELETE", "runners", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyRegisteredRunnerOptions represents the available
|
||||||
|
// VerifyRegisteredRunner() options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/runners.html#verify-authentication-for-a-registered-runner
|
||||||
|
type VerifyRegisteredRunnerOptions struct {
|
||||||
|
Token *string `url:"token" json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyRegisteredRunner registers a new Runner for the instance.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/runners.html#verify-authentication-for-a-registered-runner
|
||||||
|
func (s *RunnersService) VerifyRegisteredRunner(opt *VerifyRegisteredRunnerOptions, options ...OptionFunc) (*Response, error) {
|
||||||
|
req, err := s.client.NewRequest("POST", "runners/verify", opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
142
vendor/github.com/xanzy/go-gitlab/services.go
generated
vendored
142
vendor/github.com/xanzy/go-gitlab/services.go
generated
vendored
@ -45,8 +45,10 @@ type Service struct {
|
|||||||
MergeRequestsEvents bool `json:"merge_requests_events"`
|
MergeRequestsEvents bool `json:"merge_requests_events"`
|
||||||
TagPushEvents bool `json:"tag_push_events"`
|
TagPushEvents bool `json:"tag_push_events"`
|
||||||
NoteEvents bool `json:"note_events"`
|
NoteEvents bool `json:"note_events"`
|
||||||
|
ConfidentialNoteEvents bool `json:"confidential_note_events"`
|
||||||
PipelineEvents bool `json:"pipeline_events"`
|
PipelineEvents bool `json:"pipeline_events"`
|
||||||
JobEvents bool `json:"job_events"`
|
JobEvents bool `json:"job_events"`
|
||||||
|
WikiPageEvents bool `json:"wiki_page_events"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGitLabCIServiceOptions represents the available SetGitLabCIService()
|
// SetGitLabCIServiceOptions represents the available SetGitLabCIService()
|
||||||
@ -252,7 +254,28 @@ type SlackService struct {
|
|||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/services.html#slack
|
// https://docs.gitlab.com/ce/api/services.html#slack
|
||||||
type SlackServiceProperties struct {
|
type SlackServiceProperties struct {
|
||||||
NotifyOnlyBrokenPipelines bool `json:"notify_only_broken_pipelines"`
|
// Note: NotifyOnlyBrokenPipelines and NotifyOnlyDefaultBranch are not
|
||||||
|
// just "bool" because in some cases gitlab returns
|
||||||
|
// "notify_only_broken_pipelines": true, and in other cases
|
||||||
|
// "notify_only_broken_pipelines": "1". The same is for
|
||||||
|
// "notify_only_default_branch" field.
|
||||||
|
// We need to handle this, until the bug will be fixed.
|
||||||
|
// Ref: https://gitlab.com/gitlab-org/gitlab-ce/issues/50122
|
||||||
|
|
||||||
|
NotifyOnlyBrokenPipelines BoolValue `url:"notify_only_broken_pipelines,omitempty" json:"notify_only_broken_pipelines,omitempty"`
|
||||||
|
NotifyOnlyDefaultBranch BoolValue `url:"notify_only_default_branch,omitempty" json:"notify_only_default_branch,omitempty"`
|
||||||
|
WebHook string `url:"webhook,omitempty" json:"webhook,omitempty"`
|
||||||
|
Username string `url:"username,omitempty" json:"username,omitempty"`
|
||||||
|
Channel string `url:"channel,omitempty" json:"channel,omitempty"`
|
||||||
|
PushChannel string `url:"push_channel,omitempty" json:"push_channel,omitempty"`
|
||||||
|
IssueChannel string `url:"issue_channel,omitempty" json:"issue_channel,omitempty"`
|
||||||
|
ConfidentialIssueChannel string `url:"confidential_issue_channel,omitempty" json:"confidential_issue_channel,omitempty"`
|
||||||
|
MergeRequestChannel string `url:"merge_request_channel,omitempty" json:"merge_request_channel,omitempty"`
|
||||||
|
NoteChannel string `url:"note_channel,omitempty" json:"note_channel,omitempty"`
|
||||||
|
ConfidentialNoteChannel string `url:"confidential_note_channel,omitempty" json:"confidential_note_channel,omitempty"`
|
||||||
|
TagPushChannel string `url:"tag_push_channel,omitempty" json:"tag_push_channel,omitempty"`
|
||||||
|
PipelineChannel string `url:"pipeline_channel,omitempty" json:"pipeline_channel,omitempty"`
|
||||||
|
WikiPageChannel string `url:"wiki_page_channel,omitempty" json:"wiki_page_channel,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSlackService gets Slack service settings for a project.
|
// GetSlackService gets Slack service settings for a project.
|
||||||
@ -286,9 +309,32 @@ func (s *ServicesService) GetSlackService(pid interface{}, options ...OptionFunc
|
|||||||
// GitLab API docs:
|
// GitLab API docs:
|
||||||
// https://docs.gitlab.com/ce/api/services.html#edit-slack-service
|
// https://docs.gitlab.com/ce/api/services.html#edit-slack-service
|
||||||
type SetSlackServiceOptions struct {
|
type SetSlackServiceOptions struct {
|
||||||
WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty" `
|
WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"`
|
||||||
Username *string `url:"username,omitempty" json:"username,omitempty" `
|
Username *string `url:"username,omitempty" json:"username,omitempty"`
|
||||||
Channel *string `url:"channel,omitempty" json:"channel,omitempty"`
|
Channel *string `url:"channel,omitempty" json:"channel,omitempty"`
|
||||||
|
NotifyOnlyBrokenPipelines *bool `url:"notify_only_broken_pipelines,omitempty" json:"notify_only_broken_pipelines,omitempty"`
|
||||||
|
NotifyOnlyDefaultBranch *bool `url:"notify_only_default_branch,omitempty" json:"notify_only_default_branch,omitempty"`
|
||||||
|
PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"`
|
||||||
|
PushChannel *string `url:"push_channel,omitempty" json:"push_channel,omitempty"`
|
||||||
|
IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"`
|
||||||
|
IssueChannel *string `url:"issue_channel,omitempty" json:"issue_channel,omitempty"`
|
||||||
|
ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
|
||||||
|
ConfidentialIssueChannel *string `url:"confidential_issue_channel,omitempty" json:"confidential_issue_channel,omitempty"`
|
||||||
|
MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
|
||||||
|
MergeRequestChannel *string `url:"merge_request_channel,omitempty" json:"merge_request_channel,omitempty"`
|
||||||
|
TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
|
||||||
|
TagPushChannel *string `url:"tag_push_channel,omitempty" json:"tag_push_channel,omitempty"`
|
||||||
|
NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"`
|
||||||
|
NoteChannel *string `url:"note_channel,omitempty" json:"note_channel,omitempty"`
|
||||||
|
ConfidentialNoteEvents *bool `url:"confidential_note_events" json:"confidential_note_events"`
|
||||||
|
// TODO: Currently, GitLab ignores this option (not implemented yet?), so
|
||||||
|
// there is no way to set it. Uncomment when this is fixed.
|
||||||
|
// See: https://gitlab.com/gitlab-org/gitlab-ce/issues/49730
|
||||||
|
//ConfidentialNoteChannel *string `json:"confidential_note_channel,omitempty"`
|
||||||
|
PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
|
||||||
|
PipelineChannel *string `url:"pipeline_channel,omitempty" json:"pipeline_channel,omitempty"`
|
||||||
|
WikiPageChannel *string `url:"wiki_page_channel,omitempty" json:"wiki_page_channel,omitempty"`
|
||||||
|
WikiPageEvents *bool `url:"wiki_page_events" json:"wiki_page_events"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSlackService sets Slack service for a project
|
// SetSlackService sets Slack service for a project
|
||||||
@ -513,3 +559,91 @@ func (s *ServicesService) DeleteJenkinsCIService(pid interface{}, options ...Opt
|
|||||||
|
|
||||||
return s.client.Do(req, nil)
|
return s.client.Do(req, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MicrosoftTeamsService represents Microsoft Teams service settings.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/services.html#microsoft-teams
|
||||||
|
type MicrosoftTeamsService struct {
|
||||||
|
Service
|
||||||
|
Properties *MicrosoftTeamsServiceProperties `json:"properties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MicrosoftTeamsServiceProperties represents Microsoft Teams specific properties.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/services.html#microsoft-teams
|
||||||
|
type MicrosoftTeamsServiceProperties struct {
|
||||||
|
WebHook string `json:"webhook"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMicrosoftTeamsService gets MicrosoftTeams service settings for a project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/services.html#get-microsoft-teams-service-settings
|
||||||
|
func (s *ServicesService) GetMicrosoftTeamsService(pid interface{}, options ...OptionFunc) (*MicrosoftTeamsService, *Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/services/microsoft-teams", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := new(MicrosoftTeamsService)
|
||||||
|
resp, err := s.client.Do(req, svc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMicrosoftTeamsServiceOptions represents the available SetMicrosoftTeamsService()
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/services.html#create-edit-microsoft-teams-service
|
||||||
|
type SetMicrosoftTeamsServiceOptions struct {
|
||||||
|
WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMicrosoftTeamsService sets Microsoft Teams service for a project
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/services.html#create-edit-microsoft-teams-service
|
||||||
|
func (s *ServicesService) SetMicrosoftTeamsService(pid interface{}, opt *SetMicrosoftTeamsServiceOptions, options ...OptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/services/microsoft-teams", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("PUT", u, opt, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMicrosoftTeamsService deletes Microsoft Teams service for project.
|
||||||
|
//
|
||||||
|
// GitLab API docs:
|
||||||
|
// https://docs.gitlab.com/ce/api/services.html#delete-microsoft-teams-service
|
||||||
|
func (s *ServicesService) DeleteMicrosoftTeamsService(pid interface{}, options ...OptionFunc) (*Response, error) {
|
||||||
|
project, err := parseID(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("projects/%s/services/microsoft-teams", url.QueryEscape(project))
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("DELETE", u, nil, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.Do(req, nil)
|
||||||
|
}
|
||||||
|
78
vendor/github.com/xanzy/go-gitlab/session.go
generated
vendored
78
vendor/github.com/xanzy/go-gitlab/session.go
generated
vendored
@ -1,78 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2017, Sander van Harmelen
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
package gitlab
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// SessionService handles communication with the session related methods of
|
|
||||||
// the GitLab API.
|
|
||||||
//
|
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/session.html
|
|
||||||
type SessionService struct {
|
|
||||||
client *Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// Session represents a GitLab session.
|
|
||||||
//
|
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session
|
|
||||||
type Session struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
PrivateToken string `json:"private_token"`
|
|
||||||
Blocked bool `json:"blocked"`
|
|
||||||
CreatedAt *time.Time `json:"created_at"`
|
|
||||||
Bio interface{} `json:"bio"`
|
|
||||||
Skype string `json:"skype"`
|
|
||||||
Linkedin string `json:"linkedin"`
|
|
||||||
Twitter string `json:"twitter"`
|
|
||||||
WebsiteURL string `json:"website_url"`
|
|
||||||
DarkScheme bool `json:"dark_scheme"`
|
|
||||||
ThemeID int `json:"theme_id"`
|
|
||||||
IsAdmin bool `json:"is_admin"`
|
|
||||||
CanCreateGroup bool `json:"can_create_group"`
|
|
||||||
CanCreateTeam bool `json:"can_create_team"`
|
|
||||||
CanCreateProject bool `json:"can_create_project"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSessionOptions represents the available Session() options.
|
|
||||||
//
|
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session
|
|
||||||
type GetSessionOptions struct {
|
|
||||||
Login *string `url:"login,omitempty" json:"login,omitempty"`
|
|
||||||
Email *string `url:"email,omitempty" json:"email,omitempty"`
|
|
||||||
Password *string `url:"password,omitempty" json:"password,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSession logs in to get private token.
|
|
||||||
//
|
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session
|
|
||||||
func (s *SessionService) GetSession(opt *GetSessionOptions, options ...OptionFunc) (*Session, *Response, error) {
|
|
||||||
req, err := s.client.NewRequest("POST", "session", opt, options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
session := new(Session)
|
|
||||||
resp, err := s.client.Do(req, session)
|
|
||||||
if err != nil {
|
|
||||||
return nil, resp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return session, resp, err
|
|
||||||
}
|
|
62
vendor/github.com/xanzy/go-gitlab/users.go
generated
vendored
62
vendor/github.com/xanzy/go-gitlab/users.go
generated
vendored
@ -32,36 +32,40 @@ type UsersService struct {
|
|||||||
|
|
||||||
// User represents a GitLab user.
|
// User represents a GitLab user.
|
||||||
//
|
//
|
||||||
// GitLab API docs: https://docs.gitlab.com/ce/api/users.html
|
// GitLab API docs: https://docs.gitlab.com/ee/api/users.html
|
||||||
type User struct {
|
type User struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
State string `json:"state"`
|
State string `json:"state"`
|
||||||
CreatedAt *time.Time `json:"created_at"`
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
Bio string `json:"bio"`
|
Bio string `json:"bio"`
|
||||||
Location string `json:"location"`
|
Location string `json:"location"`
|
||||||
Skype string `json:"skype"`
|
PublicEmail string `json:"public_email"`
|
||||||
Linkedin string `json:"linkedin"`
|
Skype string `json:"skype"`
|
||||||
Twitter string `json:"twitter"`
|
Linkedin string `json:"linkedin"`
|
||||||
WebsiteURL string `json:"website_url"`
|
Twitter string `json:"twitter"`
|
||||||
Organization string `json:"organization"`
|
WebsiteURL string `json:"website_url"`
|
||||||
ExternUID string `json:"extern_uid"`
|
Organization string `json:"organization"`
|
||||||
Provider string `json:"provider"`
|
ExternUID string `json:"extern_uid"`
|
||||||
ThemeID int `json:"theme_id"`
|
Provider string `json:"provider"`
|
||||||
LastActivityOn *ISOTime `json:"last_activity_on"`
|
ThemeID int `json:"theme_id"`
|
||||||
ColorSchemeID int `json:"color_scheme_id"`
|
LastActivityOn *ISOTime `json:"last_activity_on"`
|
||||||
IsAdmin bool `json:"is_admin"`
|
ColorSchemeID int `json:"color_scheme_id"`
|
||||||
AvatarURL string `json:"avatar_url"`
|
IsAdmin bool `json:"is_admin"`
|
||||||
CanCreateGroup bool `json:"can_create_group"`
|
AvatarURL string `json:"avatar_url"`
|
||||||
CanCreateProject bool `json:"can_create_project"`
|
CanCreateGroup bool `json:"can_create_group"`
|
||||||
ProjectsLimit int `json:"projects_limit"`
|
CanCreateProject bool `json:"can_create_project"`
|
||||||
CurrentSignInAt *time.Time `json:"current_sign_in_at"`
|
ProjectsLimit int `json:"projects_limit"`
|
||||||
LastSignInAt *time.Time `json:"last_sign_in_at"`
|
CurrentSignInAt *time.Time `json:"current_sign_in_at"`
|
||||||
TwoFactorEnabled bool `json:"two_factor_enabled"`
|
LastSignInAt *time.Time `json:"last_sign_in_at"`
|
||||||
Identities []*UserIdentity `json:"identities"`
|
ConfirmedAt *time.Time `json:"confirmed_at"`
|
||||||
External bool `json:"external"`
|
TwoFactorEnabled bool `json:"two_factor_enabled"`
|
||||||
|
Identities []*UserIdentity `json:"identities"`
|
||||||
|
External bool `json:"external"`
|
||||||
|
PrivateProfile bool `json:"private_profile"`
|
||||||
|
SharedRunnersMinutesLimit int `json:"shared_runners_minutes_limit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserIdentity represents a user identity.
|
// UserIdentity represents a user identity.
|
||||||
|
5
vendor/github.com/zmb3/spotify/.travis.yml
generated
vendored
Normal file
5
vendor/github.com/zmb3/spotify/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.8
|
||||||
|
- 1.9
|
201
vendor/github.com/zmb3/spotify/LICENSE
generated
vendored
Normal file
201
vendor/github.com/zmb3/spotify/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
106
vendor/github.com/zmb3/spotify/README.md
generated
vendored
Normal file
106
vendor/github.com/zmb3/spotify/README.md
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
Spotify
|
||||||
|
=======
|
||||||
|
|
||||||
|
[](http://godoc.org/github.com/zmb3/spotify)
|
||||||
|
[](https://ci.appveyor.com/project/zmb3/spotify)
|
||||||
|
[](https://travis-ci.org/zmb3/spotify)
|
||||||
|
|
||||||
|
This is a Go wrapper for working with Spotify's
|
||||||
|
[Web API](https://developer.spotify.com/web-api/).
|
||||||
|
|
||||||
|
It aims to support every task listed in the Web API Endpoint Reference,
|
||||||
|
located [here](https://developer.spotify.com/web-api/endpoint-reference/).
|
||||||
|
|
||||||
|
By using this library you agree to Spotify's
|
||||||
|
[Developer Terms of Use](https://developer.spotify.com/developer-terms-of-use/).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To install the library, simply
|
||||||
|
|
||||||
|
`go get github.com/zmb3/spotify`
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Spotify uses OAuth2 for authentication and authorization.
|
||||||
|
As of May 29, 2017 _all_ Web API endpoints require an access token.
|
||||||
|
|
||||||
|
You can authenticate using a client credentials flow, but this does not provide
|
||||||
|
any authorization to access a user's private data. For most use cases, you'll
|
||||||
|
want to use the authorization code flow. This package includes an `Authenticator`
|
||||||
|
type to handle the details for you.
|
||||||
|
|
||||||
|
Start by registering your application at the following page:
|
||||||
|
|
||||||
|
https://developer.spotify.com/my-applications/.
|
||||||
|
|
||||||
|
You'll get a __client ID__ and __secret key__ for your application. An easy way to
|
||||||
|
provide this data to your application is to set the SPOTIFY_ID and SPOTIFY_SECRET
|
||||||
|
environment variables. If you choose not to use environment variables, you can
|
||||||
|
provide this data manually.
|
||||||
|
|
||||||
|
|
||||||
|
````Go
|
||||||
|
// the redirect URL must be an exact match of a URL you've registered for your application
|
||||||
|
// scopes determine which permissions the user is prompted to authorize
|
||||||
|
auth := spotify.NewAuthenticator(redirectURL, spotify.ScopeUserReadPrivate)
|
||||||
|
|
||||||
|
// if you didn't store your ID and secret key in the specified environment variables,
|
||||||
|
// you can set them manually here
|
||||||
|
auth.SetAuthInfo(clientID, secretKey)
|
||||||
|
|
||||||
|
// get the user to this URL - how you do that is up to you
|
||||||
|
// you should specify a unique state string to identify the session
|
||||||
|
url := auth.AuthURL(state)
|
||||||
|
|
||||||
|
// the user will eventually be redirected back to your redirect URL
|
||||||
|
// typically you'll have a handler set up like the following:
|
||||||
|
func redirectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// use the same state string here that you used to generate the URL
|
||||||
|
token, err := auth.Token(state, r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Couldn't get token", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// create a client using the specified token
|
||||||
|
client := auth.NewClient(token)
|
||||||
|
|
||||||
|
// the client can now be used to make authenticated requests
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
You may find the following resources useful:
|
||||||
|
|
||||||
|
1. Spotify's Web API Authorization Guide:
|
||||||
|
https://developer.spotify.com/web-api/authorization-guide/
|
||||||
|
|
||||||
|
2. Go's OAuth2 package:
|
||||||
|
https://godoc.org/golang.org/x/oauth2/google
|
||||||
|
|
||||||
|
|
||||||
|
## Helpful Hints
|
||||||
|
|
||||||
|
|
||||||
|
### Optional Parameters
|
||||||
|
|
||||||
|
Many of the functions in this package come in two forms - a simple version that
|
||||||
|
omits optional parameters and uses reasonable defaults, and a more sophisticated
|
||||||
|
version that accepts additional parameters. The latter is suffixed with `Opt`
|
||||||
|
to indicate that it accepts some optional parameters.
|
||||||
|
|
||||||
|
### Automatic Retries
|
||||||
|
|
||||||
|
The API will throttle your requests if you are sending them too rapidly.
|
||||||
|
The client can be configured to wait and re-attempt the request.
|
||||||
|
To enable this, set the `AutoRetry` field on the `Client` struct to `true`.
|
||||||
|
|
||||||
|
For more information, see Spotify [rate-limits](https://developer.spotify.com/web-api/user-guide/#rate-limiting).
|
||||||
|
|
||||||
|
## API Examples
|
||||||
|
|
||||||
|
Examples of the API can be found in the [examples](examples) directory.
|
||||||
|
|
||||||
|
You may find tools such as [Spotify's Web API Console](https://developer.spotify.com/web-api/console/)
|
||||||
|
or [Rapid API](https://rapidapi.com/package/SpotifyPublicAPI/functions?utm_source=SpotifyGitHub&utm_medium=button&utm_content=Vendor_GitHub)
|
||||||
|
valuable for experimenting with the API.
|
220
vendor/github.com/zmb3/spotify/album.go
generated
vendored
Normal file
220
vendor/github.com/zmb3/spotify/album.go
generated
vendored
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SimpleAlbum contains basic data about an album.
|
||||||
|
type SimpleAlbum struct {
|
||||||
|
// The name of the album.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// A slice of SimpleArtists
|
||||||
|
Artists []SimpleArtist `json:"artists"`
|
||||||
|
// The field is present when getting an artist’s
|
||||||
|
// albums. Possible values are “album”, “single”,
|
||||||
|
// “compilation”, “appears_on”. Compare to album_type
|
||||||
|
// this field represents relationship between the artist
|
||||||
|
// and the album.
|
||||||
|
AlbumGroup string `json:"album_group"`
|
||||||
|
// The type of the album: one of "album",
|
||||||
|
// "single", or "compilation".
|
||||||
|
AlbumType string `json:"album_type"`
|
||||||
|
// The SpotifyID for the album.
|
||||||
|
ID ID `json:"id"`
|
||||||
|
// The SpotifyURI for the album.
|
||||||
|
URI URI `json:"uri"`
|
||||||
|
// The markets in which the album is available,
|
||||||
|
// identified using ISO 3166-1 alpha-2 country
|
||||||
|
// codes. Note that al album is considered
|
||||||
|
// available in a market when at least 1 of its
|
||||||
|
// tracks is available in that market.
|
||||||
|
AvailableMarkets []string `json:"available_markets"`
|
||||||
|
// A link to the Web API enpoint providing full
|
||||||
|
// details of the album.
|
||||||
|
Endpoint string `json:"href"`
|
||||||
|
// The cover art for the album in various sizes,
|
||||||
|
// widest first.
|
||||||
|
Images []Image `json:"images"`
|
||||||
|
// Known external URLs for this album.
|
||||||
|
ExternalURLs map[string]string `json:"external_urls"`
|
||||||
|
// The date the album was first released. For example, "1981-12-15".
|
||||||
|
// Depending on the ReleaseDatePrecision, it might be shown as
|
||||||
|
// "1981" or "1981-12". You can use ReleaseDateTime to convert this
|
||||||
|
// to a time.Time value.
|
||||||
|
ReleaseDate string `json:"release_date"`
|
||||||
|
// The precision with which ReleaseDate value is known: "year", "month", or "day"
|
||||||
|
ReleaseDatePrecision string `json:"release_date_precision"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyright contains the copyright statement associated with an album.
|
||||||
|
type Copyright struct {
|
||||||
|
// The copyright text for the album.
|
||||||
|
Text string `json:"text"`
|
||||||
|
// The type of copyright.
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullAlbum provides extra album data in addition to the data provided by SimpleAlbum.
|
||||||
|
type FullAlbum struct {
|
||||||
|
SimpleAlbum
|
||||||
|
Artists []SimpleArtist `json:"artists"`
|
||||||
|
Copyrights []Copyright `json:"copyrights"`
|
||||||
|
Genres []string `json:"genres"`
|
||||||
|
// The popularity of the album, represented as an integer between 0 and 100,
|
||||||
|
// with 100 being the most popular. Popularity of an album is calculated
|
||||||
|
// from the popularify of the album's individual tracks.
|
||||||
|
Popularity int `json:"popularity"`
|
||||||
|
// The date the album was first released. For example, "1981-12-15".
|
||||||
|
// Depending on the ReleaseDatePrecision, it might be shown as
|
||||||
|
// "1981" or "1981-12". You can use ReleaseDateTime to convert this
|
||||||
|
// to a time.Time value.
|
||||||
|
ReleaseDate string `json:"release_date"`
|
||||||
|
// The precision with which ReleaseDate value is known: "year", "month", or "day"
|
||||||
|
ReleaseDatePrecision string `json:"release_date_precision"`
|
||||||
|
Tracks SimpleTrackPage `json:"tracks"`
|
||||||
|
ExternalIDs map[string]string `json:"external_ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SavedAlbum provides info about an album saved to an user's account.
|
||||||
|
type SavedAlbum struct {
|
||||||
|
// The date and time the track was saved, represented as an ISO
|
||||||
|
// 8601 UTC timestamp with a zero offset (YYYY-MM-DDTHH:MM:SSZ).
|
||||||
|
// You can use the TimestampLayout constant to convert this to
|
||||||
|
// a time.Time value.
|
||||||
|
AddedAt string `json:"added_at"`
|
||||||
|
FullAlbum `json:"album"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReleaseDateTime converts the album's ReleaseDate to a time.TimeValue.
|
||||||
|
// All of the fields in the result may not be valid. For example, if
|
||||||
|
// f.ReleaseDatePrecision is "month", then only the month and year
|
||||||
|
// (but not the day) of the result are valid.
|
||||||
|
func (f *FullAlbum) ReleaseDateTime() time.Time {
|
||||||
|
if f.ReleaseDatePrecision == "day" {
|
||||||
|
result, _ := time.Parse(DateLayout, f.ReleaseDate)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
if f.ReleaseDatePrecision == "month" {
|
||||||
|
ym := strings.Split(f.ReleaseDate, "-")
|
||||||
|
year, _ := strconv.Atoi(ym[0])
|
||||||
|
month, _ := strconv.Atoi(ym[1])
|
||||||
|
return time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
}
|
||||||
|
year, _ := strconv.Atoi(f.ReleaseDate)
|
||||||
|
return time.Date(year, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAlbum gets Spotify catalog information for a single album, given its Spotify ID.
|
||||||
|
func (c *Client) GetAlbum(id ID) (*FullAlbum, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%salbums/%s", c.baseURL, id)
|
||||||
|
|
||||||
|
var a FullAlbum
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toStringSlice(ids []ID) []string {
|
||||||
|
result := make([]string, len(ids))
|
||||||
|
for i, str := range ids {
|
||||||
|
result[i] = str.String()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAlbums gets Spotify Catalog information for multiple albums, given their
|
||||||
|
// Spotify IDs. It supports up to 20 IDs in a single call. Albums are returned
|
||||||
|
// in the order requested. If an album is not found, that position in the
|
||||||
|
// result slice will be nil.
|
||||||
|
func (c *Client) GetAlbums(ids ...ID) ([]*FullAlbum, error) {
|
||||||
|
if len(ids) > 20 {
|
||||||
|
return nil, errors.New("spotify: exceeded maximum number of albums")
|
||||||
|
}
|
||||||
|
spotifyURL := fmt.Sprintf("%salbums?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ","))
|
||||||
|
|
||||||
|
var a struct {
|
||||||
|
Albums []*FullAlbum `json:"albums"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Albums, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlbumType represents the type of an album. It can be used to filter
|
||||||
|
// results when searching for albums.
|
||||||
|
type AlbumType int
|
||||||
|
|
||||||
|
// AlbumType values that can be used to filter which types of albums are
|
||||||
|
// searched for. These are flags that can be bitwise OR'd together
|
||||||
|
// to search for multiple types of albums simultaneously.
|
||||||
|
const (
|
||||||
|
AlbumTypeAlbum AlbumType = 1 << iota
|
||||||
|
AlbumTypeSingle = 1 << iota
|
||||||
|
AlbummTypeAppearsOn = 1 << iota
|
||||||
|
AlbumTypeCompilation = 1 << iota
|
||||||
|
)
|
||||||
|
|
||||||
|
func (at AlbumType) encode() string {
|
||||||
|
types := []string{}
|
||||||
|
if at&AlbumTypeAlbum != 0 {
|
||||||
|
types = append(types, "album")
|
||||||
|
}
|
||||||
|
if at&AlbumTypeSingle != 0 {
|
||||||
|
types = append(types, "single")
|
||||||
|
}
|
||||||
|
if at&AlbummTypeAppearsOn != 0 {
|
||||||
|
types = append(types, "appears_on")
|
||||||
|
}
|
||||||
|
if at&AlbumTypeCompilation != 0 {
|
||||||
|
types = append(types, "compilation")
|
||||||
|
}
|
||||||
|
return strings.Join(types, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAlbumTracks gets the tracks for a particular album.
|
||||||
|
// If you only care about the tracks, this call is more efficient
|
||||||
|
// than GetAlbum.
|
||||||
|
func (c *Client) GetAlbumTracks(id ID) (*SimpleTrackPage, error) {
|
||||||
|
return c.GetAlbumTracksOpt(id, -1, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAlbumTracksOpt behaves like GetAlbumTracks, with the exception that it
|
||||||
|
// allows you to specify extra parameters that limit the number of results returned.
|
||||||
|
// The maximum number of results to return is specified by limit.
|
||||||
|
// The offset argument can be used to specify the index of the first track to return.
|
||||||
|
// It can be used along with limit to reqeust the next set of results.
|
||||||
|
func (c *Client) GetAlbumTracksOpt(id ID, limit, offset int) (*SimpleTrackPage, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%salbums/%s/tracks", c.baseURL, id)
|
||||||
|
v := url.Values{}
|
||||||
|
if limit != -1 {
|
||||||
|
v.Set("limit", strconv.Itoa(limit))
|
||||||
|
}
|
||||||
|
if offset != -1 {
|
||||||
|
v.Set("offset", strconv.Itoa(offset))
|
||||||
|
}
|
||||||
|
optional := v.Encode()
|
||||||
|
if optional != "" {
|
||||||
|
spotifyURL = spotifyURL + "?" + optional
|
||||||
|
}
|
||||||
|
|
||||||
|
var result SimpleTrackPage
|
||||||
|
err := c.get(spotifyURL, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
152
vendor/github.com/zmb3/spotify/artist.go
generated
vendored
Normal file
152
vendor/github.com/zmb3/spotify/artist.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SimpleArtist contains basic info about an artist.
|
||||||
|
type SimpleArtist struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ID ID `json:"id"`
|
||||||
|
// The Spotify URI for the artist.
|
||||||
|
URI URI `json:"uri"`
|
||||||
|
// A link to the Web API enpoint providing full details of the artist.
|
||||||
|
Endpoint string `json:"href"`
|
||||||
|
ExternalURLs map[string]string `json:"external_urls"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullArtist provides extra artist data in addition to what is provided by SimpleArtist.
|
||||||
|
type FullArtist struct {
|
||||||
|
SimpleArtist
|
||||||
|
// The popularity of the artist, expressed as an integer between 0 and 100.
|
||||||
|
// The artist's popularity is calculated from the popularity of the artist's tracks.
|
||||||
|
Popularity int `json:"popularity"`
|
||||||
|
// A list of genres the artist is associated with. For example, "Prog Rock"
|
||||||
|
// or "Post-Grunge". If not yet classified, the slice is empty.
|
||||||
|
Genres []string `json:"genres"`
|
||||||
|
Followers Followers
|
||||||
|
// Images of the artist in various sizes, widest first.
|
||||||
|
Images []Image `json:"images"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtist gets Spotify catalog information for a single artist, given its Spotify ID.
|
||||||
|
func (c *Client) GetArtist(id ID) (*FullArtist, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%sartists/%s", c.baseURL, id)
|
||||||
|
|
||||||
|
var a FullArtist
|
||||||
|
err := c.get(spotifyURL, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtists gets spotify catalog information for several artists based on their
|
||||||
|
// Spotify IDs. It supports up to 50 artists in a single call. Artists are
|
||||||
|
// returned in the order requested. If an artist is not found, that position
|
||||||
|
// in the result will be nil. Duplicate IDs will result in duplicate artists
|
||||||
|
// in the result.
|
||||||
|
func (c *Client) GetArtists(ids ...ID) ([]*FullArtist, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%sartists?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ","))
|
||||||
|
|
||||||
|
var a struct {
|
||||||
|
Artists []*FullArtist
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Artists, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistsTopTracks gets Spotify catalog information about an artist's top
|
||||||
|
// tracks in a particular country. It returns a maximum of 10 tracks. The
|
||||||
|
// country is specified as an ISO 3166-1 alpha-2 country code.
|
||||||
|
func (c *Client) GetArtistsTopTracks(artistID ID, country string) ([]FullTrack, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%sartists/%s/top-tracks?country=%s", c.baseURL, artistID, country)
|
||||||
|
|
||||||
|
var t struct {
|
||||||
|
Tracks []FullTrack `json:"tracks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.Tracks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRelatedArtists gets Spotify catalog information about artists similar to a
|
||||||
|
// given artist. Similarity is based on analysis of the Spotify community's
|
||||||
|
// listening history. This function returns up to 20 artists that are considered
|
||||||
|
// related to the specified artist.
|
||||||
|
func (c *Client) GetRelatedArtists(id ID) ([]FullArtist, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%sartists/%s/related-artists", c.baseURL, id)
|
||||||
|
|
||||||
|
var a struct {
|
||||||
|
Artists []FullArtist `json:"artists"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Artists, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistAlbums gets Spotify catalog information about an artist's albums.
|
||||||
|
// It is equivalent to GetArtistAlbumsOpt(artistID, nil).
|
||||||
|
func (c *Client) GetArtistAlbums(artistID ID) (*SimpleAlbumPage, error) {
|
||||||
|
return c.GetArtistAlbumsOpt(artistID, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistAlbumsOpt is just like GetArtistAlbums, but it accepts optional
|
||||||
|
// parameters used to filter and sort the result.
|
||||||
|
//
|
||||||
|
// The AlbumType argument can be used to find a particular type of album. Search
|
||||||
|
// for multiple types by OR-ing the types together.
|
||||||
|
func (c *Client) GetArtistAlbumsOpt(artistID ID, options *Options, t *AlbumType) (*SimpleAlbumPage, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%sartists/%s/albums", c.baseURL, artistID)
|
||||||
|
// add optional query string if options were specified
|
||||||
|
values := url.Values{}
|
||||||
|
if t != nil {
|
||||||
|
values.Set("album_type", t.encode())
|
||||||
|
}
|
||||||
|
if options != nil {
|
||||||
|
if options.Country != nil {
|
||||||
|
values.Set("market", *options.Country)
|
||||||
|
} else {
|
||||||
|
// if the market is not specified, Spotify will likely return a lot
|
||||||
|
// of duplicates (one for each market in which the album is available)
|
||||||
|
// - prevent this behavior by falling back to the US by default
|
||||||
|
// TODO: would this ever be the desired behavior?
|
||||||
|
values.Set("market", CountryUSA)
|
||||||
|
}
|
||||||
|
if options.Limit != nil {
|
||||||
|
values.Set("limit", strconv.Itoa(*options.Limit))
|
||||||
|
}
|
||||||
|
if options.Offset != nil {
|
||||||
|
values.Set("offset", strconv.Itoa(*options.Offset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if query := values.Encode(); query != "" {
|
||||||
|
spotifyURL += "?" + query
|
||||||
|
}
|
||||||
|
|
||||||
|
var p SimpleAlbumPage
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &p, nil
|
||||||
|
}
|
110
vendor/github.com/zmb3/spotify/audio_analysis.go
generated
vendored
Normal file
110
vendor/github.com/zmb3/spotify/audio_analysis.go
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AudioAnalysis contains a detailed audio analysis for a single track
|
||||||
|
// identified by its unique Spotify ID. See:
|
||||||
|
// https://developer.spotify.com/web-api/get-audio-analysis/
|
||||||
|
type AudioAnalysis struct {
|
||||||
|
Bars []Marker `json:"bars"`
|
||||||
|
Beats []Marker `json:"beats"`
|
||||||
|
Meta AnalysisMeta `json:"meta"`
|
||||||
|
Sections []Section `json:"sections"`
|
||||||
|
Segments []Segment `json:"segments"`
|
||||||
|
Tatums []Marker `json:"tatums"`
|
||||||
|
Track AnalysisTrack `json:"track"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marker represents beats, bars, tatums and are used in segment and section
|
||||||
|
// descriptions.
|
||||||
|
type Marker struct {
|
||||||
|
Start float64 `json:"start"`
|
||||||
|
Duration float64 `json:"duration"`
|
||||||
|
Confidence float64 `json:"confidence"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnalysisMeta describes details about Spotify's audio analysis of the track
|
||||||
|
type AnalysisMeta struct {
|
||||||
|
AnalyzerVersion string `json:"analyzer_version"`
|
||||||
|
Platform string `json:"platform"`
|
||||||
|
DetailedStatus string `json:"detailed_status"`
|
||||||
|
StatusCode int `json:"status"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
AnalysisTime float64 `json:"analysis_time"`
|
||||||
|
InputProcess string `json:"input_process"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section represents a large variation in rhythm or timbre, e.g. chorus, verse,
|
||||||
|
// bridge, guitar solo, etc. Each section contains its own descriptions of
|
||||||
|
// tempo, key, mode, time_signature, and loudness.
|
||||||
|
type Section struct {
|
||||||
|
Marker
|
||||||
|
Loudness float64 `json:"loudness"`
|
||||||
|
Tempo float64 `json:"tempo"`
|
||||||
|
TempoConfidence float64 `json:"tempo_confidence"`
|
||||||
|
Key Key `json:"key"`
|
||||||
|
KeyConfidence float64 `json:"key_confidence"`
|
||||||
|
Mode Mode `json:"mode"`
|
||||||
|
ModeConfidence float64 `json:"mode_confidence"`
|
||||||
|
TimeSignature int `json:"time_signature"`
|
||||||
|
TimeSignatureConfidence float64 `json:"time_signature_confidence"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Segment is characterized by it's perceptual onset and duration in seconds,
|
||||||
|
// loudness (dB), pitch and timbral content.
|
||||||
|
type Segment struct {
|
||||||
|
Marker
|
||||||
|
LoudnessStart float64 `json:"loudness_start"`
|
||||||
|
LoudnessMaxTime float64 `json:"loudness_max_time"`
|
||||||
|
LoudnessMax float64 `json:"loudness_max"`
|
||||||
|
LoudnessEnd float64 `json:"loudness_end"`
|
||||||
|
Pitches []float64 `json:"pitches"`
|
||||||
|
Timbre []float64 `json:"timbre"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnalysisTrack contains audio analysis data about the track as a whole
|
||||||
|
type AnalysisTrack struct {
|
||||||
|
NumSamples int64 `json:"num_samples"`
|
||||||
|
Duration float64 `json:"duration"`
|
||||||
|
SampleMD5 string `json:"sample_md5"`
|
||||||
|
OffsetSeconds int `json:"offset_seconds"`
|
||||||
|
WindowSeconds int `json:"window_seconds"`
|
||||||
|
AnalysisSampleRate int64 `json:"analysis_sample_rate"`
|
||||||
|
AnalysisChannels int `json:"analysis_channels"`
|
||||||
|
EndOfFadeIn float64 `json:"end_of_fade_in"`
|
||||||
|
StartOfFadeOut float64 `json:"start_of_fade_out"`
|
||||||
|
Loudness float64 `json:"loudness"`
|
||||||
|
Tempo float64 `json:"tempo"`
|
||||||
|
TempoConfidence float64 `json:"tempo_confidence"`
|
||||||
|
TimeSignature int `json:"time_signature"`
|
||||||
|
TimeSignatureConfidence float64 `json:"time_signature_confidence"`
|
||||||
|
Key Key `json:"key"`
|
||||||
|
KeyConfidence float64 `json:"key_confidence"`
|
||||||
|
Mode Mode `json:"mode"`
|
||||||
|
ModeConfidence float64 `json:"mode_confidence"`
|
||||||
|
CodeString string `json:"codestring"`
|
||||||
|
CodeVersion float64 `json:"code_version"`
|
||||||
|
EchoprintString string `json:"echoprintstring"`
|
||||||
|
EchoprintVersion float64 `json:"echoprint_version"`
|
||||||
|
SynchString string `json:"synchstring"`
|
||||||
|
SynchVersion float64 `json:"synch_version"`
|
||||||
|
RhythmString string `json:"rhythmstring"`
|
||||||
|
RhythmVersion float64 `json:"rhythm_version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAudioAnalysis queries the Spotify web API for an audio analysis of a
|
||||||
|
// single track.
|
||||||
|
func (c *Client) GetAudioAnalysis(id ID) (*AudioAnalysis, error) {
|
||||||
|
url := fmt.Sprintf("%saudio-analysis/%s", c.baseURL, id)
|
||||||
|
|
||||||
|
temp := AudioAnalysis{}
|
||||||
|
|
||||||
|
err := c.get(url, &temp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &temp, nil
|
||||||
|
}
|
123
vendor/github.com/zmb3/spotify/audio_features.go
generated
vendored
Normal file
123
vendor/github.com/zmb3/spotify/audio_features.go
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AudioFeatures contains various high-level acoustic attributes
|
||||||
|
// for a particular track.
|
||||||
|
type AudioFeatures struct {
|
||||||
|
//Acousticness is a confidence measure from 0.0 to 1.0 of whether
|
||||||
|
// the track is acoustic. A value of 1.0 represents high confidence
|
||||||
|
// that the track is acoustic.
|
||||||
|
Acousticness float32 `json:"acousticness"`
|
||||||
|
// An HTTP URL to access the full audio analysis of the track.
|
||||||
|
// The URL is cryptographically signed and configured to expire
|
||||||
|
// after roughly 10 minutes. Do not store these URLs for later use.
|
||||||
|
AnalysisURL string `json:"analysis_url"`
|
||||||
|
// Danceability describes how suitable a track is for dancing based
|
||||||
|
// on a combination of musical elements including tempo, rhythm stability,
|
||||||
|
// beat strength, and overall regularity. A value of 0.0 is least danceable
|
||||||
|
// and 1.0 is most danceable.
|
||||||
|
Danceability float32 `json:"danceability"`
|
||||||
|
// The length of the track in milliseconds.
|
||||||
|
Duration int `json:"duration_ms"`
|
||||||
|
// Energy is a measure from 0.0 to 1.0 and represents a perceptual mesaure
|
||||||
|
// of intensity and activity. Typically, energetic tracks feel fast, loud,
|
||||||
|
// and noisy.
|
||||||
|
Energy float32 `json:"energy"`
|
||||||
|
// The Spotify ID for the track.
|
||||||
|
ID ID `json:"id"`
|
||||||
|
// Predicts whether a track contains no vocals. "Ooh" and "aah" sounds are
|
||||||
|
// treated as instrumental in this context. Rap or spoken words are clearly
|
||||||
|
// "vocal". The closer the Instrumentalness value is to 1.0, the greater
|
||||||
|
// likelihood the track contains no vocal content. Values above 0.5 are
|
||||||
|
// intended to represent instrumental tracks, but confidence is higher as the
|
||||||
|
// value approaches 1.0.
|
||||||
|
Instrumentalness float32 `json:"instrumentalness"`
|
||||||
|
// The key the track is in. Integers map to pitches using standard Pitch Class notation
|
||||||
|
// (https://en.wikipedia.org/wiki/Pitch_class).
|
||||||
|
Key int `json:"key"`
|
||||||
|
// Detects the presence of an audience in the recording. Higher liveness
|
||||||
|
// values represent an increased probability that the track was performed live.
|
||||||
|
// A value above 0.8 provides strong likelihook that the track is live.
|
||||||
|
Liveness float32 `json:"liveness"`
|
||||||
|
// The overall loudness of a track in decibels (dB). Loudness values are
|
||||||
|
// averaged across the entire track and are useful for comparing the relative
|
||||||
|
// loudness of tracks. Typical values range between -60 and 0 dB.
|
||||||
|
Loudness float32 `json:"loudness"`
|
||||||
|
// Mode indicates the modality (major or minor) of a track.
|
||||||
|
Mode int `json:"mode"`
|
||||||
|
// Detects the presence of spoken words in a track. The more exclusively
|
||||||
|
// speech-like the recording, the closer to 1.0 the speechiness will be.
|
||||||
|
// Values above 0.66 describe tracks that are probably made entirely of
|
||||||
|
// spoken words. Values between 0.33 and 0.66 describe tracks that may
|
||||||
|
// contain both music and speech, including such cases as rap music.
|
||||||
|
// Values below 0.33 most likely represent music and other non-speech-like tracks.
|
||||||
|
Speechiness float32 `json:"speechiness"`
|
||||||
|
// The overall estimated tempo of the track in beats per minute (BPM).
|
||||||
|
Tempo float32 `json:"tempo"`
|
||||||
|
// An estimated overall time signature of a track. The time signature (meter)
|
||||||
|
// is a notational convention to specify how many beats are in each bar (or measure).
|
||||||
|
TimeSignature int `json:"time_signature"`
|
||||||
|
// A link to the Web API endpoint providing full details of the track.
|
||||||
|
TrackURL string `json:"track_href"`
|
||||||
|
// The Spotify URI for the track.
|
||||||
|
URI URI `json:"uri"`
|
||||||
|
// A measure from 0.0 to 1.0 describing the musical positiveness conveyed
|
||||||
|
// by a track. Tracks with high valence sound more positive (e.g. happy,
|
||||||
|
// cheerful, euphoric), while tracks with low valence sound more negative
|
||||||
|
// (e.g. sad, depressed, angry).
|
||||||
|
Valence float32 `json:"valence"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key represents a pitch using Pitch Class notation.
|
||||||
|
type Key int
|
||||||
|
|
||||||
|
const (
|
||||||
|
C Key = iota
|
||||||
|
CSharp
|
||||||
|
D
|
||||||
|
DSharp
|
||||||
|
E
|
||||||
|
F
|
||||||
|
FSharp
|
||||||
|
G
|
||||||
|
GSharp
|
||||||
|
A
|
||||||
|
ASharp
|
||||||
|
B
|
||||||
|
DFlat = CSharp
|
||||||
|
EFlat = DSharp
|
||||||
|
GFlat = FSharp
|
||||||
|
AFlat = GSharp
|
||||||
|
BFlat = ASharp
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mode indicates the modality (major or minor) of a track.
|
||||||
|
type Mode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Minor Mode = iota
|
||||||
|
Major
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetAudioFeatures queries the Spotify Web API for various
|
||||||
|
// high-level acoustic attributes of audio tracks.
|
||||||
|
// Objects are returned in the order requested. If an object
|
||||||
|
// is not found, a nil value is returned in the appropriate position.
|
||||||
|
func (c *Client) GetAudioFeatures(ids ...ID) ([]*AudioFeatures, error) {
|
||||||
|
url := fmt.Sprintf("%saudio-features?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ","))
|
||||||
|
|
||||||
|
temp := struct {
|
||||||
|
F []*AudioFeatures `json:"audio_features"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err := c.get(url, &temp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp.F, nil
|
||||||
|
}
|
180
vendor/github.com/zmb3/spotify/auth.go
generated
vendored
Normal file
180
vendor/github.com/zmb3/spotify/auth.go
generated
vendored
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AuthURL is the URL to Spotify Accounts Service's OAuth2 endpoint.
|
||||||
|
AuthURL = "https://accounts.spotify.com/authorize"
|
||||||
|
// TokenURL is the URL to the Spotify Accounts Service's OAuth2
|
||||||
|
// token endpoint.
|
||||||
|
TokenURL = "https://accounts.spotify.com/api/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scopes let you specify exactly which types of data your application wants to access.
|
||||||
|
// The set of scopes you pass in your authentication request determines what access the
|
||||||
|
// permissions the user is asked to grant.
|
||||||
|
const (
|
||||||
|
// ScopeImageUpload seeks permission to upload images to Spotify on your behalf.
|
||||||
|
ScopeImageUpload = "ugc-image-upload"
|
||||||
|
// ScopePlaylistReadPrivate seeks permission to read
|
||||||
|
// a user's private playlists.
|
||||||
|
ScopePlaylistReadPrivate = "playlist-read-private"
|
||||||
|
// ScopePlaylistModifyPublic seeks write access
|
||||||
|
// to a user's public playlists.
|
||||||
|
ScopePlaylistModifyPublic = "playlist-modify-public"
|
||||||
|
// ScopePlaylistModifyPrivate seeks write access to
|
||||||
|
// a user's private playlists.
|
||||||
|
ScopePlaylistModifyPrivate = "playlist-modify-private"
|
||||||
|
// ScopePlaylistReadCollaborative seeks permission to
|
||||||
|
// access a user's collaborative playlists.
|
||||||
|
ScopePlaylistReadCollaborative = "playlist-read-collaborative"
|
||||||
|
// ScopeUserFollowModify seeks write/delete access to
|
||||||
|
// the list of artists and other users that a user follows.
|
||||||
|
ScopeUserFollowModify = "user-follow-modify"
|
||||||
|
// ScopeUserFollowRead seeks read access to the list of
|
||||||
|
// artists and other users that a user follows.
|
||||||
|
ScopeUserFollowRead = "user-follow-read"
|
||||||
|
// ScopeUserLibraryModify seeks write/delete access to a
|
||||||
|
// user's "Your Music" library.
|
||||||
|
ScopeUserLibraryModify = "user-library-modify"
|
||||||
|
// ScopeUserLibraryRead seeks read access to a user's "Your Music" library.
|
||||||
|
ScopeUserLibraryRead = "user-library-read"
|
||||||
|
// ScopeUserReadPrivate seeks read access to a user's
|
||||||
|
// subsription details (type of user account).
|
||||||
|
ScopeUserReadPrivate = "user-read-private"
|
||||||
|
// ScopeUserReadEmail seeks read access to a user's email address.
|
||||||
|
ScopeUserReadEmail = "user-read-email"
|
||||||
|
// ScopeUserReadBirthdate seeks read access to a user's birthdate.
|
||||||
|
ScopeUserReadBirthdate = "user-read-birthdate"
|
||||||
|
// ScopeUserReadCurrentlyPlaying seeks read access to a user's currently playing track
|
||||||
|
ScopeUserReadCurrentlyPlaying = "user-read-currently-playing"
|
||||||
|
// ScopeUserReadPlaybackState seeks read access to the user's current playback state
|
||||||
|
ScopeUserReadPlaybackState = "user-read-playback-state"
|
||||||
|
// ScopeUserModifyPlaybackState seeks write access to the user's current playback state
|
||||||
|
ScopeUserModifyPlaybackState = "user-modify-playback-state"
|
||||||
|
// ScopeUserReadRecentlyPlayed allows access to a user's recently-played songs
|
||||||
|
ScopeUserReadRecentlyPlayed = "user-read-recently-played"
|
||||||
|
// ScopeUserTopRead seeks read access to a user's top tracks and artists
|
||||||
|
ScopeUserTopRead = "user-top-read"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Authenticator provides convenience functions for implementing the OAuth2 flow.
|
||||||
|
// You should always use `NewAuthenticator` to make them.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// a := spotify.NewAuthenticator(redirectURL, spotify.ScopeUserLibaryRead, spotify.ScopeUserFollowRead)
|
||||||
|
// // direct user to Spotify to log in
|
||||||
|
// http.Redirect(w, r, a.AuthURL("state-string"), http.StatusFound)
|
||||||
|
//
|
||||||
|
// // then, in redirect handler:
|
||||||
|
// token, err := a.Token(state, r)
|
||||||
|
// client := a.NewClient(token)
|
||||||
|
//
|
||||||
|
type Authenticator struct {
|
||||||
|
config *oauth2.Config
|
||||||
|
context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAuthenticator creates an authenticator which is used to implement the
|
||||||
|
// OAuth2 authorization flow. The redirectURL must exactly match one of the
|
||||||
|
// URLs specified in your Spotify developer account.
|
||||||
|
//
|
||||||
|
// By default, NewAuthenticator pulls your client ID and secret key from the
|
||||||
|
// SPOTIFY_ID and SPOTIFY_SECRET environment variables. If you'd like to provide
|
||||||
|
// them from some other source, you can call `SetAuthInfo(id, key)` on the
|
||||||
|
// returned authenticator.
|
||||||
|
func NewAuthenticator(redirectURL string, scopes ...string) Authenticator {
|
||||||
|
cfg := &oauth2.Config{
|
||||||
|
ClientID: os.Getenv("SPOTIFY_ID"),
|
||||||
|
ClientSecret: os.Getenv("SPOTIFY_SECRET"),
|
||||||
|
RedirectURL: redirectURL,
|
||||||
|
Scopes: scopes,
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: AuthURL,
|
||||||
|
TokenURL: TokenURL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable HTTP/2 for DefaultClient, see: https://github.com/zmb3/spotify/issues/20
|
||||||
|
tr := &http.Transport{
|
||||||
|
TLSNextProto: map[string]func(authority string, c *tls.Conn) http.RoundTripper{},
|
||||||
|
}
|
||||||
|
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{Transport: tr})
|
||||||
|
return Authenticator{
|
||||||
|
config: cfg,
|
||||||
|
context: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthInfo overwrites the client ID and secret key used by the authenticator.
|
||||||
|
// You can use this if you don't want to store this information in environment variables.
|
||||||
|
func (a *Authenticator) SetAuthInfo(clientID, secretKey string) {
|
||||||
|
a.config.ClientID = clientID
|
||||||
|
a.config.ClientSecret = secretKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthURL returns a URL to the the Spotify Accounts Service's OAuth2 endpoint.
|
||||||
|
//
|
||||||
|
// State is a token to protect the user from CSRF attacks. You should pass the
|
||||||
|
// same state to `Token`, where it will be validated. For more info, refer to
|
||||||
|
// http://tools.ietf.org/html/rfc6749#section-10.12.
|
||||||
|
func (a Authenticator) AuthURL(state string) string {
|
||||||
|
return a.config.AuthCodeURL(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token pulls an authorization code from an HTTP request and attempts to exchange
|
||||||
|
// it for an access token. The standard use case is to call Token from the handler
|
||||||
|
// that handles requests to your application's redirect URL.
|
||||||
|
func (a Authenticator) Token(state string, r *http.Request) (*oauth2.Token, error) {
|
||||||
|
values := r.URL.Query()
|
||||||
|
if e := values.Get("error"); e != "" {
|
||||||
|
return nil, errors.New("spotify: auth failed - " + e)
|
||||||
|
}
|
||||||
|
code := values.Get("code")
|
||||||
|
if code == "" {
|
||||||
|
return nil, errors.New("spotify: didn't get access code")
|
||||||
|
}
|
||||||
|
actualState := values.Get("state")
|
||||||
|
if actualState != state {
|
||||||
|
return nil, errors.New("spotify: redirect state parameter doesn't match")
|
||||||
|
}
|
||||||
|
return a.config.Exchange(a.context, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exchange is like Token, except it allows you to manually specify the access
|
||||||
|
// code instead of pulling it out of an HTTP request.
|
||||||
|
func (a Authenticator) Exchange(code string) (*oauth2.Token, error) {
|
||||||
|
return a.config.Exchange(a.context, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates a Client that will use the specified access token for its API requests.
|
||||||
|
func (a Authenticator) NewClient(token *oauth2.Token) Client {
|
||||||
|
client := a.config.Client(a.context, token)
|
||||||
|
return Client{
|
||||||
|
http: client,
|
||||||
|
baseURL: baseAddress,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token gets the client's current token.
|
||||||
|
func (c *Client) Token() (*oauth2.Token, error) {
|
||||||
|
transport, ok := c.http.Transport.(*oauth2.Transport)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("spotify: oauth2 transport type not correct")
|
||||||
|
}
|
||||||
|
t, err := transport.Source.Token()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
140
vendor/github.com/zmb3/spotify/category.go
generated
vendored
Normal file
140
vendor/github.com/zmb3/spotify/category.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Category is used by Spotify to tag items in. For example, on the Spotify
|
||||||
|
// player's "Browse" tab.
|
||||||
|
type Category struct {
|
||||||
|
// A link to the Web API endpoint returning full details of the category
|
||||||
|
Endpoint string `json:"href"`
|
||||||
|
// The category icon, in various sizes
|
||||||
|
Icons []Image `json:"icons"`
|
||||||
|
// The Spotify category ID. This isn't a base-62 Spotify ID, its just
|
||||||
|
// a short string that describes and identifies the category (ie "party").
|
||||||
|
ID string `json:"id"`
|
||||||
|
// The name of the category
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCategoryOpt is like GetCategory, but it accepts optional arguments.
|
||||||
|
// The country parameter is an ISO 3166-1 alpha-2 country code. It can be
|
||||||
|
// used to ensure that the category exists for a particular country. The
|
||||||
|
// locale argument is an ISO 639 language code and an ISO 3166-1 alpha-2
|
||||||
|
// country code, separated by an underscore. It can be used to get the
|
||||||
|
// category strings in a particular language (for example: "es_MX" means
|
||||||
|
// get categories in Mexico, returned in Spanish).
|
||||||
|
//
|
||||||
|
// This call requries authorization.
|
||||||
|
func (c *Client) GetCategoryOpt(id, country, locale string) (Category, error) {
|
||||||
|
cat := Category{}
|
||||||
|
spotifyURL := fmt.Sprintf("%sbrowse/categories/%s", c.baseURL, id)
|
||||||
|
values := url.Values{}
|
||||||
|
if country != "" {
|
||||||
|
values.Set("country", country)
|
||||||
|
}
|
||||||
|
if locale != "" {
|
||||||
|
values.Set("locale", locale)
|
||||||
|
}
|
||||||
|
if query := values.Encode(); query != "" {
|
||||||
|
spotifyURL += "?" + query
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &cat)
|
||||||
|
if err != nil {
|
||||||
|
return cat, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cat, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCategory gets a single category used to tag items in Spotify
|
||||||
|
// (on, for example, the Spotify player's Browse tab).
|
||||||
|
func (c *Client) GetCategory(id string) (Category, error) {
|
||||||
|
return c.GetCategoryOpt(id, "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCategoryPlaylists gets a list of Spotify playlists tagged with a paricular category.
|
||||||
|
func (c *Client) GetCategoryPlaylists(catID string) (*SimplePlaylistPage, error) {
|
||||||
|
return c.GetCategoryPlaylistsOpt(catID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCategoryPlaylistsOpt is like GetCategoryPlaylists, but it accepts optional
|
||||||
|
// arguments.
|
||||||
|
func (c *Client) GetCategoryPlaylistsOpt(catID string, opt *Options) (*SimplePlaylistPage, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%sbrowse/categories/%s/playlists", c.baseURL, catID)
|
||||||
|
if opt != nil {
|
||||||
|
values := url.Values{}
|
||||||
|
if opt.Country != nil {
|
||||||
|
values.Set("country", *opt.Country)
|
||||||
|
}
|
||||||
|
if opt.Limit != nil {
|
||||||
|
values.Set("limit", strconv.Itoa(*opt.Limit))
|
||||||
|
}
|
||||||
|
if opt.Offset != nil {
|
||||||
|
values.Set("offset", strconv.Itoa(*opt.Offset))
|
||||||
|
}
|
||||||
|
if query := values.Encode(); query != "" {
|
||||||
|
spotifyURL += "?" + query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper := struct {
|
||||||
|
Playlists SimplePlaylistPage `json:"playlists"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &wrapper)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &wrapper.Playlists, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCategories gets a list of categories used to tag items in Spotify
|
||||||
|
// (on, for example, the Spotify player's "Browse" tab).
|
||||||
|
func (c *Client) GetCategories() (*CategoryPage, error) {
|
||||||
|
return c.GetCategoriesOpt(nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCategoriesOpt is like GetCategories, but it accepts optional parameters.
|
||||||
|
//
|
||||||
|
// The locale option can be used to get the results in a particular language.
|
||||||
|
// It consists of an ISO 639 language code and an ISO 3166-1 alpha-2 country
|
||||||
|
// code, separated by an underscore. Specify the empty string to have results
|
||||||
|
// returned in the Spotify default language (American English).
|
||||||
|
func (c *Client) GetCategoriesOpt(opt *Options, locale string) (*CategoryPage, error) {
|
||||||
|
spotifyURL := c.baseURL + "browse/categories"
|
||||||
|
values := url.Values{}
|
||||||
|
if locale != "" {
|
||||||
|
values.Set("locale", locale)
|
||||||
|
}
|
||||||
|
if opt != nil {
|
||||||
|
if opt.Country != nil {
|
||||||
|
values.Set("country", *opt.Country)
|
||||||
|
}
|
||||||
|
if opt.Limit != nil {
|
||||||
|
values.Set("limit", strconv.Itoa(*opt.Limit))
|
||||||
|
}
|
||||||
|
if opt.Offset != nil {
|
||||||
|
values.Set("offset", strconv.Itoa(*opt.Offset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if query := values.Encode(); query != "" {
|
||||||
|
spotifyURL += "?" + query
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper := struct {
|
||||||
|
Categories CategoryPage `json:"categories"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &wrapper)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &wrapper.Categories, nil
|
||||||
|
}
|
32
vendor/github.com/zmb3/spotify/countries.go
generated
vendored
Normal file
32
vendor/github.com/zmb3/spotify/countries.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
// ISO 3166-1 alpha 2 country codes.
|
||||||
|
//
|
||||||
|
// see: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
|
||||||
|
const (
|
||||||
|
CountryArgentina = "AR"
|
||||||
|
CountryAustralia = "AU"
|
||||||
|
CountryAustria = "AT"
|
||||||
|
CountryBelarus = "BY"
|
||||||
|
CountryBelgium = "BE"
|
||||||
|
CountryBrazil = "BR"
|
||||||
|
CountryCanada = "CA"
|
||||||
|
CountryChile = "CL"
|
||||||
|
CountryChina = "CN"
|
||||||
|
CountryGermany = "DE"
|
||||||
|
CountryHongKong = "HK"
|
||||||
|
CountryIreland = "IE"
|
||||||
|
CountryIndia = "IN"
|
||||||
|
CountryItaly = "IT"
|
||||||
|
CountryJapan = "JP"
|
||||||
|
CountrySpain = "ES"
|
||||||
|
CountryFinland = "FI"
|
||||||
|
CountryFrance = "FR"
|
||||||
|
CountryMexico = "MX"
|
||||||
|
CountryNewZealand = "NZ"
|
||||||
|
CountryRussia = "RU"
|
||||||
|
CountrySwitzerland = "CH"
|
||||||
|
CountryUnitedArabEmirates = "AE"
|
||||||
|
CountryUnitedKingdom = "GB"
|
||||||
|
CountryUSA = "US"
|
||||||
|
)
|
37
vendor/github.com/zmb3/spotify/cursor.go
generated
vendored
Normal file
37
vendor/github.com/zmb3/spotify/cursor.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
// This file contains the types that implement Spotify's cursor-based
|
||||||
|
// paging object. Like the standard paging object, this object is a
|
||||||
|
// container for a set of items. Unlike the standard paging object, a
|
||||||
|
// cursor-based paging object does not provide random access to the results.
|
||||||
|
|
||||||
|
// Cursor contains a key that can be used to find the next set
|
||||||
|
// of items.
|
||||||
|
type Cursor struct {
|
||||||
|
After string `json:"after"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// cursorPage contains all of the fields in a Spotify cursor-based
|
||||||
|
// paging object, except for the actual items. This type is meant
|
||||||
|
// to be embedded in other types that add the Items field.
|
||||||
|
type cursorPage struct {
|
||||||
|
// A link to the Web API endpoint returning the full
|
||||||
|
// result of this request.
|
||||||
|
Endpoint string `json:"href"`
|
||||||
|
// The maximum number of items returned, as set in the query
|
||||||
|
// (or default value if unset).
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
// The URL to the next set of items.
|
||||||
|
Next string `json:"next"`
|
||||||
|
// The total number of items available to return.
|
||||||
|
Total int `json:"total"`
|
||||||
|
// The cursor used to find the next set of items.
|
||||||
|
Cursor Cursor `json:"cursors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullArtistCursorPage is a cursor-based paging object containing
|
||||||
|
// a set of FullArtist objects.
|
||||||
|
type FullArtistCursorPage struct {
|
||||||
|
cursorPage
|
||||||
|
Artists []FullArtist `json:"items"`
|
||||||
|
}
|
5
vendor/github.com/zmb3/spotify/full_tests.bat
generated
vendored
Normal file
5
vendor/github.com/zmb3/spotify/full_tests.bat
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@echo off
|
||||||
|
REM - The tests that actually hit the Spotify Web API don't run by default.
|
||||||
|
REM - Use this script to run them in addition to the standard unit tests.
|
||||||
|
|
||||||
|
cmd /C "set FULLTEST=y && go test %*"
|
61
vendor/github.com/zmb3/spotify/library.go
generated
vendored
Normal file
61
vendor/github.com/zmb3/spotify/library.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserHasTracks checks if one or more tracks are saved to the current user's
|
||||||
|
// "Your Music" library.
|
||||||
|
func (c *Client) UserHasTracks(ids ...ID) ([]bool, error) {
|
||||||
|
if l := len(ids); l == 0 || l > 50 {
|
||||||
|
return nil, errors.New("spotify: UserHasTracks supports 1 to 50 IDs per call")
|
||||||
|
}
|
||||||
|
spotifyURL := fmt.Sprintf("%sme/tracks/contains?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ","))
|
||||||
|
|
||||||
|
var result []bool
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTracksToLibrary saves one or more tracks to the current user's
|
||||||
|
// "Your Music" library. This call requires the ScopeUserLibraryModify scope.
|
||||||
|
// A track can only be saved once; duplicate IDs are ignored.
|
||||||
|
func (c *Client) AddTracksToLibrary(ids ...ID) error {
|
||||||
|
return c.modifyLibraryTracks(true, ids...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveTracksFromLibrary removes one or more tracks from the current user's
|
||||||
|
// "Your Music" library. This call requires the ScopeUserModifyLibrary scope.
|
||||||
|
// Trying to remove a track when you do not have the user's authorization
|
||||||
|
// results in a `spotify.Error` with the status code set to http.StatusUnauthorized.
|
||||||
|
func (c *Client) RemoveTracksFromLibrary(ids ...ID) error {
|
||||||
|
return c.modifyLibraryTracks(false, ids...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) modifyLibraryTracks(add bool, ids ...ID) error {
|
||||||
|
if l := len(ids); l == 0 || l > 50 {
|
||||||
|
return errors.New("spotify: this call supports 1 to 50 IDs per call")
|
||||||
|
}
|
||||||
|
spotifyURL := fmt.Sprintf("%sme/tracks?ids=%s", c.baseURL, strings.Join(toStringSlice(ids), ","))
|
||||||
|
method := "DELETE"
|
||||||
|
if add {
|
||||||
|
method = "PUT"
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(method, spotifyURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
87
vendor/github.com/zmb3/spotify/page.go
generated
vendored
Normal file
87
vendor/github.com/zmb3/spotify/page.go
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrNoMorePages is the error returned when you attempt to get the next
|
||||||
|
// (or previous) set of data but you've reached the end of the data set.
|
||||||
|
var ErrNoMorePages = errors.New("spotify: no more pages")
|
||||||
|
|
||||||
|
// This file contains the types that implement Spotify's paging object.
|
||||||
|
// See: https://developer.spotify.com/web-api/object-model/#paging-object
|
||||||
|
|
||||||
|
// basePage contains all of the fields in a Spotify paging object, except
|
||||||
|
// for the actual items. This type is meant to be embedded in other types
|
||||||
|
// that add the Items field.
|
||||||
|
type basePage struct {
|
||||||
|
// A link to the Web API Endpoint returning the full
|
||||||
|
// result of this request.
|
||||||
|
Endpoint string `json:"href"`
|
||||||
|
// The maximum number of items in the response, as set
|
||||||
|
// in the query (or default value if unset).
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
// The offset of the items returned, as set in the query
|
||||||
|
// (or default value if unset).
|
||||||
|
Offset int `json:"offset"`
|
||||||
|
// The total number of items available to return.
|
||||||
|
Total int `json:"total"`
|
||||||
|
// The URL to the next page of items (if available).
|
||||||
|
Next string `json:"next"`
|
||||||
|
// The URL to the previous page of items (if available).
|
||||||
|
Previous string `json:"previous"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullArtistPage contains FullArtists returned by the Web API.
|
||||||
|
type FullArtistPage struct {
|
||||||
|
basePage
|
||||||
|
Artists []FullArtist `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimpleAlbumPage contains SimpleAlbums returned by the Web API.
|
||||||
|
type SimpleAlbumPage struct {
|
||||||
|
basePage
|
||||||
|
Albums []SimpleAlbum `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SavedAlbumPage contains SavedAlbums returned by the Web API.
|
||||||
|
type SavedAlbumPage struct {
|
||||||
|
basePage
|
||||||
|
Albums []SavedAlbum `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimplePlaylistPage contains SimplePlaylists returned by the Web API.
|
||||||
|
type SimplePlaylistPage struct {
|
||||||
|
basePage
|
||||||
|
Playlists []SimplePlaylist `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimpleTrackPage contains SimpleTracks returned by the Web API.
|
||||||
|
type SimpleTrackPage struct {
|
||||||
|
basePage
|
||||||
|
Tracks []SimpleTrack `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullTrackPage contains FullTracks returned by the Web API.
|
||||||
|
type FullTrackPage struct {
|
||||||
|
basePage
|
||||||
|
Tracks []FullTrack `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SavedTrackPage contains SavedTracks return by the Web API.
|
||||||
|
type SavedTrackPage struct {
|
||||||
|
basePage
|
||||||
|
Tracks []SavedTrack `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlaylistTrackPage contains information about tracks in a playlist.
|
||||||
|
type PlaylistTrackPage struct {
|
||||||
|
basePage
|
||||||
|
Tracks []PlaylistTrack `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CategoryPage contains Category objects returned by the Web API.
|
||||||
|
type CategoryPage struct {
|
||||||
|
basePage
|
||||||
|
Categories []Category `json:"items"`
|
||||||
|
}
|
528
vendor/github.com/zmb3/spotify/player.go
generated
vendored
Executable file
528
vendor/github.com/zmb3/spotify/player.go
generated
vendored
Executable file
@ -0,0 +1,528 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PlayerDevice contains information about a device that a user can play music on
|
||||||
|
type PlayerDevice struct {
|
||||||
|
// ID of the device. This may be empty.
|
||||||
|
ID ID `json:"id"`
|
||||||
|
// Active If this device is the currently active device.
|
||||||
|
Active bool `json:"is_active"`
|
||||||
|
// Restricted Whether controlling this device is restricted. At present if
|
||||||
|
// this is "true" then no Web API commands will be accepted by this device.
|
||||||
|
Restricted bool `json:"is_restricted"`
|
||||||
|
// Name The name of the device.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Type of device, such as "Computer", "Smartphone" or "Speaker".
|
||||||
|
Type string `json:"type"`
|
||||||
|
// Volume The current volume in percent.
|
||||||
|
Volume int `json:"volume_percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerState contains information about the current playback.
|
||||||
|
type PlayerState struct {
|
||||||
|
CurrentlyPlaying
|
||||||
|
// Device The device that is currently active
|
||||||
|
Device PlayerDevice `json:"device"`
|
||||||
|
// ShuffleState Shuffle is on or off
|
||||||
|
ShuffleState bool `json:"shuffle_state"`
|
||||||
|
// RepeatState off, track, context
|
||||||
|
RepeatState string `json:"repeat_state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlaybackContext is the playback context
|
||||||
|
type PlaybackContext struct {
|
||||||
|
// ExternalURLs of the context, or null if not available.
|
||||||
|
ExternalURLs map[string]string `json:"external_urls"`
|
||||||
|
// Endpoint of the context, or null if not available.
|
||||||
|
Endpoint string `json:"href"`
|
||||||
|
// Type of the item's context. Can be one of album, artist or playlist.
|
||||||
|
Type string `json:"type"`
|
||||||
|
// URI is the Spotify URI for the context.
|
||||||
|
URI URI `json:"uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentlyPlaying contains the information about currently playing items
|
||||||
|
type CurrentlyPlaying struct {
|
||||||
|
// Timestamp when data was fetched
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
// PlaybackContext current context
|
||||||
|
PlaybackContext PlaybackContext `json:"context"`
|
||||||
|
// Progress into the currently playing track.
|
||||||
|
Progress int `json:"progress_ms"`
|
||||||
|
// Playing If something is currently playing.
|
||||||
|
Playing bool `json:"is_playing"`
|
||||||
|
// The currently playing track. Can be null.
|
||||||
|
Item *FullTrack `json:"Item"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecentlyPlayedItem struct {
|
||||||
|
// Track is the track information
|
||||||
|
Track SimpleTrack `json:"track"`
|
||||||
|
|
||||||
|
// PlayedAt is the time that this song was played
|
||||||
|
PlayedAt time.Time `json:"played_at"`
|
||||||
|
|
||||||
|
// PlaybackContext is the current playback context
|
||||||
|
PlaybackContext PlaybackContext `json:"context"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecentlyPlayedResult struct {
|
||||||
|
Items []RecentlyPlayedItem `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlaybackOffset can be specified either by track URI OR Position. If both are present the
|
||||||
|
// request will return 400 BAD REQUEST. If incorrect values are provided for position or uri,
|
||||||
|
// the request may be accepted but with an unpredictable resulting action on playback.
|
||||||
|
type PlaybackOffset struct {
|
||||||
|
// Position is zero based and can’t be negative.
|
||||||
|
Position int `json:"position,omitempty"`
|
||||||
|
// URI is a string representing the uri of the item to start at.
|
||||||
|
URI URI `json:"uri,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PlayOptions struct {
|
||||||
|
// DeviceID The id of the device this command is targeting. If not
|
||||||
|
// supplied, the user's currently active device is the target.
|
||||||
|
DeviceID *ID `json:"-"`
|
||||||
|
// PlaybackContext Spotify URI of the context to play.
|
||||||
|
// Valid contexts are albums, artists & playlists.
|
||||||
|
PlaybackContext *URI `json:"context_uri,omitempty"`
|
||||||
|
// URIs Array of the Spotify track URIs to play
|
||||||
|
URIs []URI `json:"uris,omitempty"`
|
||||||
|
// PlaybackOffset Indicates from where in the context playback should start.
|
||||||
|
// Only available when context corresponds to an album or playlist
|
||||||
|
// object, or when the URIs parameter is used.
|
||||||
|
PlaybackOffset *PlaybackOffset `json:"offset,omitempty"`
|
||||||
|
// PositionMs Indicates from what position to start playback.
|
||||||
|
// Must be a positive number. Passing in a position that is greater
|
||||||
|
// than the length of the track will cause the player to start playing the next song.
|
||||||
|
// Defaults to 0, starting a track from the beginning.
|
||||||
|
PositionMs int `json:"position_ms,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecentlyPlayedOptions describes options for the recently-played request. All
|
||||||
|
// fields are optional. Only one of `AfterEpochMs` and `BeforeEpochMs` may be
|
||||||
|
// given. Note that it seems as if Spotify only remembers the fifty most-recent
|
||||||
|
// tracks as of right now.
|
||||||
|
type RecentlyPlayedOptions struct {
|
||||||
|
// Limit is the maximum number of items to return. Must be no greater than
|
||||||
|
// fifty.
|
||||||
|
Limit int
|
||||||
|
|
||||||
|
// AfterEpochMs is a Unix epoch in milliseconds that describes a time after
|
||||||
|
// which to return songs.
|
||||||
|
AfterEpochMs int64
|
||||||
|
|
||||||
|
// BeforeEpochMs is a Unix epoch in milliseconds that describes a time
|
||||||
|
// before which to return songs.
|
||||||
|
BeforeEpochMs int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerDevices information about available devices for the current user.
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserReadPlaybackState scope in order to read information
|
||||||
|
func (c *Client) PlayerDevices() ([]PlayerDevice, error) {
|
||||||
|
var result struct {
|
||||||
|
PlayerDevices []PlayerDevice `json:"devices"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.get(c.baseURL+"me/player/devices", &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.PlayerDevices, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerState gets information about the playing state for the current user
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserReadPlaybackState scope in order to read information
|
||||||
|
func (c *Client) PlayerState() (*PlayerState, error) {
|
||||||
|
return c.PlayerStateOpt(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerStateOpt is like PlayerState, but it accepts additional
|
||||||
|
// options for sorting and filtering the results.
|
||||||
|
func (c *Client) PlayerStateOpt(opt *Options) (*PlayerState, error) {
|
||||||
|
spotifyURL := c.baseURL + "me/player"
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.Country != nil {
|
||||||
|
v.Set("market", *opt.Country)
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result PlayerState
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerCurrentlyPlaying gets information about the currently playing status
|
||||||
|
// for the current user.
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserReadCurrentlyPlaying scope or the ScopeUserReadPlaybackState
|
||||||
|
// scope in order to read information
|
||||||
|
func (c *Client) PlayerCurrentlyPlaying() (*CurrentlyPlaying, error) {
|
||||||
|
return c.PlayerCurrentlyPlayingOpt(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerCurrentlyPlayingOpt is like PlayerCurrentlyPlaying, but it accepts
|
||||||
|
// additional options for sorting and filtering the results.
|
||||||
|
func (c *Client) PlayerCurrentlyPlayingOpt(opt *Options) (*CurrentlyPlaying, error) {
|
||||||
|
spotifyURL := c.baseURL + "me/player/currently-playing"
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.Country != nil {
|
||||||
|
v.Set("market", *opt.Country)
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", spotifyURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result CurrentlyPlaying
|
||||||
|
err = c.execute(req, &result, http.StatusNoContent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerRecentlyPlayed gets a list of recently-played tracks for the current
|
||||||
|
// user. This call requires ScopeUserReadRecentlyPlayed.
|
||||||
|
func (c *Client) PlayerRecentlyPlayed() ([]RecentlyPlayedItem, error) {
|
||||||
|
return c.PlayerRecentlyPlayedOpt(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerRecentlyPlayedOpt is like PlayerRecentlyPlayed, but it accepts
|
||||||
|
// additional options for sorting and filtering the results.
|
||||||
|
func (c *Client) PlayerRecentlyPlayedOpt(opt *RecentlyPlayedOptions) ([]RecentlyPlayedItem, error) {
|
||||||
|
spotifyURL := c.baseURL + "me/player/recently-played"
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.Limit != 0 {
|
||||||
|
v.Set("limit", strconv.FormatInt(int64(opt.Limit), 10))
|
||||||
|
}
|
||||||
|
if opt.BeforeEpochMs != 0 {
|
||||||
|
v.Set("before", strconv.FormatInt(int64(opt.BeforeEpochMs), 10))
|
||||||
|
}
|
||||||
|
if opt.AfterEpochMs != 0 {
|
||||||
|
v.Set("after", strconv.FormatInt(int64(opt.AfterEpochMs), 10))
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := RecentlyPlayedResult{}
|
||||||
|
err := c.get(spotifyURL, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransferPlayback transfers playback to a new device and determine if
|
||||||
|
// it should start playing.
|
||||||
|
//
|
||||||
|
// Note that a value of false for the play parameter when also transferring
|
||||||
|
// to another device_id will not pause playback. To ensure that playback is
|
||||||
|
// paused on the new device you should send a pause command to the currently
|
||||||
|
// active device before transferring to the new device_id.
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserModifyPlaybackState in order to modify the player state
|
||||||
|
func (c *Client) TransferPlayback(deviceID ID, play bool) error {
|
||||||
|
reqData := struct {
|
||||||
|
DeviceID []ID `json:"device_ids"`
|
||||||
|
Play bool `json:"play"`
|
||||||
|
}{
|
||||||
|
DeviceID: []ID{deviceID},
|
||||||
|
Play: play,
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
err := json.NewEncoder(buf).Encode(reqData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodPut, c.baseURL+"me/player", buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil, http.StatusNoContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play Start a new context or resume current playback on the user's active
|
||||||
|
// device. This call requires ScopeUserModifyPlaybackState in order to modify the player state.
|
||||||
|
func (c *Client) Play() error {
|
||||||
|
return c.PlayOpt(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayOpt is like Play but with more options
|
||||||
|
func (c *Client) PlayOpt(opt *PlayOptions) error {
|
||||||
|
spotifyURL := c.baseURL + "me/player/play"
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.DeviceID != nil {
|
||||||
|
v.Set("device_id", opt.DeviceID.String())
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
|
||||||
|
err := json.NewEncoder(buf).Encode(opt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodPut, spotifyURL, buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil, http.StatusNoContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause Playback on the user's currently active device.
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserModifyPlaybackState in order to modify the player state
|
||||||
|
func (c *Client) Pause() error {
|
||||||
|
return c.PauseOpt(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PauseOpt is like Pause but with more options
|
||||||
|
//
|
||||||
|
// Only expects PlayOptions.DeviceID, all other options will be ignored
|
||||||
|
func (c *Client) PauseOpt(opt *PlayOptions) error {
|
||||||
|
spotifyURL := c.baseURL + "me/player/pause"
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.DeviceID != nil {
|
||||||
|
v.Set("device_id", opt.DeviceID.String())
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodPut, spotifyURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil, http.StatusNoContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next skips to the next track in the user's queue in the user's
|
||||||
|
// currently active device. This call requires ScopeUserModifyPlaybackState
|
||||||
|
// in order to modify the player state
|
||||||
|
func (c *Client) Next() error {
|
||||||
|
return c.NextOpt(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextOpt is like Next but with more options
|
||||||
|
//
|
||||||
|
// Only expects PlayOptions.DeviceID, all other options will be ignored
|
||||||
|
func (c *Client) NextOpt(opt *PlayOptions) error {
|
||||||
|
spotifyURL := c.baseURL + "me/player/next"
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.DeviceID != nil {
|
||||||
|
v.Set("device_id", opt.DeviceID.String())
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodPost, spotifyURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil, http.StatusNoContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous skips to the Previous track in the user's queue in the user's
|
||||||
|
// currently active device. This call requires ScopeUserModifyPlaybackState
|
||||||
|
// in order to modify the player state
|
||||||
|
func (c *Client) Previous() error {
|
||||||
|
return c.PreviousOpt(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreviousOpt is like Previous but with more options
|
||||||
|
//
|
||||||
|
// Only expects PlayOptions.DeviceID, all other options will be ignored
|
||||||
|
func (c *Client) PreviousOpt(opt *PlayOptions) error {
|
||||||
|
spotifyURL := c.baseURL + "me/player/previous"
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.DeviceID != nil {
|
||||||
|
v.Set("device_id", opt.DeviceID.String())
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodPost, spotifyURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil, http.StatusNoContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek to the given position in the user’s currently playing track.
|
||||||
|
//
|
||||||
|
// The position in milliseconds to seek to. Must be a positive number.
|
||||||
|
// Passing in a position that is greater than the length of the track
|
||||||
|
// will cause the player to start playing the next song.
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserModifyPlaybackState in order to modify the player state
|
||||||
|
func (c *Client) Seek(position int) error {
|
||||||
|
return c.SeekOpt(position, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SeekOpt is like Seek but with more options
|
||||||
|
//
|
||||||
|
// Only expects PlayOptions.DeviceID, all other options will be ignored
|
||||||
|
func (c *Client) SeekOpt(position int, opt *PlayOptions) error {
|
||||||
|
return c.playerFuncWithOpt(
|
||||||
|
"me/player/seek",
|
||||||
|
url.Values{
|
||||||
|
"position_ms": []string{strconv.FormatInt(int64(position), 10)},
|
||||||
|
},
|
||||||
|
opt,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeat Set the repeat mode for the user's playback.
|
||||||
|
//
|
||||||
|
// Options are repeat-track, repeat-context, and off.
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserModifyPlaybackState in order to modify the player state.
|
||||||
|
func (c *Client) Repeat(state string) error {
|
||||||
|
return c.RepeatOpt(state, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepeatOpt is like Repeat but with more options
|
||||||
|
//
|
||||||
|
// Only expects PlayOptions.DeviceID, all other options will be ignored.
|
||||||
|
func (c *Client) RepeatOpt(state string, opt *PlayOptions) error {
|
||||||
|
return c.playerFuncWithOpt(
|
||||||
|
"me/player/repeat",
|
||||||
|
url.Values{
|
||||||
|
"state": []string{state},
|
||||||
|
},
|
||||||
|
opt,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume set the volume for the user's current playback device.
|
||||||
|
//
|
||||||
|
// Percent is must be a value from 0 to 100 inclusive.
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserModifyPlaybackState in order to modify the player state
|
||||||
|
func (c *Client) Volume(percent int) error {
|
||||||
|
return c.VolumeOpt(percent, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumeOpt is like Volume but with more options
|
||||||
|
//
|
||||||
|
// Only expects PlayOptions.DeviceID, all other options will be ignored
|
||||||
|
func (c *Client) VolumeOpt(percent int, opt *PlayOptions) error {
|
||||||
|
return c.playerFuncWithOpt(
|
||||||
|
"me/player/volume",
|
||||||
|
url.Values{
|
||||||
|
"volume_percent": []string{strconv.FormatInt(int64(percent), 10)},
|
||||||
|
},
|
||||||
|
opt,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle switches shuffle on or off for user's playback.
|
||||||
|
//
|
||||||
|
// Requires the ScopeUserModifyPlaybackState in order to modify the player state
|
||||||
|
func (c *Client) Shuffle(shuffle bool) error {
|
||||||
|
return c.ShuffleOpt(shuffle, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShuffleOpt is like Shuffle but with more options
|
||||||
|
//
|
||||||
|
// Only expects PlayOptions.DeviceID, all other options will be ignored
|
||||||
|
func (c *Client) ShuffleOpt(shuffle bool, opt *PlayOptions) error {
|
||||||
|
return c.playerFuncWithOpt(
|
||||||
|
"me/player/shuffle",
|
||||||
|
url.Values{
|
||||||
|
"state": []string{strconv.FormatBool(shuffle)},
|
||||||
|
},
|
||||||
|
opt,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) playerFuncWithOpt(urlSuffix string, values url.Values, opt *PlayOptions) error {
|
||||||
|
spotifyURL := c.baseURL + urlSuffix
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
if opt.DeviceID != nil {
|
||||||
|
values.Set("device_id", opt.DeviceID.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params := values.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPut, spotifyURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil, http.StatusNoContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
662
vendor/github.com/zmb3/spotify/playlist.go
generated
vendored
Normal file
662
vendor/github.com/zmb3/spotify/playlist.go
generated
vendored
Normal file
@ -0,0 +1,662 @@
|
|||||||
|
package spotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PlaylistTracks contains details about the tracks in a playlist.
|
||||||
|
type PlaylistTracks struct {
|
||||||
|
// A link to the Web API endpoint where full details of
|
||||||
|
// the playlist's tracks can be retrieved.
|
||||||
|
Endpoint string `json:"href"`
|
||||||
|
// The total number of tracks in the playlist.
|
||||||
|
Total uint `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimplePlaylist contains basic info about a Spotify playlist.
|
||||||
|
type SimplePlaylist struct {
|
||||||
|
// Indicates whether the playlist owner allows others to modify the playlist.
|
||||||
|
// Note: only non-collaborative playlists are currently returned by Spotify's Web API.
|
||||||
|
Collaborative bool `json:"collaborative"`
|
||||||
|
ExternalURLs map[string]string `json:"external_urls"`
|
||||||
|
// A link to the Web API endpoint providing full details of the playlist.
|
||||||
|
Endpoint string `json:"href"`
|
||||||
|
ID ID `json:"id"`
|
||||||
|
// The playlist image. Note: this field is only returned for modified,
|
||||||
|
// verified playlists. Otherwise the slice is empty. If returned, the source
|
||||||
|
// URL for the image is temporary and will expire in less than a day.
|
||||||
|
Images []Image `json:"images"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Owner User `json:"owner"`
|
||||||
|
IsPublic bool `json:"public"`
|
||||||
|
// The version identifier for the current playlist. Can be supplied in other
|
||||||
|
// requests to target a specific playlist version.
|
||||||
|
SnapshotID string `json:"snapshot_id"`
|
||||||
|
// A collection to the Web API endpoint where full details of the playlist's
|
||||||
|
// tracks can be retrieved, along with the total number of tracks in the playlist.
|
||||||
|
Tracks PlaylistTracks `json:"tracks"`
|
||||||
|
URI URI `json:"uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullPlaylist provides extra playlist data in addition to the data provided by SimplePlaylist.
|
||||||
|
type FullPlaylist struct {
|
||||||
|
SimplePlaylist
|
||||||
|
// The playlist description. Only returned for modified, verified playlists.
|
||||||
|
Description string `json:"description"`
|
||||||
|
// Information about the followers of this playlist.
|
||||||
|
Followers Followers `json:"followers"`
|
||||||
|
Tracks PlaylistTrackPage `json:"tracks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlaylistOptions contains optional parameters that can be used when querying
|
||||||
|
// for featured playlists. Only the non-nil fields are used in the request.
|
||||||
|
type PlaylistOptions struct {
|
||||||
|
Options
|
||||||
|
// The desired language, consisting of a lowercase IO 639
|
||||||
|
// language code and an uppercase ISO 3166-1 alpha-2
|
||||||
|
// country code, joined by an underscore. Provide this
|
||||||
|
// parameter if you want the results returned in a particular
|
||||||
|
// language. If not specified, the result will be returned
|
||||||
|
// in the Spotify default language (American English).
|
||||||
|
Locale *string
|
||||||
|
// A timestamp in ISO 8601 format (yyyy-MM-ddTHH:mm:ss).
|
||||||
|
// use this paramter to specify the user's local time to
|
||||||
|
// get results tailored for that specific date and time
|
||||||
|
// in the day. If not provided, the response defaults to
|
||||||
|
// the current UTC time.
|
||||||
|
Timestamp *string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FeaturedPlaylistsOpt gets a list of playlists featured by Spotify.
|
||||||
|
// It accepts a number of optional parameters via the opt argument.
|
||||||
|
func (c *Client) FeaturedPlaylistsOpt(opt *PlaylistOptions) (message string, playlists *SimplePlaylistPage, e error) {
|
||||||
|
spotifyURL := c.baseURL + "browse/featured-playlists"
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.Locale != nil {
|
||||||
|
v.Set("locale", *opt.Locale)
|
||||||
|
}
|
||||||
|
if opt.Country != nil {
|
||||||
|
v.Set("country", *opt.Country)
|
||||||
|
}
|
||||||
|
if opt.Timestamp != nil {
|
||||||
|
v.Set("timestamp", *opt.Timestamp)
|
||||||
|
}
|
||||||
|
if opt.Limit != nil {
|
||||||
|
v.Set("limit", strconv.Itoa(*opt.Limit))
|
||||||
|
}
|
||||||
|
if opt.Offset != nil {
|
||||||
|
v.Set("offset", strconv.Itoa(*opt.Offset))
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
Playlists SimplePlaylistPage `json:"playlists"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &result)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Message, &result.Playlists, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FeaturedPlaylists gets a list of playlists featured by Spotify.
|
||||||
|
// It is equivalent to c.FeaturedPlaylistsOpt(nil).
|
||||||
|
func (c *Client) FeaturedPlaylists() (message string, playlists *SimplePlaylistPage, e error) {
|
||||||
|
return c.FeaturedPlaylistsOpt(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FollowPlaylist adds the current user as a follower of the specified
|
||||||
|
// playlist. Any playlist can be followed, regardless of its private/public
|
||||||
|
// status, as long as you know the owner and playlist ID.
|
||||||
|
//
|
||||||
|
// If the public argument is true, then the playlist will be included in the
|
||||||
|
// user's public playlists. To be able to follow playlists privately, the user
|
||||||
|
// must have granted the ScopePlaylistModifyPrivate scope. The
|
||||||
|
// ScopePlaylistModifyPublic scope is required to follow playlists publicly.
|
||||||
|
func (c *Client) FollowPlaylist(owner ID, playlist ID, public bool) error {
|
||||||
|
spotifyURL := buildFollowURI(c.baseURL, owner, playlist)
|
||||||
|
body := strings.NewReader(strconv.FormatBool(public))
|
||||||
|
req, err := http.NewRequest("PUT", spotifyURL, body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
err = c.execute(req, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnfollowPlaylist removes the current user as a follower of a playlist.
|
||||||
|
// Unfollowing a publicly followed playlist requires ScopePlaylistModifyPublic.
|
||||||
|
// Unfolowing a privately followed playlist requies ScopePlaylistModifyPrivate.
|
||||||
|
func (c *Client) UnfollowPlaylist(owner, playlist ID) error {
|
||||||
|
spotifyURL := buildFollowURI(c.baseURL, owner, playlist)
|
||||||
|
req, err := http.NewRequest("DELETE", spotifyURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildFollowURI(url string, owner, playlist ID) string {
|
||||||
|
return fmt.Sprintf("%susers/%s/playlists/%s/followers",
|
||||||
|
url, string(owner), string(playlist))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlaylistsForUser gets a list of the playlists owned or followed by a
|
||||||
|
// particular Spotify user.
|
||||||
|
//
|
||||||
|
// Private playlists and collaborative playlists are only retrievable for the
|
||||||
|
// current user. In order to read private playlists, the user must have granted
|
||||||
|
// the ScopePlaylistReadPrivate scope. Note that this scope alone will not
|
||||||
|
// return collaborative playlists, even though they are always private. In
|
||||||
|
// order to read collaborative playlists, the user must have granted the
|
||||||
|
// ScopePlaylistReadCollaborative scope.
|
||||||
|
func (c *Client) GetPlaylistsForUser(userID string) (*SimplePlaylistPage, error) {
|
||||||
|
return c.GetPlaylistsForUserOpt(userID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlaylistsForUserOpt is like PlaylistsForUser, but it accepts optional paramters
|
||||||
|
// for filtering the results.
|
||||||
|
func (c *Client) GetPlaylistsForUserOpt(userID string, opt *Options) (*SimplePlaylistPage, error) {
|
||||||
|
spotifyURL := c.baseURL + "users/" + userID + "/playlists"
|
||||||
|
if opt != nil {
|
||||||
|
v := url.Values{}
|
||||||
|
if opt.Limit != nil {
|
||||||
|
v.Set("limit", strconv.Itoa(*opt.Limit))
|
||||||
|
}
|
||||||
|
if opt.Offset != nil {
|
||||||
|
v.Set("offset", strconv.Itoa(*opt.Offset))
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result SimplePlaylistPage
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlaylist gets a playlist
|
||||||
|
func (c *Client) GetPlaylist(playlistID ID) (*FullPlaylist, error) {
|
||||||
|
return c.GetPlaylistOpt(playlistID, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlaylistOpt is like GetPlaylist, but it accepts an optional fields parameter
|
||||||
|
// that can be used to filter the query.
|
||||||
|
//
|
||||||
|
// fields is a comma-separated list of the fields to return.
|
||||||
|
// See the JSON tags on the FullPlaylist struct for valid field options.
|
||||||
|
// For example, to get just the playlist's description and URI:
|
||||||
|
// fields = "description,uri"
|
||||||
|
//
|
||||||
|
// A dot separator can be used to specify non-reoccurring fields, while
|
||||||
|
// parentheses can be used to specify reoccurring fields within objects.
|
||||||
|
// For example, to get just the added date and the user ID of the adder:
|
||||||
|
// fields = "tracks.items(added_at,added_by.id)"
|
||||||
|
//
|
||||||
|
// Use multiple parentheses to drill down into nested objects, for example:
|
||||||
|
// fields = "tracks.items(track(name,href,album(name,href)))"
|
||||||
|
//
|
||||||
|
// Fields can be excluded by prefixing them with an exclamation mark, for example;
|
||||||
|
// fields = "tracks.items(track(name,href,album(!name,href)))"
|
||||||
|
func (c *Client) GetPlaylistOpt(playlistID ID, fields string) (*FullPlaylist, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s", c.baseURL, playlistID)
|
||||||
|
if fields != "" {
|
||||||
|
spotifyURL += "?fields=" + url.QueryEscape(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
var playlist FullPlaylist
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &playlist)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &playlist, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlaylistTracks gets full details of the tracks in a playlist, given the
|
||||||
|
// playlist's Spotify ID.
|
||||||
|
func (c *Client) GetPlaylistTracks(playlistID ID) (*PlaylistTrackPage, error) {
|
||||||
|
return c.GetPlaylistTracksOpt(playlistID, nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlaylistTracksOpt is like GetPlaylistTracks, but it accepts optional parameters
|
||||||
|
// for sorting and filtering the results.
|
||||||
|
//
|
||||||
|
// The field parameter is a comma-separated list of the fields to return. See the
|
||||||
|
// JSON struct tags for the PlaylistTrackPage type for valid field names.
|
||||||
|
// For example, to get just the total number of tracks and the request limit:
|
||||||
|
// fields = "total,limit"
|
||||||
|
//
|
||||||
|
// A dot separator can be used to specify non-reoccurring fields, while parentheses
|
||||||
|
// can be used to specify reoccurring fields within objects. For example, to get
|
||||||
|
// just the added date and user ID of the adder:
|
||||||
|
// fields = "items(added_at,added_by.id
|
||||||
|
//
|
||||||
|
// Use multiple parentheses to drill down into nested objects. For example:
|
||||||
|
// fields = "items(track(name,href,album(name,href)))"
|
||||||
|
//
|
||||||
|
// Fields can be excluded by prefixing them with an exclamation mark. For example:
|
||||||
|
// fields = "items.track.album(!external_urls,images)"
|
||||||
|
func (c *Client) GetPlaylistTracksOpt(playlistID ID,
|
||||||
|
opt *Options, fields string) (*PlaylistTrackPage, error) {
|
||||||
|
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s/tracks", c.baseURL, playlistID)
|
||||||
|
v := url.Values{}
|
||||||
|
if fields != "" {
|
||||||
|
v.Set("fields", fields)
|
||||||
|
}
|
||||||
|
if opt != nil {
|
||||||
|
if opt.Limit != nil {
|
||||||
|
v.Set("limit", strconv.Itoa(*opt.Limit))
|
||||||
|
}
|
||||||
|
if opt.Offset != nil {
|
||||||
|
v.Set("offset", strconv.Itoa(*opt.Offset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if params := v.Encode(); params != "" {
|
||||||
|
spotifyURL += "?" + params
|
||||||
|
}
|
||||||
|
|
||||||
|
var result PlaylistTrackPage
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatePlaylistForUser creates a playlist for a Spotify user.
|
||||||
|
// The playlist will be empty until you add tracks to it.
|
||||||
|
// The playlistName does not need to be unique - a user can have
|
||||||
|
// several playlists with the same name.
|
||||||
|
//
|
||||||
|
// Creating a public playlist for a user requires ScopePlaylistModifyPublic;
|
||||||
|
// creating a private playlist requires ScopePlaylistModifyPrivate.
|
||||||
|
//
|
||||||
|
// On success, the newly created playlist is returned.
|
||||||
|
func (c *Client) CreatePlaylistForUser(userID, playlistName, description string, public bool) (*FullPlaylist, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%susers/%s/playlists", c.baseURL, userID)
|
||||||
|
body := struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Public bool `json:"public"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}{
|
||||||
|
playlistName,
|
||||||
|
public,
|
||||||
|
description,
|
||||||
|
}
|
||||||
|
bodyJSON, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", spotifyURL, bytes.NewReader(bodyJSON))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
var p FullPlaylist
|
||||||
|
err = c.execute(req, &p, http.StatusCreated)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangePlaylistName changes the name of a playlist. This call requires that the
|
||||||
|
// user has authorized the ScopePlaylistModifyPublic or ScopePlaylistModifyPrivate
|
||||||
|
// scopes (depending on whether the playlist is public or private).
|
||||||
|
// The current user must own the playlist in order to modify it.
|
||||||
|
func (c *Client) ChangePlaylistName(playlistID ID, newName string) error {
|
||||||
|
return c.modifyPlaylist(playlistID, newName, "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangePlaylistAccess modifies the public/private status of a playlist. This call
|
||||||
|
// requires that the user has authorized the ScopePlaylistModifyPublic or
|
||||||
|
// ScopePlaylistModifyPrivate scopes (depending on whether the playlist is
|
||||||
|
// currently public or private). The current user must own the playlist in order to modify it.
|
||||||
|
func (c *Client) ChangePlaylistAccess(playlistID ID, public bool) error {
|
||||||
|
return c.modifyPlaylist(playlistID, "", "", &public)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangePlaylistDescription modifies the description of a playlist. This call
|
||||||
|
// requires that the user has authorized the ScopePlaylistModifyPublic or
|
||||||
|
// ScopePlaylistModifyPrivate scopes (depending on whether the playlist is
|
||||||
|
// currently public or private). The current user must own the playlist in order to modify it.
|
||||||
|
func (c *Client) ChangePlaylistDescription(playlistID ID, newDescription string) error {
|
||||||
|
return c.modifyPlaylist(playlistID, "", newDescription, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangePlaylistNameAndAccess combines ChangePlaylistName and ChangePlaylistAccess into
|
||||||
|
// a single Web API call. It requires that the user has authorized the ScopePlaylistModifyPublic
|
||||||
|
// or ScopePlaylistModifyPrivate scopes (depending on whether the playlist is currently
|
||||||
|
// public or private). The current user must own the playlist in order to modify it.
|
||||||
|
func (c *Client) ChangePlaylistNameAndAccess(playlistID ID, newName string, public bool) error {
|
||||||
|
return c.modifyPlaylist(playlistID, newName, "", &public)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangePlaylistNameAccessAndDescription combines ChangePlaylistName, ChangePlaylistAccess, and
|
||||||
|
// ChangePlaylistDescription into a single Web API call. It requires that the user has authorized
|
||||||
|
// the ScopePlaylistModifyPublic or ScopePlaylistModifyPrivate scopes (depending on whether the
|
||||||
|
// playlist is currently public or private). The current user must own the playlist in order to modify it.
|
||||||
|
func (c *Client) ChangePlaylistNameAccessAndDescription(playlistID ID, newName, newDescription string, public bool) error {
|
||||||
|
return c.modifyPlaylist(playlistID, newName, newDescription, &public)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) modifyPlaylist(playlistID ID, newName, newDescription string, public *bool) error {
|
||||||
|
body := struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Public *bool `json:"public,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
}{
|
||||||
|
newName,
|
||||||
|
public,
|
||||||
|
newDescription,
|
||||||
|
}
|
||||||
|
bodyJSON, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s", c.baseURL, string(playlistID))
|
||||||
|
req, err := http.NewRequest("PUT", spotifyURL, bytes.NewReader(bodyJSON))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
err = c.execute(req, nil, http.StatusCreated)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTracksToPlaylist adds one or more tracks to a user's playlist.
|
||||||
|
// This call requires ScopePlaylistModifyPublic or ScopePlaylistModifyPrivate.
|
||||||
|
// A maximum of 100 tracks can be added per call. It returns a snapshot ID that
|
||||||
|
// can be used to identify this version (the new version) of the playlist in
|
||||||
|
// future requests.
|
||||||
|
func (c *Client) AddTracksToPlaylist(playlistID ID, trackIDs ...ID) (snapshotID string, err error) {
|
||||||
|
|
||||||
|
uris := make([]string, len(trackIDs))
|
||||||
|
for i, id := range trackIDs {
|
||||||
|
uris[i] = fmt.Sprintf("spotify:track:%s", id)
|
||||||
|
}
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
m["uris"] = uris
|
||||||
|
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s/tracks",
|
||||||
|
c.baseURL, string(playlistID))
|
||||||
|
body, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST", spotifyURL, bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
result := struct {
|
||||||
|
SnapshotID string `json:"snapshot_id"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err = c.execute(req, &result, http.StatusCreated)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.SnapshotID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveTracksFromPlaylist removes one or more tracks from a user's playlist.
|
||||||
|
// This call requrles that the user has authorized the ScopePlaylistModifyPublic
|
||||||
|
// or ScopePlaylistModifyPrivate scopes.
|
||||||
|
//
|
||||||
|
// If the track(s) occur multiple times in the specified playlist, then all occurrences
|
||||||
|
// of the track will be removed. If successful, the snapshot ID returned can be used to
|
||||||
|
// identify the playlist version in future requests.
|
||||||
|
func (c *Client) RemoveTracksFromPlaylist(playlistID ID, trackIDs ...ID) (newSnapshotID string, err error) {
|
||||||
|
|
||||||
|
tracks := make([]struct {
|
||||||
|
URI string `json:"uri"`
|
||||||
|
}, len(trackIDs))
|
||||||
|
|
||||||
|
for i, u := range trackIDs {
|
||||||
|
tracks[i].URI = fmt.Sprintf("spotify:track:%s", u)
|
||||||
|
}
|
||||||
|
return c.removeTracksFromPlaylist(playlistID, tracks, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackToRemove specifies a track to be removed from a playlist.
|
||||||
|
// Positions is a slice of 0-based track indices.
|
||||||
|
// TrackToRemove is used with RemoveTracksFromPlaylistOpt.
|
||||||
|
type TrackToRemove struct {
|
||||||
|
URI string `json:"uri"`
|
||||||
|
Positions []int `json:"positions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTrackToRemove creates a new TrackToRemove object with the specified
|
||||||
|
// track ID and playlist locations.
|
||||||
|
func NewTrackToRemove(trackID string, positions []int) TrackToRemove {
|
||||||
|
return TrackToRemove{
|
||||||
|
URI: fmt.Sprintf("spotify:track:%s", trackID),
|
||||||
|
Positions: positions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveTracksFromPlaylistOpt is like RemoveTracksFromPlaylist, but it supports
|
||||||
|
// optional parameters that offer more fine-grained control. Instead of deleting
|
||||||
|
// all occurrences of a track, this function takes an index with each track URI
|
||||||
|
// that indicates the position of the track in the playlist.
|
||||||
|
//
|
||||||
|
// In addition, the snapshotID parameter allows you to specify the snapshot ID
|
||||||
|
// against which you want to make the changes. Spotify will validate that the
|
||||||
|
// specified tracks exist in the specified positions and make the changes, even
|
||||||
|
// if more recent changes have been made to the playlist. If a track in the
|
||||||
|
// specified position is not found, the entire request will fail and no edits
|
||||||
|
// will take place. (Note: the snapshot is optional, pass the empty string if
|
||||||
|
// you don't care about it.)
|
||||||
|
func (c *Client) RemoveTracksFromPlaylistOpt(playlistID ID,
|
||||||
|
tracks []TrackToRemove, snapshotID string) (newSnapshotID string, err error) {
|
||||||
|
|
||||||
|
return c.removeTracksFromPlaylist(playlistID, tracks, snapshotID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) removeTracksFromPlaylist(playlistID ID,
|
||||||
|
tracks interface{}, snapshotID string) (newSnapshotID string, err error) {
|
||||||
|
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
m["tracks"] = tracks
|
||||||
|
if snapshotID != "" {
|
||||||
|
m["snapshot_id"] = snapshotID
|
||||||
|
}
|
||||||
|
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s/tracks",
|
||||||
|
c.baseURL, string(playlistID))
|
||||||
|
body, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("DELETE", spotifyURL, bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
result := struct {
|
||||||
|
SnapshotID string `json:"snapshot_id"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err = c.execute(req, &result)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.SnapshotID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplacePlaylistTracks replaces all of the tracks in a playlist, overwriting its
|
||||||
|
// exising tracks This can be useful for replacing or reordering tracks, or for
|
||||||
|
// clearing a playlist.
|
||||||
|
//
|
||||||
|
// Modifying a public playlist requires that the user has authorized the
|
||||||
|
// ScopePlaylistModifyPublic scope. Modifying a private playlist requires the
|
||||||
|
// ScopePlaylistModifyPrivate scope.
|
||||||
|
//
|
||||||
|
// A maximum of 100 tracks is permited in this call. Additional tracks must be
|
||||||
|
// added via AddTracksToPlaylist.
|
||||||
|
func (c *Client) ReplacePlaylistTracks(playlistID ID, trackIDs ...ID) error {
|
||||||
|
trackURIs := make([]string, len(trackIDs))
|
||||||
|
for i, u := range trackIDs {
|
||||||
|
trackURIs[i] = fmt.Sprintf("spotify:track:%s", u)
|
||||||
|
}
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s/tracks?uris=%s",
|
||||||
|
c.baseURL, playlistID, strings.Join(trackURIs, ","))
|
||||||
|
req, err := http.NewRequest("PUT", spotifyURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.execute(req, nil, http.StatusCreated)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserFollowsPlaylist checks if one or more (up to 5) Spotify users are following
|
||||||
|
// a Spotify playlist, given the playlist's owner and ID.
|
||||||
|
//
|
||||||
|
// Checking if a user follows a playlist publicly doesn't require any scopes.
|
||||||
|
// Checking if the user is privately following a playlist is only possible for the
|
||||||
|
// current user when that user has granted access to the ScopePlaylistReadPrivate scope.
|
||||||
|
func (c *Client) UserFollowsPlaylist(playlistID ID, userIDs ...string) ([]bool, error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s/followers/contains?ids=%s",
|
||||||
|
c.baseURL, playlistID, strings.Join(userIDs, ","))
|
||||||
|
|
||||||
|
follows := make([]bool, len(userIDs))
|
||||||
|
|
||||||
|
err := c.get(spotifyURL, &follows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return follows, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlaylistReorderOptions is used with ReorderPlaylistTracks to reorder
|
||||||
|
// a track or group of tracks in a playlist.
|
||||||
|
//
|
||||||
|
// For example, in a playlist with 10 tracks, you can:
|
||||||
|
//
|
||||||
|
// - move the first track to the end of the playlist by setting
|
||||||
|
// RangeStart to 0 and InsertBefore to 10
|
||||||
|
// - move the last track to the beginning of the playlist by setting
|
||||||
|
// RangeStart to 9 and InsertBefore to 0
|
||||||
|
// - Move the last 2 tracks to the beginning of the playlist by setting
|
||||||
|
// RangeStart to 8 and RangeLength to 2.
|
||||||
|
type PlaylistReorderOptions struct {
|
||||||
|
// The position of the first track to be reordered.
|
||||||
|
// This field is required.
|
||||||
|
RangeStart int `json:"range_start"`
|
||||||
|
// The amount of tracks to be reordered. This field is optional. If
|
||||||
|
// you don't set it, the value 1 will be used.
|
||||||
|
RangeLength int `json:"range_length,omitempty"`
|
||||||
|
// The position where the tracks should be inserted. To reorder the
|
||||||
|
// tracks to the end of the playlist, simply set this to the position
|
||||||
|
// after the last track. This field is required.
|
||||||
|
InsertBefore int `json:"insert_before"`
|
||||||
|
// The playlist's snapshot ID against which you wish to make the changes.
|
||||||
|
// This field is optional.
|
||||||
|
SnapshotID string `json:"snapshot_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReorderPlaylistTracks reorders a track or group of tracks in a playlist. It
|
||||||
|
// returns a snapshot ID that can be used to identify the [newly modified] playlist
|
||||||
|
// version in future requests.
|
||||||
|
//
|
||||||
|
// See the docs for PlaylistReorderOptions for information on how the reordering
|
||||||
|
// works.
|
||||||
|
//
|
||||||
|
// Reordering tracks in the current user's public playlist requires ScopePlaylistModifyPublic.
|
||||||
|
// Reordering tracks in the user's private playlists (including collaborative playlists) requires
|
||||||
|
// ScopePlaylistModifyPrivate.
|
||||||
|
func (c *Client) ReorderPlaylistTracks(playlistID ID, opt PlaylistReorderOptions) (snapshotID string, err error) {
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s/tracks", c.baseURL, playlistID)
|
||||||
|
j, err := json.Marshal(opt)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("PUT", spotifyURL, bytes.NewReader(j))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
result := struct {
|
||||||
|
SnapshotID string `json:"snapshot_id"`
|
||||||
|
}{}
|
||||||
|
err = c.execute(req, &result)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.SnapshotID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPlaylistImage replaces the image used to represent a playlist.
|
||||||
|
// This action can only be performed by the owner of the playlist,
|
||||||
|
// and requires ScopeImageUpload as well as ScopeModifyPlaylist{Public|Private}..
|
||||||
|
func (c *Client) SetPlaylistImage(playlistID ID, img io.Reader) error {
|
||||||
|
spotifyURL := fmt.Sprintf("%splaylists/%s/images", c.baseURL, playlistID)
|
||||||
|
// data flow:
|
||||||
|
// img (reader) -> copy into base64 encoder (writer) -> pipe (write end)
|
||||||
|
// pipe (read end) -> request body
|
||||||
|
r, w := io.Pipe()
|
||||||
|
go func() {
|
||||||
|
enc := base64.NewEncoder(base64.StdEncoding, w)
|
||||||
|
_, err := io.Copy(enc, img)
|
||||||
|
enc.Close()
|
||||||
|
w.CloseWithError(err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
req, err := http.NewRequest("PUT", spotifyURL, r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "image/jpeg")
|
||||||
|
return c.execute(req, nil, http.StatusAccepted)
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user