freshsales 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b588a2ecb49dd8ab5de0d2c2e43d3f45ca6048e9
4
- data.tar.gz: 531664c1425cfc9b14ea3eaaafb0a7b0ed1ceba3
3
+ metadata.gz: 15cc945c608ab34a89ba51dc2297260e3059c448
4
+ data.tar.gz: 2a0c39b54b2da29038e3f290cf3021d8ad21b013
5
5
  SHA512:
6
- metadata.gz: db59e03d374712a35b2fdf5d539c887864b326029c4930527d4cc03ea7e49dda72411084eb38615ffe2a58c1e6b191188bb0111c25c064735a5aea756b333313
7
- data.tar.gz: db23ff551d53a5c1d74d19da05d97cb3ca4590881f79a5cb1019e68b6a27a8ab650dd8e7a6a3082ebd63a0116bdeb1d5bb4ca75b2f8d8fb628b4622a9d993162
6
+ metadata.gz: 37988f797ec440b64d5bd88fa8fa22bccc49d7fc590710ac72836ae62c9362a036c77ca3993d16ed6fd88ee903b9d743b087796d164ef9ea125bd645bcaa961f
7
+ data.tar.gz: e124629869c83af354ccaebef63684b3e7ec052c5cf4f8e595f7e456b47af4c13680712dba9d59d2ff339f6c4268e422eeda564d2d9260edab774838fa3aab96
data/.circleci/config.yml CHANGED
@@ -7,7 +7,7 @@ jobs:
7
7
  build:
8
8
  docker:
9
9
  # specify the version you desire here
10
- - image: circleci/ruby:2.4.1-node-browsers
10
+ - image: cimg/ruby:2.5-browsers
11
11
 
12
12
  # Specify service dependencies here if necessary
13
13
  # CircleCI maintains a library of pre-built images
@@ -51,4 +51,4 @@ jobs:
51
51
  path: /tmp/rspec/
52
52
  - store_artifacts:
53
53
  path: /tmp/rspec/
54
- destination: test-results
54
+ destination: test-results
@@ -0,0 +1,2 @@
1
+ future-release=v0.0.6
2
+ exclude-labels=nochangelog,question
data/.rubocop.yml CHANGED
@@ -5,9 +5,10 @@
5
5
  #
6
6
  # File.chmod(0o777, f)
7
7
  #
8
- #AllCops:
8
+ AllCops:
9
9
  #Include:
10
10
  # - '**/fastlane/Fastfile'
11
+ TargetRubyVersion: 2.4
11
12
 
12
13
  # broken in 0.52.1
13
14
  Layout/EmptyLinesAroundArguments:
@@ -55,4 +56,4 @@ Layout/EndOfLine:
55
56
 
56
57
  # Some issues with rspec style
57
58
  Lint/AmbiguousBlockAssociation:
58
- Enabled: false
59
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # Change Log
2
+
3
+ ## [v0.0.4](https://github.com/DragonBox/freshsales/tree/v0.0.4) (2018-04-11)
4
+ [Full Changelog](https://github.com/DragonBox/freshsales/compare/v0.0.3...v0.0.4)
5
+
6
+ **Closed issues:**
7
+
8
+ - Relax dependencies [\#5](https://github.com/DragonBox/freshsales/issues/5)
9
+
10
+ ## [v0.0.3](https://github.com/DragonBox/freshsales/tree/v0.0.3) (2018-04-10)
11
+ [Full Changelog](https://github.com/DragonBox/freshsales/compare/v0.0.2...v0.0.3)
12
+
13
+ ## [v0.0.2](https://github.com/DragonBox/freshsales/tree/v0.0.2) (2018-04-10)
14
+ [Full Changelog](https://github.com/DragonBox/freshsales/compare/v0.0.1...v0.0.2)
15
+
16
+ **Implemented enhancements:**
17
+
18
+ - add more configuration options [\#4](https://github.com/DragonBox/freshsales/issues/4)
19
+ - handle errors \(Faraday::Error::ClientError\) [\#3](https://github.com/DragonBox/freshsales/issues/3)
20
+ - Clean pagination API [\#2](https://github.com/DragonBox/freshsales/issues/2)
21
+
22
+ ## [v0.0.1](https://github.com/DragonBox/freshsales/tree/v0.0.1) (2018-04-07)
23
+
24
+
25
+ \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
data/Gemfile.lock CHANGED
@@ -1,80 +1,95 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- freshsales (0.0.1)
5
- faraday (~> 0.9.1)
6
- multi_json (~> 1.11.0)
4
+ freshsales (0.0.6)
5
+ faraday (>= 0.16.0)
6
+ multi_json (>= 1.11.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activesupport (5.1.6)
11
+ activesupport (5.2.5)
12
12
  concurrent-ruby (~> 1.0, >= 1.0.2)
13
13
  i18n (>= 0.7, < 2)
14
14
  minitest (~> 5.1)
15
15
  tzinfo (~> 1.1)
16
- addressable (2.5.2)
17
- public_suffix (>= 2.0.2, < 4.0)
18
- ast (2.4.0)
19
- builder (3.2.3)
20
- byebug (10.0.2)
21
- coderay (1.1.2)
22
- concurrent-ruby (1.0.5)
23
- coveralls (0.8.21)
16
+ addressable (2.7.0)
17
+ public_suffix (>= 2.0.2, < 5.0)
18
+ ast (2.4.2)
19
+ builder (3.2.4)
20
+ byebug (11.1.3)
21
+ coderay (1.1.3)
22
+ colored (1.2)
23
+ concurrent-ruby (1.1.8)
24
+ coveralls (0.8.23)
24
25
  json (>= 1.8, < 3)
25
- simplecov (~> 0.14.1)
26
+ simplecov (~> 0.16.1)
26
27
  term-ansicolor (~> 1.3)
27
- thor (~> 0.19.4)
28
+ thor (>= 0.19.4, < 2.0)
28
29
  tins (~> 1.6)
29
- diff-lcs (1.3)
30
- docile (1.1.5)
31
- faraday (0.9.2)
30
+ crack (0.4.5)
31
+ rexml
32
+ diff-lcs (1.4.4)
33
+ docile (1.3.5)
34
+ faraday (1.4.1)
35
+ faraday-excon (~> 1.1)
36
+ faraday-net_http (~> 1.0)
37
+ faraday-net_http_persistent (~> 1.1)
32
38
  multipart-post (>= 1.2, < 3)
33
- faraday-http-cache (2.0.0)
34
- faraday (~> 0.8)
35
- github_changelog_generator (1.14.3)
39
+ ruby2_keywords (>= 0.0.4)
40
+ faraday-excon (1.1.0)
41
+ faraday-http-cache (2.2.0)
42
+ faraday (>= 0.8)
43
+ faraday-net_http (1.0.1)
44
+ faraday-net_http_persistent (1.1.0)
45
+ github_changelog_generator (1.15.2)
36
46
  activesupport
37
47
  faraday-http-cache
38
48
  multi_json
39
49
  octokit (~> 4.6)
40
- rainbow (>= 2.1)
50
+ rainbow (>= 2.2.1)
41
51
  rake (>= 10.0)
42
- retriable (~> 2.1)
43
- i18n (1.0.0)
52
+ retriable (~> 3.0)
53
+ hashdiff (1.0.1)
54
+ highline (1.7.10)
55
+ i18n (1.8.10)
44
56
  concurrent-ruby (~> 1.0)
45
- json (2.1.0)
46
- method_source (0.9.0)
47
- minitest (5.11.3)
48
- multi_json (1.11.3)
49
- multipart-post (2.0.0)
50
- octokit (4.8.0)
57
+ json (2.5.1)
58
+ method_source (1.0.0)
59
+ minitest (5.14.4)
60
+ multi_json (1.15.0)
61
+ multipart-post (2.1.1)
62
+ octokit (4.20.0)
63
+ faraday (>= 0.9)
51
64
  sawyer (~> 0.8.0, >= 0.5.3)
52
- parallel (1.12.1)
53
- parser (2.5.0.5)
54
- ast (~> 2.4.0)
55
- powerpack (0.1.1)
56
- pry (0.11.3)
57
- coderay (~> 1.1.0)
58
- method_source (~> 0.9.0)
59
- pry-byebug (3.6.0)
60
- byebug (~> 10.0)
61
- pry (~> 0.10)
62
- public_suffix (3.0.2)
65
+ parallel (1.20.1)
66
+ parser (2.7.2.0)
67
+ ast (~> 2.4.1)
68
+ powerpack (0.1.3)
69
+ pry (0.13.1)
70
+ coderay (~> 1.1)
71
+ method_source (~> 1.0)
72
+ pry-byebug (3.9.0)
73
+ byebug (~> 11.0)
74
+ pry (~> 0.13.0)
75
+ public_suffix (4.0.6)
63
76
  rainbow (3.0.0)
64
- rake (10.5.0)
65
- retriable (2.1.0)
66
- rspec (3.1.0)
67
- rspec-core (~> 3.1.0)
68
- rspec-expectations (~> 3.1.0)
69
- rspec-mocks (~> 3.1.0)
70
- rspec-core (3.1.7)
71
- rspec-support (~> 3.1.0)
72
- rspec-expectations (3.1.2)
77
+ rake (13.0.3)
78
+ retriable (3.1.2)
79
+ rexml (3.2.5)
80
+ rspec (3.8.0)
81
+ rspec-core (~> 3.8.0)
82
+ rspec-expectations (~> 3.8.0)
83
+ rspec-mocks (~> 3.8.0)
84
+ rspec-core (3.8.2)
85
+ rspec-support (~> 3.8.0)
86
+ rspec-expectations (3.8.6)
73
87
  diff-lcs (>= 1.2.0, < 2.0)
74
- rspec-support (~> 3.1.0)
75
- rspec-mocks (3.1.3)
76
- rspec-support (~> 3.1.0)
77
- rspec-support (3.1.2)
88
+ rspec-support (~> 3.8.0)
89
+ rspec-mocks (3.8.2)
90
+ diff-lcs (>= 1.2.0, < 2.0)
91
+ rspec-support (~> 3.8.0)
92
+ rspec-support (3.8.3)
78
93
  rspec_junit_formatter (0.2.3)
79
94
  builder (< 4)
80
95
  rspec-core (>= 2, < 4, != 2.12.0)
@@ -85,37 +100,47 @@ GEM
85
100
  rainbow (>= 2.2.2, < 4.0)
86
101
  ruby-progressbar (~> 1.7)
87
102
  unicode-display_width (~> 1.0, >= 1.0.1)
88
- ruby-progressbar (1.9.0)
89
- sawyer (0.8.1)
90
- addressable (>= 2.3.5, < 2.6)
91
- faraday (~> 0.8, < 1.0)
92
- simplecov (0.14.1)
93
- docile (~> 1.1.0)
103
+ ruby-progressbar (1.11.0)
104
+ ruby2_keywords (0.0.4)
105
+ sawyer (0.8.2)
106
+ addressable (>= 2.3.5)
107
+ faraday (> 0.8, < 2.0)
108
+ simplecov (0.16.1)
109
+ docile (~> 1.1)
94
110
  json (>= 1.8, < 3)
95
111
  simplecov-html (~> 0.10.0)
96
112
  simplecov-html (0.10.2)
97
- term-ansicolor (1.6.0)
113
+ sync (0.5.0)
114
+ term-ansicolor (1.7.1)
98
115
  tins (~> 1.0)
99
- thor (0.19.4)
116
+ thor (1.1.0)
100
117
  thread_safe (0.3.6)
101
- tins (1.16.3)
102
- tzinfo (1.2.5)
118
+ tins (1.28.0)
119
+ sync
120
+ tzinfo (1.2.9)
103
121
  thread_safe (~> 0.1)
104
- unicode-display_width (1.3.0)
122
+ unicode-display_width (1.7.0)
123
+ webmock (3.3.0)
124
+ addressable (>= 2.3.6)
125
+ crack (>= 0.3.2)
126
+ hashdiff
105
127
 
106
128
  PLATFORMS
107
129
  ruby
108
130
 
109
131
  DEPENDENCIES
110
- bundler (~> 1.13)
132
+ bundler (~> 2.2)
133
+ colored (>= 1.2, < 2.0.0)
111
134
  coveralls
112
135
  freshsales!
113
136
  github_changelog_generator
137
+ highline (~> 1.7.10)
114
138
  pry-byebug
115
- rake (~> 10.0)
116
- rspec (~> 3.1.0)
139
+ rake (>= 12.3.3)
140
+ rspec (~> 3.8.0)
117
141
  rspec_junit_formatter (~> 0.2.3)
118
142
  rubocop (~> 0.52.1)
143
+ webmock (~> 3.3.0)
119
144
 
120
145
  BUNDLED WITH
121
- 1.16.1
146
+ 2.2.16
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # U3D
1
+ # Freshsales
2
2
 
3
3
  [![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/DragonBox/freshsales/blob/master/LICENSE)
4
- [![Gem](https://img.shields.io/gem/v/u3d.svg?style=flat)](https://rubygems.org/gems/freshsales)
4
+ [![Gem](https://img.shields.io/gem/v/freshsales.svg?style=flat)](https://rubygems.org/gems/freshsales)
5
5
  [![Build Status](https://img.shields.io/circleci/project/DragonBox/freshsales/master.svg?style=flat)](https://circleci.com/gh/DragonBox/freshsales)
6
6
  [![Coverage Status](https://coveralls.io/repos/github/DragonBox/freshsales/badge.svg?branch=master)](https://coveralls.io/github/DragonBox/freshsales?branch=master)
7
7
 
8
- Freshsales is a ruby wrapper around Freshsales API.
8
+ Freshsales is a ruby wrapper around [Freshsales API](https://www.freshsales.io/api/)
9
9
 
10
10
  ---
11
11
 
@@ -15,46 +15,103 @@ Freshsales is a ruby wrapper around Freshsales API.
15
15
  gem install freshsales
16
16
  ```
17
17
 
18
+ ### Requirements
19
+
20
+ A Freshsales account and an API key. You can set your API key here.
21
+
22
+ https://yourdomain.freshsales.io/personal-settings/api-settings
23
+
18
24
  ## Getting started
19
25
 
20
26
  ```ruby
21
- config = {}
22
- config[:freshsales_token] = "...."
23
- config[:freshsales_domain] = "yourdomain" # from https://yourdomain.freshsales.io/
24
- Freshsales::API.new(config)
27
+ # given https://yourdomain.freshsales.io/ and your API key
28
+ freshsales = Freshsales::API.new(freshsales_domain: "yourdomain", freshsales_apikey: "...")
25
29
  ```
26
30
 
31
+ ### Design philosophy
32
+
33
+ Freshsales expose resources using a RESTful API allowing to [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) those resources. It also provides extra features such as search.
34
+
35
+ Inspired by [gibbon](https://github.com/amro/gibbon), this library provides a simple dynamic language to construct the URLs required to query those resources.
36
+
37
+ E.g. `freshsales.leads.post(body: requestbody)` would represent a `POST /api/leads/` request and return a `Freshsale::Response` instance.
38
+
39
+ The json data (`requestbody`) can be passed as string or Hashes.
40
+
41
+ The received json data can be obtained as raw or Hashes (with symbolized keys or not).
42
+
27
43
  ## Examples
28
44
 
29
- * Create / Update / Get / Delete
45
+ ### Create / Read / Update / Search / Delete resources
30
46
 
31
47
  ```ruby
32
48
  email = "sample@sample.com"
33
49
 
34
50
  lead_data = %({"lead":{"last_name":"Sampleton (sample)", "email": "#{email}"}})
35
51
 
36
- # create lead
52
+ # Create lead
37
53
  result = freshsales.leads.post(body: lead_data)
38
54
  lead_id = result.body['lead']['id']
39
55
 
40
56
  updated_lead_data = %({"lead":{"mobile_number":"1-926-555-9999", "email": "#{email}"}})
41
57
 
42
- # update the lead
43
- freshsales.leads(lead_id).put(body: updated_lead_data).body
44
-
45
- # get the lead
58
+ # Read the lead
46
59
  freshsales.leads(lead_id).get.body
47
60
 
48
- # search the lead by email
61
+ # Update the lead
62
+ freshsales.leads(lead_id).put(body: updated_lead_data).body
63
+
64
+ # Search the lead by email
49
65
  sample = freshsales.search.get(params: {include: "lead", q: email}).body.first
50
66
 
51
- # delete it
67
+ # Delete it
52
68
  freshsales.leads(lead_id).delete
53
69
  ```
54
70
 
71
+ ### Finding a particular view
72
+
73
+ ```ruby
74
+ filters = freshsales.contacts.filters.get
75
+
76
+ view_id = filters.body['filters'].select{|f| "All Contacts" == f['name'] }.first['id']
77
+ ```
78
+
79
+ ### Paginated resources
80
+
81
+ Some resources are paginated and controlled by the `per_page` and `page` parameters.
82
+
83
+ While you can return individual pages like this:
84
+ ```ruby
85
+ freshsales.contacts.view(view_id).get(params: {"per_page": 100, "page": 2}).body
86
+ ```
87
+
88
+ the library also allows to iterate over all pages either one element at a time or one page at a time, lazily making the requests for the different pages when required by the client.
89
+
90
+ ```ruby
91
+ freshsales.contacts.view(view_id).get_all.each do |contact|
92
+ # do something with this contact, which may come from any page
93
+ end
94
+
95
+ page_params = { "per_page": 100, "sort": "id", "sort_type": "asc", "include": "owner,creater,source"}
96
+ freshsales.contacts.view(view_id).get_all_pages(params: page_params).each do |contact_page|
97
+ # do something with this page's data which may contain up to 100 contacts and
98
+ # their associated owner, creater and source data
99
+ end
100
+ ```
101
+
102
+ `get_all` and `get_all_pages` return a `Freshsale::Cursor` whose `each` method returns a ruby `Enumerator` when no block is given.
103
+
104
+ **tip** Enumerators in ruby can be used as [Enumerable](https://ruby-doc.org/core/Enumerable.html). This allows you to apply collection operations on them, even chain them, to transform or filter the returned data.
105
+
106
+ E.g. if you wanted to restrict the number of elements/pages you could do `get_all[_pages].each.take(100)[.each]`.
107
+
55
108
  ### Troubleshoot
56
109
 
57
- Enable the `debug` option
110
+ Enable the `debug` option (`Freshsales::API.new(debug: true)`)
111
+
112
+ ### WIP / first public release
113
+
114
+ The library is a work in progress. There will be a couple of API changes before the first public version is officially rolled out. Check [the issues targeted for the 0.1.0 milestone](https://github.com/DragonBox/freshsales/issues?q=is%3Aopen+is%3Aissue+milestone%3A0.1.0)
58
115
 
59
116
  ### Solve SSL Errors
60
117
 
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2018-present WeWantToKnow AS
3
5
  #
@@ -24,9 +26,239 @@ require "bundler/gem_tasks"
24
26
  require "rspec/core/rake_task"
25
27
  require 'rubocop/rake_task'
26
28
 
29
+ require 'logger'
30
+ require 'colored'
31
+ require 'highline/import'
32
+ module UI
33
+ # raised from crash!
34
+ class UICrash < StandardError
35
+ end
36
+
37
+ class EPipeIgnorerLogDevice < Logger::LogDevice
38
+ def initialize(logdev)
39
+ @logdev = logdev
40
+ end
41
+
42
+ # rubocop:disable HandleExceptions
43
+ def write(message)
44
+ @logdev.write(message)
45
+ rescue Errno::EPIPE
46
+ # ignored
47
+ end
48
+ # rubocop:enable HandleExceptions
49
+ end
50
+ class << self
51
+ def log
52
+ return @log if @log
53
+
54
+ $stdout.sync = true
55
+
56
+ @log ||= Logger.new(EPipeIgnorerLogDevice.new($stdout))
57
+
58
+ @log.formatter = proc do |severity, datetime, _progname, msg|
59
+ "#{format_string(datetime, severity)}#{msg}\n"
60
+ end
61
+
62
+ @log
63
+ end
64
+
65
+ def verbose?
66
+ false
67
+ end
68
+
69
+ def format_string(datetime = Time.now, severity = "")
70
+ timestamp ||= if verbose?
71
+ '%Y-%m-%d %H:%M:%S.%2N'
72
+ else
73
+ '%H:%M:%S'
74
+ end
75
+ s = []
76
+ s << "#{severity} " if verbose? && severity && !severity.empty?
77
+ s << "[#{datetime.strftime(timestamp)}] " if timestamp
78
+ s.join('')
79
+ end
80
+
81
+ def confirm(message)
82
+ verify_interactive!(message)
83
+ agree("#{format_string}#{message.to_s.yellow} (y/n)", true)
84
+ end
85
+
86
+ def user_error!(message)
87
+ raise StandardError, message.to_s.red
88
+ end
89
+
90
+ def input(message)
91
+ verify_interactive!(message)
92
+ ask("#{format_string}#{message.to_s.yellow}").to_s.strip
93
+ end
94
+
95
+ def error(message)
96
+ log.error(message.to_s.red)
97
+ end
98
+
99
+ def important(message)
100
+ log.error(message.to_s.yellow)
101
+ end
102
+
103
+ def success(message)
104
+ log.error(message.to_s.green)
105
+ end
106
+
107
+ def message(message)
108
+ log.info(message.to_s)
109
+ end
110
+
111
+ def deprecated(message)
112
+ log.error(message.to_s.bold.blue)
113
+ end
114
+
115
+ def command(message)
116
+ log.info("$ #{message}".cyan.underline)
117
+ end
118
+
119
+ def interactive?
120
+ interactive = true
121
+ interactive = false if $stdout.isatty == false
122
+ # interactive = false if Helper.ci?
123
+ return interactive
124
+ end
125
+
126
+ private
127
+
128
+ def verify_interactive!(message)
129
+ return if interactive?
130
+ important(message)
131
+ crash!("Could not retrieve response as the program runs in non-interactive mode")
132
+ end
133
+
134
+ def crash!(exception)
135
+ raise UICrash.new, exception.to_s
136
+ end
137
+ end
138
+ end
139
+
27
140
  RSpec::Core::RakeTask.new(:spec)
28
141
  RuboCop::RakeTask.new
29
142
 
143
+ class GithubChangelogGenerator
144
+ PATH = '.github_changelog_generator'
145
+ class << self
146
+ def future_release
147
+ s = File.read(PATH)
148
+ s.split("\n").each do |line|
149
+ m = line.match(/future-release=v(.*)/)
150
+ return m[1] if m
151
+ end
152
+ raise "Couldn't find future-release in #{PATH}"
153
+ end
154
+
155
+ def future_release=(nextv)
156
+ s = File.read(PATH)
157
+ lines = s.split("\n").map do |line|
158
+ m = line.match(/future-release=v(.*)/)
159
+ if m
160
+ "future-release=v#{nextv}"
161
+ else
162
+ line
163
+ end
164
+ end
165
+ File.write(PATH, lines.join("\n") + "\n")
166
+ end
167
+ end
168
+ end
169
+
170
+ class FreshsalesCode
171
+ PATH = 'lib/freshsales/version.rb'
172
+ class << self
173
+ def version=(version)
174
+ s = File.read(PATH)
175
+ lines = s.split("\n").map do |line|
176
+ m = line.match(/(.*VERSION = ['"]).*(['"].*)/)
177
+ if m
178
+ "#{m[1]}#{version}#{m[2]}"
179
+ else
180
+ line
181
+ end
182
+ end
183
+ File.write(PATH, lines.join("\n") + "\n")
184
+ end
185
+ end
186
+ end
187
+
188
+ require 'English'
189
+ def run_command(command, error_message = nil)
190
+ output = `#{command}`
191
+ unless $CHILD_STATUS.success?
192
+ error_message = "Failed to run command '#{command}'" if error_message.nil?
193
+ UI.user_error!(error_message)
194
+ end
195
+ output
196
+ end
197
+
198
+ task :ensure_git_clean do
199
+ branch = run_command('git rev-parse --abbrev-ref HEAD', "Couldn't get current git branch").strip
200
+ UI.user_error!("You are not on 'master' but on '#{branch}'") unless branch == "master"
201
+ output = run_command('git status --porcelain', "Couldn't get git status")
202
+ UI.user_error!("git status not clean:\n#{output}") unless output == ""
203
+ end
204
+
205
+ # ensure ready to prepare a PR
206
+ task :prepare_git_pr, [:pr_branch] do |_t, args|
207
+ pr_branch = args['pr_branch']
208
+ raise "Missing pr_branch argument" unless pr_branch
209
+ UI.user_error! "Prepare git PR stopped by user" unless UI.confirm("Creating PR branch #{pr_branch}")
210
+ run_command("git checkout -b #{pr_branch}")
211
+ end
212
+
213
+ desc 'Prepare a release: check repo status, generate changelog, create PR'
214
+ task pre_release: 'ensure_git_clean' do
215
+ require 'freshsales/version'
216
+ nextversion = Freshsales::VERSION
217
+
218
+ # check not already released
219
+ output = run_command("git tag -l v#{nextversion}").strip
220
+ UI.user_error! "Version '#{nextversion}' already released. Run 'rake bump'" unless output == ''
221
+
222
+ gh_future_release = GithubChangelogGenerator.future_release
223
+ UI.user_error! "GithubChangelogGenerator version #{gh_future_release} != #{nextversion}" unless gh_future_release == nextversion
224
+
225
+ pr_branch = "release_#{nextversion}"
226
+ Rake::Task["prepare_git_pr"].invoke(pr_branch)
227
+
228
+ Rake::Task["changelog"].invoke
229
+
230
+ sh('git diff')
231
+ # FIXME: cleanup branch, etc
232
+ UI.user_error! "Pre release stopped by user." unless UI.confirm("CHANGELOG PR for version #{nextversion}. Confirm?")
233
+
234
+ msg = "Preparing release for #{nextversion}"
235
+ sh 'git add CHANGELOG.md'
236
+ sh "git commit -m '#{msg}'"
237
+ sh "git push lacostej" # FIXME: hardcoded
238
+ # FIXME: check hub present
239
+ sh "hub pull-request -m '#{msg}'" # requires hub pre-release " -l nochangelog"
240
+ sh 'git checkout master'
241
+ sh "git branch -D #{pr_branch}"
242
+ end
243
+
244
+ desc 'Bump the version number to the version entered interactively; pushes a commit to master'
245
+ task bump: 'ensure_git_clean' do
246
+ nextversion = UI.input "Next version will be:"
247
+ UI.user_error! "Bump version stopped by user" unless UI.confirm("Next version will be #{nextversion}. Confirm?")
248
+ FreshsalesCode.version = nextversion
249
+ GithubChangelogGenerator.future_release = nextversion
250
+ sh 'rspec'
251
+ sh 'git add .github_changelog_generator lib/freshsales/version.rb Gemfile.lock'
252
+ sh "git commit -m 'Bump version to #{nextversion}'"
253
+ sh 'git push'
254
+ end
255
+
256
+ desc 'Update the changelog, no commit made'
257
+ task :changelog do
258
+ puts "Updating changelog #{ENV['CHANGELOG_GITHUB_TOKEN']}"
259
+ sh "github_changelog_generator" if ENV['CHANGELOG_GITHUB_TOKEN']
260
+ end
261
+
30
262
  desc 'Run all rspec tests'
31
263
  task :test_all do
32
264
  formatter = "--format progress"
data/appveyor.yml CHANGED
@@ -9,6 +9,7 @@ init:
9
9
 
10
10
  install:
11
11
  - set PATH=C:\Ruby24-x64\bin;%PATH%
12
+ - gem install bundler
12
13
  - bundle install
13
14
 
14
15
  environment:
data/freshsales.gemspec CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path('../lib', __FILE__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'freshsales/version'
@@ -8,7 +10,7 @@ Gem::Specification.new do |spec|
8
10
  spec.authors = ["Jerome Lacoste"]
9
11
  spec.email = 'jerome@wewanttoknow.com'
10
12
 
11
- spec.required_ruby_version = '>= 2.1.0'
13
+ spec.required_ruby_version = '>= 2.4.0'
12
14
 
13
15
  spec.summary = "Freshsales"
14
16
  spec.description = 'A wrapper for Freshsales API'
@@ -22,16 +24,19 @@ Gem::Specification.new do |spec|
22
24
  spec.require_paths = ["lib"]
23
25
 
24
26
  # using same minimal dependencies as gibbon, for the sake of compatibility
25
- spec.add_dependency 'faraday', '~> 0.9.1'
26
- spec.add_dependency 'multi_json', '~> 1.11.0'
27
+ spec.add_dependency 'faraday', '>= 0.16.0'
28
+ spec.add_dependency 'multi_json', '>= 1.11.0'
27
29
 
28
30
  # Development only
29
- spec.add_development_dependency "bundler", "~> 1.13"
31
+ spec.add_development_dependency "bundler", "~> 2.2"
32
+ spec.add_development_dependency "colored", '>= 1.2', '< 2.0.0'
30
33
  spec.add_development_dependency "coveralls"
31
34
  spec.add_development_dependency "github_changelog_generator"
35
+ spec.add_development_dependency "highline", "~> 1.7.10"
32
36
  spec.add_development_dependency "pry-byebug"
33
- spec.add_development_dependency "rake", "~> 10.0"
34
- spec.add_development_dependency "rspec", "~> 3.1.0"
37
+ spec.add_development_dependency "rake", ">= 12.3.3"
38
+ spec.add_development_dependency "rspec", "~> 3.8.0"
35
39
  spec.add_development_dependency 'rspec_junit_formatter', '~> 0.2.3'
36
40
  spec.add_development_dependency 'rubocop', '~> 0.52.1'
41
+ spec.add_development_dependency "webmock", "~> 3.3.0"
37
42
  end
data/lib/freshsales.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2018-present WeWantToKnow AS
3
5
  #
@@ -24,7 +26,6 @@ require 'logger'
24
26
  require 'uri'
25
27
  require 'cgi'
26
28
  require 'multi_json'
27
- require 'pry'
28
29
  require 'faraday'
29
30
 
30
31
  require 'freshsales/version'
@@ -1,15 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Freshsales
2
4
  class API
3
- attr_accessor :freshsales_token, :freshsales_domain, :debug, :symbolize_keys, :logger, :adapter, :proxy
5
+ attr_accessor :freshsales_apikey, :freshsales_domain, :debug, :symbolize_keys, :logger, :faraday_adapter, :proxy, :raw_data
4
6
 
5
7
  def initialize(opts = {})
6
- @freshsales_token = opts.fetch(:freshsales_token, ENV["FRESHSALES_TOKEN"])
8
+ @freshsales_apikey = opts.fetch(:freshsales_apikey, ENV["FRESHSALES_APIKEY"])
7
9
  @freshsales_domain = opts.fetch(:freshsales_domain, ENV["FRESHSALES_DOMAIN"])
8
- @symbolize_keys = false
10
+ @raw_data = opts.fetch(:raw_data, false)
11
+ @symbolize_keys = opts.fetch(:symbolize_keys, false)
9
12
  @debug = opts.fetch(:debug, false)
10
- @logger = ::Logger.new(STDOUT)
11
- @adapter = Faraday.default_adapter
12
- @proxy = nil
13
+ @logger = opts.fetch(:logger, ::Logger.new(STDOUT))
14
+ @faraday_adapter = opts.fetch(:faraday_adapter, Faraday.default_adapter)
15
+ @proxy = opts.fetch(:proxy, ENV["FRESHSALES_PROXY"])
13
16
 
14
17
  @client = Client.new(self)
15
18
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Freshsales
2
4
  class Client
3
5
  def initialize(config)
@@ -18,20 +20,24 @@ module Freshsales
18
20
  parsed_response = nil
19
21
 
20
22
  if response.body && !response.body.empty?
21
- begin
22
- headers = response.headers
23
- body = MultiJson.load(response.body, symbolize_keys: @config.symbolize_keys)
24
- parsed_response = Response.new(headers: headers, body: body)
25
- rescue MultiJson::ParseError
26
- error_params = { title: "UNPARSEABLE_RESPONSE", status_code: 500 }
27
- error = FreshsalesError.new("Unparseable response: '#{response.body}'", error_params)
28
- raise error
29
- end
23
+ headers = response.headers
24
+ body = response.body
25
+ body = jsonify_body(body) unless @config.raw_data
26
+ parsed_response = Response.new(headers: headers, body: body)
30
27
  end
31
28
 
32
29
  parsed_response
33
30
  end
34
31
 
32
+ def jsonify_body(body, ignore_parsing_errors: false)
33
+ MultiJson.load(body, symbolize_keys: @config.symbolize_keys)
34
+ rescue MultiJson::ParseError => e
35
+ return if ignore_parsing_errors
36
+ error_params = { detail: e.message, status_code: 500, raw_body: body }
37
+ error = FreshsalesError.new("Unparseable response", error_params)
38
+ raise error
39
+ end
40
+
35
41
  def freshsales_domain
36
42
  "https://#{@config.freshsales_domain}.freshsales.io"
37
43
  end
@@ -47,6 +53,32 @@ module Freshsales
47
53
  end
48
54
  request.url path
49
55
  end
56
+ rescue StandardError => e
57
+ handle_request_error(e)
58
+ end
59
+
60
+ def handle_request_error(error)
61
+ error_params = {}
62
+ if error.is_a?(Faraday::ClientError) && error.response
63
+ error_params[:status_code] = error.response[:status]
64
+ error_params[:raw_body] = error.response[:body]
65
+
66
+ parsed_response = jsonify_body(error.response[:body], ignore_parsing_errors: true)
67
+
68
+ if parsed_response
69
+ error_params[:body] = parsed_response
70
+
71
+ code_key = @config.symbolize_keys ? :code : "code"
72
+ message_key = @config.symbolize_keys ? :message : "message"
73
+
74
+ error_params[:code] = parsed_response[code_key] if parsed_response[code_key]
75
+ error_params[:detail] = parsed_response[message_key] if parsed_response[message_key]
76
+ end
77
+ end
78
+ message = error_params[:detail] || error.message
79
+ error_to_raise = FreshsalesError.new(message, error_params)
80
+
81
+ raise error_to_raise
50
82
  end
51
83
 
52
84
  def connection
@@ -55,13 +87,13 @@ module Freshsales
55
87
  Faraday.new(freshsales_domain, proxy: @config.proxy, ssl: { version: "TLSv1_2" }) do |c|
56
88
  # c.request :url_encoded
57
89
  c.response :raise_error
58
- c.use Faraday::Request::Authorization, 'Token', "token=#{@config.freshsales_token}"
90
+ c.use Faraday::Request::Authorization, 'Token', "token=#{@config.freshsales_apikey}"
59
91
  if @config.debug
60
92
  c.response :logger, @config.logger, bodies: true do |logger|
61
93
  logger.filter(/(Token token=)(\w+)/, '\1[HIDDEN]')
62
94
  end
63
95
  end
64
- c.adapter @config.adapter
96
+ c.adapter @config.faraday_adapter
65
97
  end
66
98
  end
67
99
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Freshsales
2
4
  class Cursor
3
5
  include Enumerable
4
6
 
5
- def initialize(client, path, type, collection_name, args)
7
+ def initialize(client, path, type, collection_name, args = {})
6
8
  @client = client
7
9
  @path = path
8
10
  @type = type
@@ -41,8 +43,6 @@ module Freshsales
41
43
  @client.logger
42
44
  end
43
45
 
44
- MAX = 100_000 # FIXME: get rid off or configure
45
-
46
46
  def fetch_next_page
47
47
  nextpage = @page + 1
48
48
  @args[:params] = params.merge(page: nextpage)
@@ -68,8 +68,10 @@ module Freshsales
68
68
  logger.debug "Found #{j.count} elements #{@type} #{@collection_name}"
69
69
 
70
70
  data = j
71
+ elsif j.is_a? String
72
+ raise "Unexpected data type received #{j.class}. Are you combining pagination with raw_data? Unsupported for now"
71
73
  else
72
- raise "Unexpected data type received #{j.class}"
74
+ raise "Unexpected data type received #{j.class}."
73
75
  end
74
76
 
75
77
  @last_response = last
@@ -78,7 +80,7 @@ module Freshsales
78
80
  end
79
81
 
80
82
  def last?
81
- @last_response || @collection.size >= MAX
83
+ @last_response
82
84
  end
83
85
  end
84
86
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Freshsales
2
4
  class FreshsalesError < StandardError
3
5
  attr_reader :params
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Freshsales
2
4
  class RequestBuilder
3
5
  def initialize(client)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Freshsales
2
4
  class Response
3
5
  attr_accessor :headers, :body
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Freshsales
2
- VERSION = "0.0.1".freeze
4
+ VERSION = "0.0.6"
3
5
  end
metadata CHANGED
@@ -1,41 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: freshsales
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerome Lacoste
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-07 00:00:00.000000000 Z
11
+ date: 2021-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.9.1
19
+ version: 0.16.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.9.1
26
+ version: 0.16.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: multi_json
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.11.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.11.0
41
41
  - !ruby/object:Gem::Dependency
@@ -44,14 +44,34 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.13'
47
+ version: '2.2'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.13'
54
+ version: '2.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: colored
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ - - "<"
63
+ - !ruby/object:Gem::Version
64
+ version: 2.0.0
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '1.2'
72
+ - - "<"
73
+ - !ruby/object:Gem::Version
74
+ version: 2.0.0
55
75
  - !ruby/object:Gem::Dependency
56
76
  name: coveralls
57
77
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +100,20 @@ dependencies:
80
100
  - - ">="
81
101
  - !ruby/object:Gem::Version
82
102
  version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: highline
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 1.7.10
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: 1.7.10
83
117
  - !ruby/object:Gem::Dependency
84
118
  name: pry-byebug
85
119
  requirement: !ruby/object:Gem::Requirement
@@ -98,30 +132,30 @@ dependencies:
98
132
  name: rake
99
133
  requirement: !ruby/object:Gem::Requirement
100
134
  requirements:
101
- - - "~>"
135
+ - - ">="
102
136
  - !ruby/object:Gem::Version
103
- version: '10.0'
137
+ version: 12.3.3
104
138
  type: :development
105
139
  prerelease: false
106
140
  version_requirements: !ruby/object:Gem::Requirement
107
141
  requirements:
108
- - - "~>"
142
+ - - ">="
109
143
  - !ruby/object:Gem::Version
110
- version: '10.0'
144
+ version: 12.3.3
111
145
  - !ruby/object:Gem::Dependency
112
146
  name: rspec
113
147
  requirement: !ruby/object:Gem::Requirement
114
148
  requirements:
115
149
  - - "~>"
116
150
  - !ruby/object:Gem::Version
117
- version: 3.1.0
151
+ version: 3.8.0
118
152
  type: :development
119
153
  prerelease: false
120
154
  version_requirements: !ruby/object:Gem::Requirement
121
155
  requirements:
122
156
  - - "~>"
123
157
  - !ruby/object:Gem::Version
124
- version: 3.1.0
158
+ version: 3.8.0
125
159
  - !ruby/object:Gem::Dependency
126
160
  name: rspec_junit_formatter
127
161
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +184,20 @@ dependencies:
150
184
  - - "~>"
151
185
  - !ruby/object:Gem::Version
152
186
  version: 0.52.1
187
+ - !ruby/object:Gem::Dependency
188
+ name: webmock
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: 3.3.0
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: 3.3.0
153
201
  description: A wrapper for Freshsales API
154
202
  email: jerome@wewanttoknow.com
155
203
  executables: []
@@ -159,16 +207,17 @@ files:
159
207
  - ".circleci/config.yml"
160
208
  - ".github/ISSUE_TEMPLATE.md"
161
209
  - ".github/PULL_REQUEST_TEMPLATE.md"
210
+ - ".github_changelog_generator"
162
211
  - ".gitignore"
163
212
  - ".rspec"
164
213
  - ".rubocop.yml"
214
+ - CHANGELOG.md
165
215
  - CODE_OF_CONDUCT.md
166
216
  - Gemfile
167
217
  - Gemfile.lock
168
218
  - LICENSE
169
219
  - README.md
170
220
  - Rakefile
171
- - TODO
172
221
  - appveyor.yml
173
222
  - freshsales.gemspec
174
223
  - lib/freshsales.rb
@@ -183,7 +232,7 @@ homepage: https://github.com/DragonBox/freshsales
183
232
  licenses:
184
233
  - MIT
185
234
  metadata: {}
186
- post_install_message:
235
+ post_install_message:
187
236
  rdoc_options: []
188
237
  require_paths:
189
238
  - lib
@@ -191,16 +240,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
240
  requirements:
192
241
  - - ">="
193
242
  - !ruby/object:Gem::Version
194
- version: 2.1.0
243
+ version: 2.4.0
195
244
  required_rubygems_version: !ruby/object:Gem::Requirement
196
245
  requirements:
197
246
  - - ">="
198
247
  - !ruby/object:Gem::Version
199
248
  version: '0'
200
249
  requirements: []
201
- rubyforge_project:
202
- rubygems_version: 2.6.12
203
- signing_key:
250
+ rubyforge_project:
251
+ rubygems_version: 2.6.14
252
+ signing_key:
204
253
  specification_version: 4
205
254
  summary: Freshsales
206
255
  test_files: []
data/TODO DELETED
@@ -1,6 +0,0 @@
1
- * code cleanup
2
- # clean pagination API
3
- # handle errors (Faraday::Error::ClientError)
4
- # configuration options
5
-
6
- * rspecs