From 2f67f5f70680c162108f370f5911b65370dd76fd Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Wed, 12 Apr 2017 13:04:39 +0200 Subject: [PATCH 1/2] compare server and agent version for compatibility --- drone/agent/agent.go | 2 +- drone/main.go | 2 +- plugins/internal/http.go | 27 ++++++++++++++++++++++++--- plugins/sender/plugin.go | 5 ++--- router/middleware/header/header.go | 2 +- router/middleware/version.go | 2 +- server/pages.go | 4 ++++ server/rpc.go | 14 ++++++++++++++ server/template/files/error.html | 17 +++++++++++++++++ version/version.go | 18 +++++++++++------- 10 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 server/template/files/error.html diff --git a/drone/agent/agent.go b/drone/agent/agent.go index 4d1342220..33493b6eb 100644 --- a/drone/agent/agent.go +++ b/drone/agent/agent.go @@ -101,7 +101,7 @@ func loop(c *cli.Context) error { ), rpc.WithHeader( "X-Drone-Version", - version.Version, + version.Version.String(), ), ) if err != nil { diff --git a/drone/main.go b/drone/main.go index 27c9d74b2..a39074ce9 100644 --- a/drone/main.go +++ b/drone/main.go @@ -17,7 +17,7 @@ func main() { app := cli.NewApp() app.Name = "drone" - app.Version = version.Version + app.Version = version.Version.String() app.Usage = "command line utility" app.Flags = []cli.Flag{ cli.StringFlag{ diff --git a/plugins/internal/http.go b/plugins/internal/http.go index 2ae958d14..938bf3116 100644 --- a/plugins/internal/http.go +++ b/plugins/internal/http.go @@ -3,7 +3,6 @@ package internal import ( "bytes" "encoding/json" - "errors" "io" "io/ioutil" "net/http" @@ -47,8 +46,14 @@ func Send(method, path string, in, out interface{}) error { // if an error is encountered, parse and return the // error response. if resp.StatusCode > http.StatusPartialContent { - out, _ := ioutil.ReadAll(resp.Body) - return errors.New(string(out)) + out, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + return &Error{ + code: resp.StatusCode, + text: string(out), + } } // if a json response is expected, parse and return @@ -59,3 +64,19 @@ func Send(method, path string, in, out interface{}) error { return nil } + +// Error represents a http error. +type Error struct { + code int + text string +} + +// Code returns the http error code. +func (e *Error) Code() int { + return e.code +} + +// Error returns the error message in string format. +func (e *Error) Error() string { + return e.text +} diff --git a/plugins/sender/plugin.go b/plugins/sender/plugin.go index 446ea9bc3..38d1e3ba0 100644 --- a/plugins/sender/plugin.go +++ b/plugins/sender/plugin.go @@ -18,12 +18,11 @@ func NewRemote(endpoint string) model.SenderService { func (p *plugin) SenderAllowed(user *model.User, repo *model.Repo, build *model.Build) (bool, error) { path := fmt.Sprintf("%s/sender/%s/%s/%s", p.endpoint, repo.Owner, repo.Name, build.Sender) - out := new(model.Sender) - err := internal.Send("POST", path, build, out) + err := internal.Send("POST", path, build, nil) if err != nil { return false, err } - return out.Allow, nil + return true, err } func (p *plugin) SenderCreate(repo *model.Repo, sender *model.Sender) error { diff --git a/router/middleware/header/header.go b/router/middleware/header/header.go index d259431c7..7b82154ab 100644 --- a/router/middleware/header/header.go +++ b/router/middleware/header/header.go @@ -52,6 +52,6 @@ func Secure(c *gin.Context) { // version information to the HTTP response. This is intended // for debugging and troubleshooting. func Version(c *gin.Context) { - c.Header("X-DRONE-VERSION", version.Version) + c.Header("X-DRONE-VERSION", version.Version.String()) c.Next() } diff --git a/router/middleware/version.go b/router/middleware/version.go index 20466d8ec..87170010a 100644 --- a/router/middleware/version.go +++ b/router/middleware/version.go @@ -8,5 +8,5 @@ import ( // Version is a middleware function that appends the Drone version information // to the HTTP response. This is intended for debugging and troubleshooting. func Version(c *gin.Context) { - c.Header("X-DRONE-VERSION", version.Version) + c.Header("X-DRONE-VERSION", version.Version.String()) } diff --git a/server/pages.go b/server/pages.go index 74a73c206..e301fa47d 100644 --- a/server/pages.go +++ b/server/pages.go @@ -28,6 +28,10 @@ func ShowIndex(c *gin.Context) { // ShowLogin is a legacy endpoint that now redirects to // initiliaze the oauth flow func ShowLogin(c *gin.Context) { + if err := c.Query("error"); err != "" { + c.HTML(500, "error.html", gin.H{"error": err}) + return + } c.Redirect(303, "/authorize") } diff --git a/server/rpc.go b/server/rpc.go index ff1896f34..de0d8932a 100644 --- a/server/rpc.go +++ b/server/rpc.go @@ -7,15 +7,18 @@ import ( "log" "strconv" + "github.com/Sirupsen/logrus" "github.com/cncd/logging" "github.com/cncd/pipeline/pipeline/rpc" "github.com/cncd/pubsub" "github.com/cncd/queue" + "github.com/coreos/go-semver/semver" "github.com/gin-gonic/gin" "github.com/drone/drone/model" "github.com/drone/drone/remote" "github.com/drone/drone/store" + "github.com/drone/drone/version" ) // This file is a complete disaster because I'm trying to wedge in some @@ -86,6 +89,17 @@ func RPCHandler(c *gin.Context) { c.String(401, "Unable to connect agent. Invalid authorization token") return } + + agent := semver.New( + c.Request.Header.Get("X-Drone-Version"), + ) + logrus.Debugf("agent connected: ip address %s: version %s", c.ClientIP(), agent) + if agent.LessThan(version.Version) { + logrus.Warnf("Version mismatch. Agent version %s < Server version %s", agent, version.Version) + c.String(409, "Version mismatch. Agent version %s < Server version %s", agent, version.Version) + return + } + peer := RPC{ remote: remote.FromContext(c), store: store.FromContext(c), diff --git a/server/template/files/error.html b/server/template/files/error.html new file mode 100644 index 000000000..018c45c8f --- /dev/null +++ b/server/template/files/error.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + error | drone + + + {{ .error }} + + diff --git a/version/version.go b/version/version.go index 329bfbd0a..36758ec04 100644 --- a/version/version.go +++ b/version/version.go @@ -1,19 +1,23 @@ package version -import "fmt" +import "github.com/coreos/go-semver/semver" var ( // VersionMajor is for an API incompatible changes - VersionMajor = 0 + VersionMajor int64 = 0 // VersionMinor is for functionality in a backwards-compatible manner - VersionMinor = 6 + VersionMinor int64 = 6 // VersionPatch is for backwards-compatible bug fixes - VersionPatch = 0 + VersionPatch int64 = 0 // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "dev" + VersionDev string ) // Version is the specification version that the package types support. -var Version = fmt.Sprintf("%d.%d.%d+%s", - VersionMajor, VersionMinor, VersionPatch, VersionDev) +var Version = semver.Version{ + Major: VersionMajor, + Minor: VersionMinor, + Patch: VersionPatch, + Metadata: VersionDev, +} From 1d46344bf6e98d5b3281ab3659f918b17f3000e9 Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Wed, 12 Apr 2017 13:14:43 +0200 Subject: [PATCH 2/2] missing semver vendor --- vendor/github.com/coreos/go-semver/LICENSE | 202 +++++++++++++ .../coreos/go-semver/semver/semver.go | 275 ++++++++++++++++++ .../coreos/go-semver/semver/sort.go | 38 +++ vendor/vendor.json | 6 + 4 files changed, 521 insertions(+) create mode 100644 vendor/github.com/coreos/go-semver/LICENSE create mode 100644 vendor/github.com/coreos/go-semver/semver/semver.go create mode 100644 vendor/github.com/coreos/go-semver/semver/sort.go diff --git a/vendor/github.com/coreos/go-semver/LICENSE b/vendor/github.com/coreos/go-semver/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/coreos/go-semver/LICENSE @@ -0,0 +1,202 @@ + + 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. diff --git a/vendor/github.com/coreos/go-semver/semver/semver.go b/vendor/github.com/coreos/go-semver/semver/semver.go new file mode 100644 index 000000000..9c8072d1a --- /dev/null +++ b/vendor/github.com/coreos/go-semver/semver/semver.go @@ -0,0 +1,275 @@ +// Copyright 2013-2015 CoreOS, Inc. +// +// 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. + +// Semantic Versions http://semver.org +package semver + +import ( + "bytes" + "errors" + "fmt" + "strconv" + "strings" +) + +type Version struct { + Major int64 + Minor int64 + Patch int64 + PreRelease PreRelease + Metadata string +} + +type PreRelease string + +func splitOff(input *string, delim string) (val string) { + parts := strings.SplitN(*input, delim, 2) + + if len(parts) == 2 { + *input = parts[0] + val = parts[1] + } + + return val +} + +func New(version string) *Version { + return Must(NewVersion(version)) +} + +func NewVersion(version string) (*Version, error) { + v := Version{} + + if err := v.Set(version); err != nil { + return nil, err + } + + return &v, nil +} + +// Must is a helper for wrapping NewVersion and will panic if err is not nil. +func Must(v *Version, err error) *Version { + if err != nil { + panic(err) + } + return v +} + +// Set parses and updates v from the given version string. Implements flag.Value +func (v *Version) Set(version string) error { + metadata := splitOff(&version, "+") + preRelease := PreRelease(splitOff(&version, "-")) + dotParts := strings.SplitN(version, ".", 3) + + if len(dotParts) != 3 { + return fmt.Errorf("%s is not in dotted-tri format", version) + } + + parsed := make([]int64, 3, 3) + + for i, v := range dotParts[:3] { + val, err := strconv.ParseInt(v, 10, 64) + parsed[i] = val + if err != nil { + return err + } + } + + v.Metadata = metadata + v.PreRelease = preRelease + v.Major = parsed[0] + v.Minor = parsed[1] + v.Patch = parsed[2] + return nil +} + +func (v Version) String() string { + var buffer bytes.Buffer + + fmt.Fprintf(&buffer, "%d.%d.%d", v.Major, v.Minor, v.Patch) + + if v.PreRelease != "" { + fmt.Fprintf(&buffer, "-%s", v.PreRelease) + } + + if v.Metadata != "" { + fmt.Fprintf(&buffer, "+%s", v.Metadata) + } + + return buffer.String() +} + +func (v *Version) UnmarshalYAML(unmarshal func(interface{}) error) error { + var data string + if err := unmarshal(&data); err != nil { + return err + } + return v.Set(data) +} + +func (v Version) MarshalJSON() ([]byte, error) { + return []byte(`"` + v.String() + `"`), nil +} + +func (v *Version) UnmarshalJSON(data []byte) error { + l := len(data) + if l == 0 || string(data) == `""` { + return nil + } + if l < 2 || data[0] != '"' || data[l-1] != '"' { + return errors.New("invalid semver string") + } + return v.Set(string(data[1 : l-1])) +} + +// Compare tests if v is less than, equal to, or greater than versionB, +// returning -1, 0, or +1 respectively. +func (v Version) Compare(versionB Version) int { + if cmp := recursiveCompare(v.Slice(), versionB.Slice()); cmp != 0 { + return cmp + } + return preReleaseCompare(v, versionB) +} + +// Equal tests if v is equal to versionB. +func (v Version) Equal(versionB Version) bool { + return v.Compare(versionB) == 0 +} + +// LessThan tests if v is less than versionB. +func (v Version) LessThan(versionB Version) bool { + return v.Compare(versionB) < 0 +} + +// Slice converts the comparable parts of the semver into a slice of integers. +func (v Version) Slice() []int64 { + return []int64{v.Major, v.Minor, v.Patch} +} + +func (p PreRelease) Slice() []string { + preRelease := string(p) + return strings.Split(preRelease, ".") +} + +func preReleaseCompare(versionA Version, versionB Version) int { + a := versionA.PreRelease + b := versionB.PreRelease + + /* Handle the case where if two versions are otherwise equal it is the + * one without a PreRelease that is greater */ + if len(a) == 0 && (len(b) > 0) { + return 1 + } else if len(b) == 0 && (len(a) > 0) { + return -1 + } + + // If there is a prerelease, check and compare each part. + return recursivePreReleaseCompare(a.Slice(), b.Slice()) +} + +func recursiveCompare(versionA []int64, versionB []int64) int { + if len(versionA) == 0 { + return 0 + } + + a := versionA[0] + b := versionB[0] + + if a > b { + return 1 + } else if a < b { + return -1 + } + + return recursiveCompare(versionA[1:], versionB[1:]) +} + +func recursivePreReleaseCompare(versionA []string, versionB []string) int { + // A larger set of pre-release fields has a higher precedence than a smaller set, + // if all of the preceding identifiers are equal. + if len(versionA) == 0 { + if len(versionB) > 0 { + return -1 + } + return 0 + } else if len(versionB) == 0 { + // We're longer than versionB so return 1. + return 1 + } + + a := versionA[0] + b := versionB[0] + + aInt := false + bInt := false + + aI, err := strconv.Atoi(versionA[0]) + if err == nil { + aInt = true + } + + bI, err := strconv.Atoi(versionB[0]) + if err == nil { + bInt = true + } + + // Numeric identifiers always have lower precedence than non-numeric identifiers. + if aInt && !bInt { + return -1 + } else if !aInt && bInt { + return 1 + } + + // Handle Integer Comparison + if aInt && bInt { + if aI > bI { + return 1 + } else if aI < bI { + return -1 + } + } + + // Handle String Comparison + if a > b { + return 1 + } else if a < b { + return -1 + } + + return recursivePreReleaseCompare(versionA[1:], versionB[1:]) +} + +// BumpMajor increments the Major field by 1 and resets all other fields to their default values +func (v *Version) BumpMajor() { + v.Major += 1 + v.Minor = 0 + v.Patch = 0 + v.PreRelease = PreRelease("") + v.Metadata = "" +} + +// BumpMinor increments the Minor field by 1 and resets all other fields to their default values +func (v *Version) BumpMinor() { + v.Minor += 1 + v.Patch = 0 + v.PreRelease = PreRelease("") + v.Metadata = "" +} + +// BumpPatch increments the Patch field by 1 and resets all other fields to their default values +func (v *Version) BumpPatch() { + v.Patch += 1 + v.PreRelease = PreRelease("") + v.Metadata = "" +} diff --git a/vendor/github.com/coreos/go-semver/semver/sort.go b/vendor/github.com/coreos/go-semver/semver/sort.go new file mode 100644 index 000000000..e256b41a5 --- /dev/null +++ b/vendor/github.com/coreos/go-semver/semver/sort.go @@ -0,0 +1,38 @@ +// Copyright 2013-2015 CoreOS, Inc. +// +// 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 semver + +import ( + "sort" +) + +type Versions []*Version + +func (s Versions) Len() int { + return len(s) +} + +func (s Versions) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Versions) Less(i, j int) bool { + return s[i].LessThan(*s[j]) +} + +// Sort sorts the given slice of Version +func Sort(versions []*Version) { + sort.Sort(Versions(versions)) +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 2c7a8727a..0618618a8 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -103,6 +103,12 @@ "revision": "63b1974bbcc9b4b251ed18f88edc3a643eb64ff7", "revisionTime": "2017-04-06T02:25:48Z" }, + { + "checksumSHA1": "nux9tCYmTA5bOCVODF3Rqzcu60U=", + "path": "github.com/coreos/go-semver/semver", + "revision": "5e3acbb5668c4c3deb4842615c4098eb61fb6b1e", + "revisionTime": "2017-02-09T20:17:57Z" + }, { "origin": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew", "path": "github.com/davecgh/go-spew/spew",