ruby_vsts 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3 @@
1
+ 3��Y���J��\�q'�HnB"0)�� yU.��8 j�%�KX{�w7��_�ыa��0&ޏoV�-Џp���e6PC�p�!Z��P9��P�O�d���"M�R좕�ov��V�cz�ř�.��ag�y�<� ���}n���)�Gmg�z��n�.�)x��ZC�I1��
2
+ h+cX}��\��}�
3
+ ?@�����N�"<ǭ�brԔo�Q���V9�r��,%�Xv �&�u����ܟ>_S��1E���H�g�l"˕b_'-
data.tar.gz.sig ADDED
Binary file
data/.codeclimate.yml ADDED
@@ -0,0 +1,18 @@
1
+ engines:
2
+ duplication:
3
+ enabled: true
4
+ config:
5
+ languages:
6
+ - ruby
7
+ fixme:
8
+ enabled: true
9
+ rubocop:
10
+ enabled: true
11
+ ratings:
12
+ paths:
13
+ - lib/**
14
+ - "**.rb"
15
+
16
+ exclude_paths:
17
+ - spec/**/*
18
+ - vendor/**/*
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
@@ -0,0 +1,8 @@
1
+ --charset UTF-8
2
+ --main README.md
3
+ --title 'Ruby VSTS Documentation'
4
+ --no-private
5
+ --markup=markdown
6
+ -
7
+ LICENSE.txt
8
+ README.md
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
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
+ [![Code Climate](https://codeclimate.com/github/prodexity/ruby_vsts.png)](https://codeclimate.com/github/prodexity/ruby_vsts)
5
+ [![Issue Count](https://codeclimate.com/github/prodexity/ruby_vsts/badges/issue_count.svg)](https://codeclimate.com/github/prodexity/ruby_vsts)
6
+ [![Test Coverage](https://codeclimate.com/github/prodexity/ruby_vsts/badges/coverage.svg)](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