moco-ruby 0.1.2 → 1.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 781b3fd8aed069892a3c387056616917556da295b17878e23e3ec3b8aa8dd8fb
4
- data.tar.gz: 1a818a32e9910e7ab30fd978e4e39348dcb7e970717b60e3f2f2b7dd755c6fbb
3
+ metadata.gz: 94fd15c735a242e23f7a1e20dd49408d12dbfbb21f1665ca64bfd85ba3251cae
4
+ data.tar.gz: 710f5ce6be51b2c363c6d2b3df871d755e5b21e90e9ad53cbb535ac249b46b6f
5
5
  SHA512:
6
- metadata.gz: aa1352b7183998b30397668eca16ca9eefbb99659f72fb60812eb14585f284789808defa0e8dfb147e6327a4d540bccf1e0531c3c3946f6753447bee347e3942
7
- data.tar.gz: 367888eed8cb0a9bc91d2301a28e9f57ab1cc57f9226e5bd09a91fb71fe52c4220ff65bcb0e2fd7aae903fc12107be37f46e5df7ce27636451a1e7d3800e6807
6
+ metadata.gz: 272eede87d5a02636ca02354ea0ef592f0d21662378fb6817b68cc6fa73e66922b43623f6ac5da5c4c76ac3db9c6ebaee12a340fcc9920df93104303f96668fd
7
+ data.tar.gz: 12f55e014641e51ecf2f666c04bff0a5f330ae68b91cf63e70060b6f85e5fc759eed517854060190651581a7ffba5bfa8345fdd25b8e2e59a96193a32cdece9a
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.6
2
+ TargetRubyVersion: 3.2
3
3
  SuggestExtensions: false
4
4
  NewCops: enable
5
5
 
@@ -15,12 +15,19 @@ Naming/MethodParameterName:
15
15
  AllowedNames:
16
16
  - a
17
17
  - b
18
+ - id
18
19
 
19
20
  Layout/LineLength:
20
21
  Max: 130
21
22
 
22
23
  Metrics/BlockLength:
23
- Max: 40
24
+ Enabled: false
24
25
 
25
26
  Metrics/ClassLength:
26
- Max: 130
27
+ Enabled: false
28
+
29
+ Metrics/MethodLength:
30
+ Enabled: false
31
+
32
+ Metrics/AbcSize:
33
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,7 +1,101 @@
1
- # Changelog
1
+ # # Changelog
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.0.0] - 2025-10-08
6
+
7
+ ### Fixed
8
+ - Fixed Project `leader` and `co_leader` associations to return User objects instead of Hashes
9
+ - Fixed Expense associations to use proper `association()` method for embedded objects
10
+ - Fixed nested resource proxy caching issue - tasks and expenses now always return fresh data
11
+ - Fixed `NestedCollectionProxy` path construction for expenses (was double-prefixing with "projects/")
12
+ - Fixed `entity_path` warnings by converting instance methods to class methods in Holiday and WebHook classes
13
+ - Fixed embedded entity conversion for leader, co_leader, and user associations in BaseEntity
14
+
15
+ ### Added
16
+ - Added comprehensive test suite using test-unit framework:
17
+ - `test/test_comprehensive.rb` - 27 integration tests covering all CRUD operations
18
+ - `test/test_holidays_expenses.rb` - 9 tests for holidays and expenses (nested resources)
19
+ - `test/test_v2_api.rb` - 4 unit tests with mocked API responses
20
+ - `test/test_helper.rb` - Shared test configuration
21
+ - Added `Project#expenses` method for nested expense access
22
+ - Added proper entity type mappings for `:leader`, `:co_leader`, and `:user` in BaseEntity
23
+ - Added dotenv gem as development dependency for test environment configuration
24
+
25
+ ### Changed
26
+ - Moved all `require_relative` statements out of methods and into file-level requires
27
+ - Improved load order in `lib/moco.rb` - core classes now load before entities
28
+ - Updated `Expense` entity to use `association()` method for project and user relationships
29
+ - Refactored nested resource access in Project class to return fresh proxies instead of cached ones
30
+ - Enhanced `NestedCollectionProxy` to properly handle nested resource paths without double-prefixing
31
+
32
+ ### Removed
33
+ - Removed manual test scripts (converted to proper test-unit tests)
34
+
35
+ ## [1.0.0.beta] - 2025-04-10
36
+
37
+ ### Fixed
38
+ - Fixed activity synchronization to properly identify existing activities in target system
39
+ - Added remote_id accessor to Activity class to prevent duplicate activity creation
40
+
41
+ ## [1.0.0.alpha] - 2025-04-10
42
+
43
+ ### Added
44
+ - Added support for nested resources with `NestedCollectionProxy` class:
45
+ - Enables ActiveRecord-style operations on nested resources (e.g., `project.tasks.create`)
46
+ - Supports proper path construction for nested API endpoints
47
+ - Implements `destroy_all` method for bulk deletion of nested resources
48
+
49
+ ## [1.0.0.alpha-initial] - 2025-04-10
50
+
51
+ ### Added
52
+ - Implemented ActiveRecord-style query interface (`where`, `find`, `find_by`, `first`, `all`, `each`) via `CollectionProxy`.
53
+ - Added ActiveRecord-style persistence methods to `BaseEntity`:
54
+ - `save` - Persist changes to an entity
55
+ - `update` - Update attributes and save in one step
56
+ - `destroy` - Delete an entity
57
+ - `reload` - Refresh an entity from the API
58
+ - Added `has_many` method to `BaseEntity` for handling one-to-many associations, complementing the existing `association` method for one-to-one associations.
59
+ - Refactored entity association methods in `Project`, `User`, and `Company` classes to use the new `has_many` method.
60
+ - Added comprehensive project lifecycle test that creates a project, adds tasks and activities, then cleans up.
61
+ - Added support for nested resources with `NestedCollectionProxy` class:
62
+ - Enables ActiveRecord-style operations on nested resources (e.g., `project.tasks.create`)
63
+ - Supports proper path construction for nested API endpoints
64
+ - Implements `destroy_all` method for bulk deletion of nested resources
65
+ - Complete redesign with Ruby-esque API
66
+ - Chainable methods for fluent interface
67
+ - Dynamic entity creation with Rails-style inflection
68
+ - Comprehensive entity coverage for all MOCO API endpoints:
69
+ - Project
70
+ - Activity
71
+ - User
72
+ - Company
73
+ - Task
74
+ - Invoice
75
+ - Deal
76
+ - Expense
77
+ - WebHook
78
+ - Schedule
79
+ - Presence
80
+ - Holiday
81
+ - PlanningEntry
82
+ - Entity association methods for related entities
83
+ - Automatic entity creation from API responses
84
+ - Struct-based fallback for unknown entity types
85
+ - Generic association method for handling relationships between entities
86
+
87
+ ### Changed
88
+ - Added ActiveSupport dependency for inflection methods
89
+ - Reorganized code structure for better maintainability
90
+ - Updated documentation with new API examples
91
+ - `MOCO::Activity#to_s` now uses `Helpers.decimal_hours_to_civil` for improved time display.
92
+ - Refined core components like `Client`, `CollectionProxy`, and `Connection`.
93
+ - Updated various entity classes (`Activity`, `BaseEntity`, `Presence`, `Project`) with internal improvements.
94
+ - Updated utility scripts (`mocurl.rb`, `sync_activity.rb`).
95
+
96
+ ### Removed
97
+ - Legacy API (`lib/moco/api.rb`) as part of the transition to the new client.
98
+
5
99
  ## [0.1.2] - 2025-04-02
6
100
 
7
101
  ### Added
@@ -19,18 +113,23 @@
19
113
  ## [0.1.1] - 2024-02-27
20
114
 
21
115
  ### Added
22
-
23
116
  - Prepared for Gem release
24
117
 
25
118
  ### Changed
26
-
27
119
  - Changed target Ruby version to 2.6 (from 3.x)
28
120
  - Applied Rubocop configuration and fixed style errors
29
121
 
30
122
  ### Security
31
-
32
123
  - Bumped `uri` dependency to 0.13.0
33
124
 
34
125
  ## [0.1.0] - 2024-02-27
35
-
36
126
  - Initial release
127
+
128
+ [Unreleased]: https://github.com/starsong-consulting/moco-ruby/compare/v1.0.0...HEAD
129
+ [1.0.0]: https://github.com/starsong-consulting/moco-ruby/compare/v1.0.0.beta...v1.0.0
130
+ [1.0.0.beta]: https://github.com/starsong-consulting/moco-ruby/compare/v1.0.0.alpha...v1.0.0.beta
131
+ [1.0.0.alpha]: https://github.com/starsong-consulting/moco-ruby/compare/v1.0.0.alpha-initial...v1.0.0.alpha
132
+ [1.0.0.alpha-initial]: https://github.com/starsong-consulting/moco-ruby/compare/v0.1.2...v1.0.0.alpha-initial
133
+ [0.1.2]: https://github.com/starsong-consulting/moco-ruby/compare/v0.1.1...v0.1.2
134
+ [0.1.1]: https://github.com/starsong-consulting/moco-ruby/compare/v0.1.0...v0.1.1
135
+ [0.1.0]: https://github.com/starsong-consulting/moco-ruby/releases/tag/v0.1.0
data/Gemfile CHANGED
@@ -5,5 +5,7 @@ source "https://rubygems.org/"
5
5
  gemspec
6
6
 
7
7
  gem "rake", "~> 13.0"
8
-
9
8
  gem "rubocop", "~> 1.21"
9
+ gem "test-unit", "~> 3.5"
10
+ gem "webmock", "~> 3.18"
11
+ gem "dotenv", "~> 2.8"
data/Gemfile.lock CHANGED
@@ -1,57 +1,106 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- moco-ruby (0.1.1)
4
+ moco-ruby (1.0.0)
5
+ activesupport (~> 7.0)
5
6
  faraday (~> 2.9.0)
6
7
  fuzzy_match (~> 2.1.0)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
- ast (2.4.2)
12
- faraday (2.9.0)
12
+ activesupport (7.2.2.1)
13
+ base64
14
+ benchmark (>= 0.3)
15
+ bigdecimal
16
+ concurrent-ruby (~> 1.0, >= 1.3.1)
17
+ connection_pool (>= 2.2.5)
18
+ drb
19
+ i18n (>= 1.6, < 2)
20
+ logger (>= 1.4.2)
21
+ minitest (>= 5.1)
22
+ securerandom (>= 0.3)
23
+ tzinfo (~> 2.0, >= 2.0.5)
24
+ addressable (2.8.7)
25
+ public_suffix (>= 2.0.2, < 7.0)
26
+ ast (2.4.3)
27
+ base64 (0.2.0)
28
+ benchmark (0.4.0)
29
+ bigdecimal (3.1.9)
30
+ concurrent-ruby (1.3.5)
31
+ connection_pool (2.5.0)
32
+ crack (1.0.0)
33
+ bigdecimal
34
+ rexml
35
+ dotenv (2.8.1)
36
+ drb (2.2.1)
37
+ faraday (2.9.2)
13
38
  faraday-net_http (>= 2.0, < 3.2)
14
- faraday-net_http (3.1.0)
39
+ faraday-net_http (3.1.1)
15
40
  net-http
16
41
  fuzzy_match (2.1.0)
17
- json (2.7.1)
18
- language_server-protocol (3.17.0.3)
19
- net-http (0.4.1)
42
+ hashdiff (1.1.2)
43
+ i18n (1.14.7)
44
+ concurrent-ruby (~> 1.0)
45
+ json (2.10.2)
46
+ language_server-protocol (3.17.0.4)
47
+ lint_roller (1.1.0)
48
+ logger (1.7.0)
49
+ minitest (5.25.5)
50
+ net-http (0.6.0)
20
51
  uri
21
- parallel (1.24.0)
22
- parser (3.3.0.5)
52
+ parallel (1.26.3)
53
+ parser (3.3.7.4)
23
54
  ast (~> 2.4.1)
24
55
  racc
25
- racc (1.7.3)
56
+ power_assert (2.0.5)
57
+ prism (1.4.0)
58
+ public_suffix (6.0.1)
59
+ racc (1.8.1)
26
60
  rainbow (3.1.1)
27
- rake (13.1.0)
28
- regexp_parser (2.9.0)
29
- rexml (3.2.6)
30
- rubocop (1.60.2)
61
+ rake (13.2.1)
62
+ regexp_parser (2.10.0)
63
+ rexml (3.4.1)
64
+ rubocop (1.75.2)
31
65
  json (~> 2.3)
32
- language_server-protocol (>= 3.17.0)
66
+ language_server-protocol (~> 3.17.0.2)
67
+ lint_roller (~> 1.1.0)
33
68
  parallel (~> 1.10)
34
69
  parser (>= 3.3.0.2)
35
70
  rainbow (>= 2.2.2, < 4.0)
36
- regexp_parser (>= 1.8, < 3.0)
37
- rexml (>= 3.2.5, < 4.0)
38
- rubocop-ast (>= 1.30.0, < 2.0)
71
+ regexp_parser (>= 2.9.3, < 3.0)
72
+ rubocop-ast (>= 1.44.0, < 2.0)
39
73
  ruby-progressbar (~> 1.7)
40
- unicode-display_width (>= 2.4.0, < 3.0)
41
- rubocop-ast (1.30.0)
42
- parser (>= 3.2.1.0)
74
+ unicode-display_width (>= 2.4.0, < 4.0)
75
+ rubocop-ast (1.44.0)
76
+ parser (>= 3.3.7.2)
77
+ prism (~> 1.4)
43
78
  ruby-progressbar (1.13.0)
44
- unicode-display_width (2.5.0)
45
- uri (0.13.0)
79
+ securerandom (0.4.1)
80
+ test-unit (3.6.8)
81
+ power_assert
82
+ tzinfo (2.0.6)
83
+ concurrent-ruby (~> 1.0)
84
+ unicode-display_width (3.1.4)
85
+ unicode-emoji (~> 4.0, >= 4.0.4)
86
+ unicode-emoji (4.0.4)
87
+ uri (1.0.3)
88
+ webmock (3.25.1)
89
+ addressable (>= 2.8.0)
90
+ crack (>= 0.3.2)
91
+ hashdiff (>= 0.4.0, < 2.0.0)
46
92
 
47
93
  PLATFORMS
48
94
  arm64-darwin-22
49
95
  arm64-darwin-23
50
96
 
51
97
  DEPENDENCIES
98
+ dotenv (~> 2.8)
52
99
  moco-ruby!
53
100
  rake (~> 13.0)
54
101
  rubocop (~> 1.21)
102
+ test-unit (~> 3.5)
103
+ webmock (~> 3.18)
55
104
 
56
105
  BUNDLED WITH
57
106
  2.4.1
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
- # moco-ruby
1
+ # MOCO Ruby Gem
2
2
 
3
- A Ruby Gem to interact with the [MOCO API](https://hundertzehn.github.io/mocoapp-api-docs/).
3
+ [![Gem Version](https://badge.fury.io/rb/moco-ruby.svg)](https://badge.fury.io/rb/moco-ruby)
4
+
5
+ A Ruby Gem to interact with the [MOCO API](https://hundertzehn.github.io/mocoapp-api-docs/). This gem provides a modern, Ruby-esque interface (`MOCO::Client`) for interacting with the MOCO API.
4
6
 
5
7
  ## Installation
6
8
 
@@ -14,88 +16,256 @@ If bundler is not being used to manage dependencies, install the gem by executin
14
16
 
15
17
  ## Usage
16
18
 
17
- ### MOCO::API
19
+ ### Initialization
20
+
21
+ ```ruby
22
+ require 'moco'
23
+
24
+ moco = MOCO::Client.new(
25
+ subdomain: "your-subdomain", # Your MOCO subdomain
26
+ api_key: "your-api-key" # Your MOCO API key
27
+ )
28
+ ```
29
+
30
+ ### Accessing Collections
31
+
32
+ Collections are accessed dynamically using pluralized entity names (following Rails conventions):
33
+
34
+ ```ruby
35
+ projects = moco.projects
36
+ activities = moco.activities
37
+ users = moco.users
38
+ # ... and so on for all supported entities
39
+ ```
40
+
41
+ ### Fetching Entities
42
+
43
+ ```ruby
44
+ # Get all entities in a collection
45
+ all_projects = moco.projects.all
46
+
47
+ # Get entities matching specific criteria
48
+ active_projects = moco.projects.where(active: true)
49
+ recent_activities = moco.activities.where(date: ">=2024-01-01")
50
+
51
+ # Get a specific entity by ID
52
+ project = moco.projects.find(12345)
53
+ user = moco.users.find(678)
54
+ ```
55
+
56
+ ### Creating Entities
18
57
 
19
58
  ```ruby
20
- moco = MOCO::API.new(subdomain, api_key)
21
- assigned_projects = moco.get_assigned_projects(active: 'true')
22
- assigned_projects.each do |project|
23
- puts "Project \##{project.id} #{project.name} for customer #{project.customer.name}"
24
- project.tasks.each do |task|
25
- puts "- Task #{task.name} is #{task.billable ? 'billable' : 'not billable'}"
26
- end
59
+ # Create a new project
60
+ new_project = moco.projects.create(
61
+ name: "New Website Project",
62
+ customer_id: 987,
63
+ billable: true
64
+ )
65
+ puts "Created project: #{new_project.name} (ID: #{new_project.id})"
66
+
67
+ # Create a new time entry (activity)
68
+ new_activity = moco.activities.create(
69
+ date: "2024-04-10",
70
+ project_id: new_project.id,
71
+ task_id: new_project.tasks.first.id, # Assumes project has tasks
72
+ hours: 3.5,
73
+ description: "Implemented feature X"
74
+ )
75
+ puts "Created activity: #{new_activity.description} on #{new_activity.date}"
76
+ ```
77
+
78
+ ### Updating Entities
79
+
80
+ Modify attributes and call `save`:
81
+
82
+ ```ruby
83
+ project = moco.projects.find(12345)
84
+ project.name = "Updated Project Name"
85
+ project.billable = false
86
+
87
+ if project.save
88
+ puts "Project updated successfully."
89
+ else
90
+ puts "Failed to update project: #{project.errors.full_messages.join(", ")}" # Assuming error handling exists
91
+ end
92
+
93
+ # You can also update directly via the collection
94
+ moco.projects.update(12345, name: "Another Update", active: false)
95
+ ```
96
+
97
+ ### Deleting Entities
98
+
99
+ ```ruby
100
+ # Delete by object
101
+ activity = moco.activities.find(9876)
102
+ if activity&.delete
103
+ puts "Activity deleted."
104
+ end
105
+
106
+ # Delete by ID via collection
107
+ if moco.activities.delete(9876)
108
+ puts "Activity deleted."
27
109
  end
28
110
  ```
29
111
 
30
- ### MOCO::Entities
112
+ ### Entity Associations
31
113
 
32
- The following entities are currently defined:
114
+ Entities provide methods to access related entities easily:
33
115
 
34
- - Project (:id, :active, :name, :customer, :tasks)
35
- - Task (:id, :active, :name, :project_id, :billable)
36
- - Activity (:id, :active, :date, :description, :project, :task, :seconds, :hours, :billable, :billed, :user, :customer, :tag)
37
- - Customer (:id, :name)
38
- - User (:id, :firstname, :lastname)
116
+ ```ruby
117
+ project = moco.projects.find(12345)
118
+
119
+ # Get tasks associated with the project
120
+ tasks = project.tasks # Returns a collection proxy for tasks
121
+ puts "Tasks for project '#{project.name}': #{tasks.map(&:name).join(', ')}"
122
+
123
+ # Get activities for the project
124
+ project_activities = project.activities
125
+ puts "Activities count: #{project_activities.size}"
39
126
 
40
- The entities implement comparison, hash and JSON conversion.
127
+ # Get the customer (company) for the project
128
+ customer = project.customer # Returns a MOCO::Company object
129
+ puts "Customer: #{customer.name}"
41
130
 
42
- ### MOCO::Sync
131
+ # ---
43
132
 
44
- Intelligently matches and syncs data from one MOCO instance to another.
45
- Currently supports activities (time entries) only.
46
- See `sync_activity.rb` for a more detailed example.
133
+ activity = moco.activities.find(9876)
134
+
135
+ # Get the associated project, task, and user
136
+ act_project = activity.project
137
+ act_task = activity.task
138
+ act_user = activity.user
139
+ puts "Activity by #{act_user.firstname} on project '#{act_project.name}' (Task: #{act_task.name})"
140
+ ```
141
+
142
+ ### Nested Resources
143
+
144
+ The gem supports ActiveRecord-style operations on nested resources:
47
145
 
48
146
  ```ruby
49
- source_api = MOCO::API.new(source_instance, source_api_key)
50
- target_api = MOCO::API.new(target_instance, target_api_key)
51
-
52
- syncer = MOCO::Sync.new(
53
- source_api,
54
- target_api,
55
- project_match_threshold: options[:match_project_threshold],
56
- task_match_threshold: options[:match_task_threshold],
57
- filters: {
58
- source: options.slice(:from, :to, :project_id, :company_id, :term),
59
- target: options.slice(:from, :to)
60
- },
61
- dry_run: options[:dry_run]
147
+ project = moco.projects.find(12345)
148
+
149
+ # Create a new task for the project
150
+ new_task = project.tasks.create(
151
+ name: "New Feature Development",
152
+ billable: true,
153
+ active: true,
154
+ budget: 40,
155
+ hourly_rate: 120
62
156
  )
157
+ puts "Created task: #{new_task.name} (ID: #{new_task.id})"
158
+
159
+ # Delete all tasks for a project
160
+ project.tasks.destroy_all
161
+
162
+ # Query tasks with conditions
163
+ billable_tasks = project.tasks.where(billable: true).all
164
+ puts "Billable tasks: #{billable_tasks.map(&:name).join(', ')}"
165
+
166
+ # Find a specific task
167
+ dev_task = project.tasks.find_by(name: "Development")
63
168
  ```
64
169
 
170
+ ### Supported Entities
171
+
172
+ The gem supports all MOCO API entities with a Ruby-esque interface:
173
+
174
+ - `Project`
175
+ - `Activity`
176
+ - `User`
177
+ - `Company`
178
+ - `Task`
179
+ - `Invoice`
180
+ - `Deal`
181
+ - `Expense`
182
+ - `WebHook`
183
+ - `Schedule`
184
+ - `Presence`
185
+ - `Holiday`
186
+ - `PlanningEntry`
187
+
188
+ Access them via the moco using their plural, snake_case names (e.g., `moco.planning_entries`).
189
+
65
190
  ## Utilities
66
191
 
67
- Utilities can use `config.yml` to fetch instance data and other configuration. For format, see `config.yml.sample`.
192
+ These command-line utilities provide helpful shortcuts. They can use credentials and configuration from a `config.yml` file (see `config.yml.sample`) in the current directory or accept parameters.
68
193
 
69
- ### mocurl
194
+ ### `mocurl`
70
195
 
71
- Run an API request against a MOCO instance and return the result nicely formatted.
72
- Use config.yml or specify api key with `-a`.
196
+ A wrapper around `curl` to easily make authenticated requests to your MOCO instance API. Useful for testing or exploring endpoints.
73
197
 
74
198
  ```
75
199
  Usage: mocurl.rb [options] url
76
200
  mocurl.rb [options] subdomain path
77
- -X, --method METHOD Set HTTP method to use
78
- -d, --data DATA Data to send to server, JSON format
79
- -a, --api-key API_KEY Manually specify MOCO API key
80
- -n, --no-format Disable JSON pretty-printing
201
+ -X, --method METHOD Set HTTP method to use (GET, POST, PUT, DELETE)
202
+ -d, --data DATA Data to send to server (JSON format) for POST/PUT
203
+ -a, --api-key API_KEY Manually specify MOCO API key (overrides config.yml)
204
+ -n, --no-format Disable JSON pretty-printing of the response
81
205
  -v, --verbose Show additional request and response information
82
206
  -h, --help Show this message
83
207
  ```
208
+ **Example:** `mocurl.rb your-subdomain projects/12345`
209
+
210
+ ### `sync_activity`
84
211
 
85
- ### sync_activity
212
+ Syncs activity data (time entries) between two MOCO instances (source and target). It uses fuzzy matching to map projects and tasks between the instances.
86
213
 
87
- Sync activity data (time entries) from one instance to another, fuzzy matching projects and tasks.
88
- It is highly recommended to use filter options (`--from`, `--to`) and to use `--dry-run` first to check the matching performance.
214
+ **Important:**
215
+ * Always use `--dry-run` first to verify the matching and intended actions.
216
+ * Use date filters (`--from`, `--to`) to limit the scope.
89
217
 
90
218
  ```
91
- Usage: sync_activity.rb [options] source target
92
- -f, --from DATE Start date (YYYY-MM-DD)
93
- -t, --to DATE End date (YYYY-MM-DD)
94
- -p, --project PROJECT_ID Project ID to filter by
95
- -c, --company COMPANY_ID Company ID to filter by
96
- -g, --term TERM Term to filter for
97
- -n, --dry-run Match only, but do not edit data
219
+ Usage: sync_activity.rb [options] source_subdomain target_subdomain
220
+ -f, --from DATE Start date for sync (YYYY-MM-DD)
221
+ -t, --to DATE End date for sync (YYYY-MM-DD)
222
+ -p, --project PROJECT_ID Source Project ID to filter by (optional)
223
+ -c, --company COMPANY_ID Source Company ID to filter by (optional)
224
+ -g, --term TERM Term to filter source activities by (optional)
225
+ -n, --dry-run Perform matching and show planned actions, but do not modify target instance
98
226
  --match-project-threshold VALUE
99
- Project matching threshold (0.0 - 1.0), default 0.8
100
- --match-task-threshold VALUE Task matching threshold (0.0 - 1.0), default 0.45
227
+ Fuzzy match threshold for projects (0.0 - 1.0), default 0.8
228
+ --match-task-threshold VALUE Fuzzy match threshold for tasks (0.0 - 1.0), default 0.45
229
+ -h, --help Show this message
101
230
  ```
231
+ **Example:** `sync_activity.rb --from 2024-04-01 --to 2024-04-10 --dry-run source-instance target-instance`
232
+
233
+ ## Development
234
+
235
+ After checking out the repo, run `bin/setup` to install dependencies.
236
+
237
+ ### Running Tests
238
+
239
+ The gem includes a comprehensive test suite with both unit tests (mocked) and integration tests (live API):
240
+
241
+ ```bash
242
+ # Run all tests
243
+ ruby test/test_v2_api.rb # Unit tests (mocked, fast)
244
+ ruby test/test_comprehensive.rb # Integration tests (requires .env)
245
+ ruby test/test_holidays_expenses.rb # Holidays & Expenses tests (requires .env)
246
+
247
+ # Or run individually
248
+ ruby test/test_v2_api.rb
249
+ ```
250
+
251
+ For integration tests, create a `.env` file with your test instance credentials:
252
+ ```
253
+ MOCO_API_TEST_SUBDOMAIN=your-test-subdomain
254
+ MOCO_API_TEST_API_KEY=your-test-api-key
255
+ ```
256
+
257
+ **Note:** The MOCO API has rate limits (120 requests per 2 minutes on standard plans). Integration tests make real API calls.
258
+
259
+ ### Installation
260
+
261
+ To install this gem onto your local machine, run `bundle exec rake install`.
262
+
263
+ To release a new version, update the version number in `version.rb`, update the `CHANGELOG.md`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
264
+
265
+ ## Contributing
266
+
267
+ Bug reports and pull requests are welcome on GitHub at https://github.com/starsong-consulting/moco-ruby.
268
+
269
+ ## License
270
+
271
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).