ruby_vsts 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +3 -0
- data.tar.gz.sig +0 -0
- data/.codeclimate.yml +18 -0
- data/.gitignore +25 -0
- data/.rspec +1 -0
- data/.rubocop.yml +44 -0
- data/.yardopts +8 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +19 -0
- data/README.md +47 -0
- data/Rakefile +14 -0
- data/certs/ruby_vsts-gem-public_cert.pem +21 -0
- data/lib/ruby_vsts.rb +33 -0
- data/lib/vsts/api_client.rb +150 -0
- data/lib/vsts/api_response.rb +24 -0
- data/lib/vsts/base_model.rb +14 -0
- data/lib/vsts/change.rb +16 -0
- data/lib/vsts/changeset.rb +76 -0
- data/lib/vsts/configuration.rb +19 -0
- data/lib/vsts/identity.rb +16 -0
- data/lib/vsts/item.rb +34 -0
- data/lib/vsts/version.rb +3 -0
- data/ruby_vsts.gemspec +36 -0
- data/spec/fixtures/tfvc_changeset_by_id.json +36 -0
- data/spec/fixtures/tfvc_changeset_changes.json +13 -0
- data/spec/fixtures/tfvc_changesets_list.json +362 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/vsts/base_model_spec.rb +10 -0
- data/spec/vsts/change_spec.rb +25 -0
- data/spec/vsts/changeset_spec.rb +145 -0
- data/spec/vsts/configuration_spec.rb +43 -0
- data/spec/vsts/item_spec.rb +74 -0
- data/spec/vsts_spec.rb +15 -0
- metadata +253 -0
- metadata.gz.sig +1 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f231587e2fb121259d565337ac2563a0d903b383
|
4
|
+
data.tar.gz: 6767463306762c36b6989d39a6edc20e84d3db88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b5e22b6d5a3aa91e66fb8f752fc07beefa5dcc05653999586a9b878fbe79f1d0e16b8f9edbe2aacf76132ef52acbd759bc4efa6378c3076f7ed7aa5383817cb
|
7
|
+
data.tar.gz: f309cb3aa500a76dd3e16820a35cf5ef11d4cbd7ba83a73b59db3241a52d7d187461023722d86bde807671127b50e5969859798d66579e537c8d70f481e1567d
|
checksums.yaml.gz.sig
ADDED
data.tar.gz.sig
ADDED
Binary file
|
data/.codeclimate.yml
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Gem builds
|
2
|
+
pkg/
|
3
|
+
*.gem
|
4
|
+
|
5
|
+
# Bundler files
|
6
|
+
.bundle
|
7
|
+
Gemfile.lock
|
8
|
+
|
9
|
+
# Ignore Byebug command history file.
|
10
|
+
.byebug_history
|
11
|
+
|
12
|
+
# SimpleCov code coverage reports
|
13
|
+
/coverage
|
14
|
+
|
15
|
+
# CodeClimate repo token to report code coverage
|
16
|
+
# See https://codeclimate.com/repos/58ea190f4e4fc9029400296b/coverage_setup
|
17
|
+
.codeclimate_repo_token
|
18
|
+
|
19
|
+
# Yard documentation files
|
20
|
+
.yardoc/
|
21
|
+
doc/
|
22
|
+
|
23
|
+
# Temporary backups, unneeded files
|
24
|
+
*.old
|
25
|
+
*.orig
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
AllCops:
|
2
|
+
DisplayCopNames: true
|
3
|
+
|
4
|
+
Rails:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Style/StringLiterals:
|
8
|
+
Enabled: false
|
9
|
+
# EnforcedStyle: double_quotes # if enabled, this can be single_quotes or double_quotes
|
10
|
+
|
11
|
+
Style/SymbolArray:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Style/WordArray:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Style/RegexpLiteral:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Metrics/LineLength:
|
21
|
+
Max: 135
|
22
|
+
# To make it possible to copy or click on URIs in the code, we allow lines
|
23
|
+
# containing a URI to be longer than Max.
|
24
|
+
AllowHeredoc: true
|
25
|
+
AllowURI: true
|
26
|
+
URISchemes:
|
27
|
+
- http
|
28
|
+
- https
|
29
|
+
|
30
|
+
Metrics/MethodLength:
|
31
|
+
CountComments: false # count full line comments?
|
32
|
+
Max: 25
|
33
|
+
|
34
|
+
Metrics/AbcSize:
|
35
|
+
# The ABC size is a calculated magnitude, so this number can be a Fixnum or
|
36
|
+
# a Float.
|
37
|
+
Max: 40
|
38
|
+
|
39
|
+
Metrics/CyclomaticComplexity:
|
40
|
+
# even 15 may still be acceptable
|
41
|
+
Max: 10
|
42
|
+
|
43
|
+
Metrics/PerceivedComplexity:
|
44
|
+
Max: 10
|
data/.yardopts
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2017 Gabor Lengyel and Prodexity Ltd.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# ruby_vsts
|
2
|
+
An unofficial Microsoft Visual Studio Team Services (VSTS) API client in Ruby
|
3
|
+
|
4
|
+
[](https://codeclimate.com/github/prodexity/ruby_vsts)
|
5
|
+
[](https://codeclimate.com/github/prodexity/ruby_vsts)
|
6
|
+
[](https://codeclimate.com/github/prodexity/ruby_vsts/coverage)
|
7
|
+
|
8
|
+
## About
|
9
|
+
This will be a Ruby gem to connect to the Microsoft Visual Studio online (VSTS) Rest API.
|
10
|
+
It may also work with recent versions of TFS too. *Work is heavily in progress!*
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
### Setup
|
15
|
+
```ruby
|
16
|
+
require 'ruby_vsts'
|
17
|
+
|
18
|
+
VSTS.configure do |config|
|
19
|
+
config.personal_access_token = "YOUR_PERSONAL_ACCESS_TOKEN"
|
20
|
+
config.base_url = "https://YOUR_INSTANCE.visualstudio.com/"
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
### Finding changesets
|
25
|
+
```ruby
|
26
|
+
VSTS::Changeset.find(72300) # find changeset by id
|
27
|
+
VSTS::Changeset.find_all(author: "fabrikam13@hotmail.com") # find by author
|
28
|
+
VSTS::Changeset.find_all(fromId: 1000, toId: 1200) # find by id range
|
29
|
+
VSTS::Changeset.find_all(fromDate: "03-01-2017", toDate: "03-18-2017-2:00PM") # find by date range
|
30
|
+
VSTS::Changeset.find_all(itemPath: "$/Fabrikam-Fiber-TFVC/Program.cs") # find by item path
|
31
|
+
VSTS::Changeset.find_all(top: 20, skip: 100) # paging
|
32
|
+
# ...
|
33
|
+
```
|
34
|
+
|
35
|
+
### Getting changes in a changeset
|
36
|
+
```ruby
|
37
|
+
changeset = VSTS::Changeset.find(72300)
|
38
|
+
changes = changeset.changes
|
39
|
+
```
|
40
|
+
|
41
|
+
### Getting change items
|
42
|
+
```ruby
|
43
|
+
item = changes[0]
|
44
|
+
file_contents = item.get # current version
|
45
|
+
```
|
46
|
+
|
47
|
+
Please see specs and the source code for further examples.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:test)
|
5
|
+
|
6
|
+
task test_and_report: [:test, :report_coverage]
|
7
|
+
|
8
|
+
task :report_coverage do
|
9
|
+
ENV["CODECLIMATE_REPO_TOKEN"] = File.read(".codeclimate_repo_token") if File.exist?(".codeclimate_repo_token")
|
10
|
+
`codeclimate-test-reporter`
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Run tests and report coverage to CodeClimate"
|
14
|
+
task default: :test_and_report
|
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDhTCCAm2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMRIwEAYDVQQDDAlydWJ5
|
3
|
+
X3ZzdHMxGTAXBgoJkiaJk/IsZAEZFglwcm9kZXhpdHkxEzARBgoJkiaJk/IsZAEZ
|
4
|
+
FgNjb20wHhcNMTcwNDEyMDk1MzE1WhcNMTgwNDEyMDk1MzE1WjBEMRIwEAYDVQQD
|
5
|
+
DAlydWJ5X3ZzdHMxGTAXBgoJkiaJk/IsZAEZFglwcm9kZXhpdHkxEzARBgoJkiaJ
|
6
|
+
k/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCnth7a
|
7
|
+
Innh/5+zT5rdwHMySmQG2qyuNh5ammn4ZleFvkZxDPpFb5Kn+BeoR8O3OWEe5WEs
|
8
|
+
4FUR/43Ow1HzYMIJIIb6MxNZyZQj6Bm+cKZPctL/h0KjC7kG+2aRdUCsfFKoZvMZ
|
9
|
+
69yHxtArNtbt6dIRsic8CHioQe0i6/7BVD/1OKKt600dt1K1zf7j7T8xWIdCwbO8
|
10
|
+
zWE4GpEBnEA4mBPMKqAZmd+DsqrbCWPie8TdfGeWo71/7rUuCbAUpMq4Rh3SpmfV
|
11
|
+
t0OQMShhuAaLoRLuIZ48hiC3ELAr9ZCK8rn5Ci2trLEVjyOvbq/QnwnGspydlyaN
|
12
|
+
xzGpH5p82DwcUP5TAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAd
|
13
|
+
BgNVHQ4EFgQUYZTJdcOOpive/ZTgo5EYhS98qUUwIgYDVR0RBBswGYEXcnVieV92
|
14
|
+
c3RzQHByb2RleGl0eS5jb20wIgYDVR0SBBswGYEXcnVieV92c3RzQHByb2RleGl0
|
15
|
+
eS5jb20wDQYJKoZIhvcNAQEFBQADggEBAFiM7TEAsjlwjCyCMlzw0Yq/igWgaaFP
|
16
|
+
of+iPXZUC49YMTpXnQjNl9sE+cxHzkJzyM00YdeJ18DDtquIZ44Hdd30J9oleJ5g
|
17
|
+
DgGCX4bCKg5WTBwqvd0ivATn9uxDxLF1VP/cl1MJPXhW8+Bhq2FzbyWvQuxHeFsI
|
18
|
+
jJNJdpaL4UgxvhYECxAd1gzvIpRFbSqJJZVr8T4tYjfxyaGJxf9T5GbtYazYcRmP
|
19
|
+
Pfk9fa2jjnmyUPewuJZHmwArB9oRryAdwWtOsvVZHZ1ulcmW+Pbo2IiYQHvl1zQH
|
20
|
+
Z5Mw91gFnDov+9F9be4W5sZmbj640vetlJGLdMFheEZ2HSX+4fEZu1k=
|
21
|
+
-----END CERTIFICATE-----
|
data/lib/ruby_vsts.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'vsts/version'
|
2
|
+
require 'vsts/configuration'
|
3
|
+
require 'vsts/api_client'
|
4
|
+
require 'vsts/api_response'
|
5
|
+
require 'vsts/base_model'
|
6
|
+
require 'vsts/identity'
|
7
|
+
require 'vsts/item'
|
8
|
+
require 'vsts/change'
|
9
|
+
require 'vsts/changeset'
|
10
|
+
|
11
|
+
# Base namespace for ruby_vsts
|
12
|
+
module VSTS
|
13
|
+
class << self
|
14
|
+
attr_accessor :configuration
|
15
|
+
attr_accessor :logger
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.configuration
|
19
|
+
@configuration ||= Configuration.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.reset
|
23
|
+
@configuration = Configuration.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.configure
|
27
|
+
yield(configuration)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.logger
|
31
|
+
@logger ||= Logger.new(STDOUT)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
# VSTS namespace
|
5
|
+
module VSTS
|
6
|
+
# API client for Visual Studio Team Services (VSTS)
|
7
|
+
# Manages access tokens and API versions, builds proper requests as expected by the VSTS API
|
8
|
+
class APIClient
|
9
|
+
# Make an API request
|
10
|
+
#
|
11
|
+
# @param method [Symbol] the method to be used, can be :get, :put, :post, :delete or :head (will be passed to RestClient)
|
12
|
+
# @param resource [String] the resource to request under the base_url (ie. "/changesets")
|
13
|
+
# @param opts [Hash] options for the request
|
14
|
+
# @option opts [Hash] :payload payload for the request (if any)
|
15
|
+
# @option opts [String] :api_version
|
16
|
+
# @option opts [String] :collection
|
17
|
+
# @option opts [String] :team_project
|
18
|
+
# @option opts [String] :area
|
19
|
+
# @option opts [Hash] :urlparams
|
20
|
+
# @return [Hash] request results as parsed from json
|
21
|
+
def self.request(method, resource, opts = {})
|
22
|
+
url = build_url(resource, opts)
|
23
|
+
VSTS.logger.debug("VSTS request: #{method} #{url}") if VSTS.configuration.debug
|
24
|
+
req = {
|
25
|
+
method: method,
|
26
|
+
url: url,
|
27
|
+
payload: opts[:payload],
|
28
|
+
headers: {
|
29
|
+
Authorization: authz_header_value,
|
30
|
+
Accept: "application/json",
|
31
|
+
"Content-Type" => "application/json"
|
32
|
+
}
|
33
|
+
}
|
34
|
+
resp = RestClient::Request.execute(req)
|
35
|
+
APIResponse.new(req, resp)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Helper method for GET requests, calls #request
|
39
|
+
#
|
40
|
+
# @param resource [String] the resource to request under the base_url (ie. "/changesets")
|
41
|
+
# @param opts [Hash] query options, see #request
|
42
|
+
# @return [Hash] request results as parsed from json
|
43
|
+
def self.get(resource, opts = {})
|
44
|
+
request(:get, resource, opts)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Helper method for POST requests, calls #request
|
48
|
+
#
|
49
|
+
# @param resource [String] the resource to request under the base_url (ie. "/changesets")
|
50
|
+
# @param payload [Hash] payload to be sent with the request, takes precedence over opts[:payload]
|
51
|
+
# @param opts [Hash] query options, see #request
|
52
|
+
# @return [Hash] request results as parsed from json
|
53
|
+
def self.post(resource, payload, opts = {})
|
54
|
+
opts[:payload] = payload
|
55
|
+
request(:post, resource, opts)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Helper method for PUT requests, calls #request
|
59
|
+
#
|
60
|
+
# @param resource [String] the resource to request under the base_url (ie. "/changesets")
|
61
|
+
# @param payload [Hash] payload to be sent with the request, takes precedence over opts[:payload]
|
62
|
+
# @param opts [Hash] query options, see #request
|
63
|
+
# @return [Hash] request results as parsed from json
|
64
|
+
def self.put(resource, payload, opts = {})
|
65
|
+
opts[:payload] = payload
|
66
|
+
request(:put, resource, opts)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Helper method for PATCH requests, calls #request
|
70
|
+
#
|
71
|
+
# @param resource [String] the resource to request under the base_url (ie. "/changesets")
|
72
|
+
# @param payload [Hash] payload to be sent with the request, takes precedence over opts[:payload]
|
73
|
+
# @param opts [Hash] query options, see #request
|
74
|
+
# @return [Hash] request results as parsed from json
|
75
|
+
def self.patch(resource, payload, opts = {})
|
76
|
+
opts[:payload] = payload
|
77
|
+
request(:patch, resource, opts)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Helper method for DELETE requests, calls #request
|
81
|
+
#
|
82
|
+
# @param resource [String] the resource to request under the base_url (ie. "/changesets")
|
83
|
+
# @param opts [Hash] query options, see #request
|
84
|
+
# @return [Hash] request results as parsed from json
|
85
|
+
def self.delete(resource, opts = {})
|
86
|
+
request(:delete, resource, opts)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Private class methods
|
90
|
+
|
91
|
+
# Builds VSTS url as described in https://www.visualstudio.com/en-us/docs/integrate/get-started/rest/basics
|
92
|
+
#
|
93
|
+
# @param resource [String] the VSTS resource
|
94
|
+
# @param opts [Hash] options hash, see #request
|
95
|
+
# @return [String] the request URL
|
96
|
+
# @private
|
97
|
+
def self.build_url(resource, opts = {})
|
98
|
+
base_url = VSTS.configuration.base_url.sub(%r{\/+$}, "")
|
99
|
+
api_version = opts[:api_version] || VSTS.configuration.api_version
|
100
|
+
collection = opts[:collection] || VSTS.configuration.collection
|
101
|
+
team_project = opts[:team_project] || VSTS.configuration.team_project
|
102
|
+
urlparams = opts[:urlparams] || {}
|
103
|
+
area = opts[:area] || VSTS.configuration.area
|
104
|
+
resource.sub!(%r{^\/+}, "")
|
105
|
+
|
106
|
+
base = [base_url, collection, team_project, "_apis", area, resource].compact.join("/")
|
107
|
+
urlparams["api-version"] ||= api_version
|
108
|
+
url_encoded_params = URI.encode_www_form(urlparams) # makes url params from Hash
|
109
|
+
|
110
|
+
base + "?" + url_encoded_params
|
111
|
+
end
|
112
|
+
|
113
|
+
# Calculate the Authorization header for the API based on the personal access token
|
114
|
+
#
|
115
|
+
# @return [String] the Authorization header value for Basic auth, ie. "Basic jrigf9404vvxsoi48t048fdj=="
|
116
|
+
# @private
|
117
|
+
def self.authz_header_value
|
118
|
+
"Basic " + Base64.strict_encode64(":" + VSTS.configuration.personal_access_token)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Build URL parameters hash from options hash (used internally)
|
122
|
+
#
|
123
|
+
# @param opts [Hash] options hash with Symbol keys to build url parameters from
|
124
|
+
# @param paramnames [Array<String>, Array<Symbol>, Array<Array<String, String>>, Array<Hash>]
|
125
|
+
# list of VSTS URL parameter names and VSTS prefixes to filter from opts
|
126
|
+
# @return [Hash] url parameters hash
|
127
|
+
# @private
|
128
|
+
def self.build_params(opts, paramnames)
|
129
|
+
urlparams = {}
|
130
|
+
paramnames.each do |paramname_with_prefix|
|
131
|
+
case paramname_with_prefix
|
132
|
+
when String, Symbol
|
133
|
+
prefix = ""
|
134
|
+
paramname = paramname_with_prefix
|
135
|
+
when Array
|
136
|
+
prefix = paramname_with_prefix[0]
|
137
|
+
paramname = paramname_with_prefix[1]
|
138
|
+
when Hash
|
139
|
+
prefix = paramname_with_prefix.first[0]
|
140
|
+
paramname = paramname_with_prefix.first[1]
|
141
|
+
else
|
142
|
+
VSTS.logger.warn("Invalid type in paramlist in APIClient##build_params: #{paramname_with_prefix.class}")
|
143
|
+
next
|
144
|
+
end
|
145
|
+
urlparams["#{prefix}#{paramname}"] = opts[paramname] if opts[paramname]
|
146
|
+
end
|
147
|
+
urlparams
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
# VSTS namespace
|
4
|
+
module VSTS
|
5
|
+
# VSTS API response
|
6
|
+
class APIResponse
|
7
|
+
attr_accessor :request, :code, :body, :parsed
|
8
|
+
|
9
|
+
# Constructor
|
10
|
+
#
|
11
|
+
# @param request [Hash] the hash that was passed to RestClient as the request descriptor
|
12
|
+
# @param response [RestClient::Response]
|
13
|
+
def initialize(request, response)
|
14
|
+
@request = request
|
15
|
+
@code = response.code
|
16
|
+
@body = response.body
|
17
|
+
begin
|
18
|
+
@parsed = JSON.parse(@body)
|
19
|
+
rescue JSON::ParserError
|
20
|
+
@parsed = nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|