jira-auto-tool 1.1.5 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dcecb56b5f19c1cd8b4b54e50ccd801bff0e6179d0adc4c379855263dc698498
4
- data.tar.gz: 021b5d028d7469d1466b324a69ace618d9973bde7c5c6f1b32df8adb1582d73a
3
+ metadata.gz: a991321a0f8768d42b913499a80fd76ff32cbea71f243e651c0097a6e9c1f10a
4
+ data.tar.gz: 346c3e37814218b13f5b3cb57d74b0431655b9dbca95edf3406f7b1d036252b8
5
5
  SHA512:
6
- metadata.gz: 80c9790171b5014a76ffcae1eae4391e7afd30fd667a48e27bd952e78e1af711e19f5c34cb030782d553de21707610d8c552a17d404f4afd755678b45b56caec
7
- data.tar.gz: 7e6ea437118ada049d32f04619224de79bf6f42c3882a02e2c741c510b8a33aa9888675773ce9a9abafd5ec0adfdb32b03af46c91868b6e3ee7882aa71812d8f
6
+ metadata.gz: c66c77d800f993de4821e03711585976c1cb021258add0d2ee5cb940d7fa92915d66d1b8754a2a4f245d768bbf19b7e71d791673ac9d30b0cf6bff23bcaadfc8
7
+ data.tar.gz: 8e3c54c724e47e4267a3ed4c65d23ff723a5c67764fdce38a05aae3ffdbc6a10d35691c4618fabc2b429a8f26af09e3303ac1004ffa0cc6ce94b1f0999b65b4c
data/README.md CHANGED
@@ -4,18 +4,44 @@
4
4
  ![Main Workflow - all branches](https://github.com/cbroult/jira-auto-tool/actions/workflows/main.yml/badge.svg?label=Ruby%20-%20all%20branches)
5
5
 
6
6
  ****
7
- The purpose of this tool it support managing the sprints of multiple teams so it is easier to adjust to changes.
7
+ The purpose of this tool is to make it easier to make adjustments to the sprints of multiple teams.
8
8
  See the [feature files](./features) for some behavior examples.
9
9
 
10
- ## Warning
11
-
12
- 1. You should familiarize yourself with this tool in a Jira sandbox project **before applying it to your context**.
13
- That can be done easily by [creating a free Atlassian account](https://www.atlassian.com/software)
14
- like it has been done to document [this tool features](./features) using executable specifications.
15
-
16
- 1. Remember that you are **not allowed** to use confidential/sensitive information when familiarizing with this tool
17
- in such a cloud sandbox. Though, if the sandbox belongs to the target context
18
- (e.g., sandbox project on the client Jira instance) you can experiment with the parameters you intend to use later.
10
+ ## Table of Contents
11
+
12
+ - [Principles](#principles)
13
+ - [Installation](#installation)
14
+ - [Setup](#setup)
15
+ - [Usage](#usage)
16
+ - [Warning](#warning)
17
+ - [Add Sprints](#add-sprints)
18
+ - [Adjusting The End Date Of Sprints](#adjusting-the-end-date-of-sprints)
19
+ - [Align Time In Sprint Dates](#align-time-in-sprint-dates)
20
+ - [List Sprints](#list-sprints)
21
+ - [List Sprint Prefixes (Teams)](#list-sprint-prefixes-teams)
22
+ - [Rename Sprints](#rename-sprints)
23
+ - [Team Sprint Mapping](#team-sprint-mapping)
24
+ - [Team Ticket Sprint Dispatching](#team-ticket-sprint-dispatching)
25
+ - [Development](#development)
26
+ - [Install Dependencies](#install-dependencies)
27
+ - [Continuous Testing While Making Changes](#continuous-testing-while-making-changes)
28
+ - [Experiment Using An Interactive Prompt](#experiment-using-an-interactive-prompt)
29
+ - [Install Locally](#install-locally)
30
+ - [Release](#release)
31
+ - [Contributing](#contributing)
32
+ - [License](#license)
33
+ - [Code of Conduct](#code-of-conduct)
34
+
35
+ ## Principles
36
+
37
+ Following a convention over configuration approach:
38
+ * All Scrum boards from the Jira instance are scanned to identify the ones matching the search criteria
39
+ (the list is [cached for a day for performance reasons](./features/cache_boards.feature) to deal with Jira
40
+ instances having thousands of boards);
41
+ * For each board, only the unclosed sprints are considered;
42
+ * Sprint manipulations only apply to those sprints whose names match the following format: `sprint_prefix_25.4.3`
43
+ * [Creating new sprints](./features/create_sprints_using_existing_ones_as_reference.feature)
44
+ will use the existing ones as a reference for the prefix and the length of the sprint.
19
45
 
20
46
  ## Installation
21
47
 
@@ -41,11 +67,8 @@ in such a cloud sandbox. Though, if the sandbox belongs to the target context
41
67
  ```
42
68
  2. Adjust the file to your context.
43
69
 
44
- **WARNING** - It is highly recommended that the JIRA_API_TOKEN value is set as an environment variable
45
- and **NOT** in the generated file.
46
-
47
- While we strive to use convention over configuration as a principle, the following environment variables have to be set
48
- in order to use this tool:
70
+ The following environment variables have to be set to use this tool. **Except** for the `JIRA_API_TOKEN` that should
71
+ be done via the configuration file.
49
72
 
50
73
  Some explanations:
51
74
 
@@ -67,8 +90,9 @@ Optional environment variables:
67
90
  See [sprint filtering](./features/sprint_filtering.feature).
68
91
  - `JIRA_CONTEXT_PATH` - Context path for Jira instance (if needed typically "/jira").
69
92
  - `JIRA_HTTP_DEBUG` - Enable HTTP debug logging (set to "true" or "false").
70
- - `JAT_RATE_LIMIT` - Rate limit for Jira API calls (e.g., "1").
71
- - `JAT_RATE_INTERVAL` - Interval for rate limiting in seconds (e.g., "1").
93
+ - `JAT_RATE_INTERVAL_IN_SECONDS` - Interval for rate limiting in seconds (e.g., "1").
94
+ - `JAT_RATE_LIMIT_PER_INTERVAL` - Rate limit for Jira API calls (e.g., "1")
95
+ See [Control Jira HTTP request rate](./features/control_http_request_rate_limit.feature).
72
96
 
73
97
  ## Usage
74
98
 
@@ -79,6 +103,16 @@ See [sprint filtering](./features/sprint_filtering.feature).
79
103
  * Leverage the [specification by examples](./features) for a detailled understand of the features.
80
104
  * Note that usually the long option names have a short version equivalent to reduce typing.
81
105
 
106
+ ### Warning
107
+
108
+ 1. You should familiarize yourself with this tool in a Jira sandbox project **before applying it to your context**.
109
+ That can be done easily by [creating a free Atlassian account](https://www.atlassian.com/software)
110
+ like it has been done to document [this tool features](./features) using executable specifications.
111
+
112
+ 1. Remember that you are **not allowed** to use confidential/sensitive information when familiarizing with this tool
113
+ in such a cloud sandbox. Though, if the sandbox belongs to the target context
114
+ (e.g., sandbox project on the client Jira instance) you can experiment with the parameters you intend to use later.
115
+
82
116
  Below are a few examples.
83
117
 
84
118
  ### Add Sprints
@@ -90,6 +124,15 @@ to the teams respective sprint prefixes.
90
124
  jira-auto-tool --sprint-add=25.4.3,4
91
125
  ```
92
126
 
127
+ ### Adjusting The End Date Of Sprints
128
+
129
+ The following is going to
130
+ [adjust the end date of sprints](./features/update_sprint_end_date_and_shift_following_ones.feature)
131
+ named `sprint_prefix_25.1.5` and shift the subsequent ones by adjust their start and end dates:
132
+ ```bash
133
+ jira-auto-tool --sprint-update-end-date=25.1.5,"2025-02-25 16:00:00 UTC"
134
+ ```
135
+
93
136
  ### Align Time In Sprint Dates
94
137
 
95
138
  ````bash
@@ -154,7 +197,18 @@ To install this gem onto your local machine, run `bundle exec rake install`.
154
197
 
155
198
  ### Release
156
199
 
157
- To release a new version, update the version number in `version.rb`, 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).
200
+ 1. Bump the gem version:
201
+ ```bash
202
+ bundle exec rake version:bump[{major|minor|patch}]
203
+ ```
204
+ 2. Release the version to [rubygems.org](https://rubygems.org):
205
+ ```bash
206
+ bundle exec rake release
207
+ ```
208
+ which will:
209
+ * create a git tag for the version
210
+ * push git commits and the created tag
211
+ * push the `.gem` file to [rubygems.org](https://rubygems.org).
158
212
 
159
213
  ## Contributing
160
214
 
@@ -10,12 +10,15 @@ DISABLE_COVERAGE: true
10
10
  EXPECTED_START_DATE_FIELD_NAME: Expected Start
11
11
  IMPLEMENTATION_TEAM_FIELD_NAME: "Implementation Team"
12
12
  JAT_RATE_INTERVAL_IN_SECONDS:
13
- JAT_RATE_LIMIT_IN_SECONDS:
13
+ JAT_RATE_LIMIT_IMPLEMENTATION:
14
+ JAT_RATE_LIMIT_PER_INTERVAL:
14
15
  JAT_TICKETS_FOR_TEAM_SPRINT_TICKET_DISPATCHER_JQL: "project = <%= project_key %> AND <%= sprint_field_name %> IS EMPTY"
16
+ # JIRA_BOARD_NAME: "<<<Name of one board if the project>>>"
15
17
  JIRA_BOARD_NAME: "<%= project_key %> - Delivery"
16
18
  JIRA_BOARD_NAME_REGEX: "<%= project_key %>|ART 16|unconventional board name"
17
19
  #JIRA_CONTEXT_PATH: /jira
18
20
  JIRA_CONTEXT_PATH:
21
+ JIRA_HTTP_DEBUG:
19
22
  JIRA_PROJECT_KEY: <%= project_key %>
20
23
  JIRA_SITE_URL: http://cbroult.atlassian.net:443/
21
24
  JIRA_SPRINT_FIELD_NAME: "<%= sprint_field_name %>"
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Disable wrappers only on Windows
4
+ puts "Disabling wrappers for Windows installation"
5
+ RubyGems.configuration.wrappers = false
6
+ exit 0
@@ -17,7 +17,7 @@ Feature: Environment Configuration Management
17
17
  """
18
18
  ---
19
19
  <%
20
- project_key = "PROJ"
20
+ project_key = "JATCIDEVLX"
21
21
  sprint_field_name = "Sprint"
22
22
  jira_username = "cbroult@yahoo.com"
23
23
  %>
@@ -27,11 +27,14 @@ Feature: Environment Configuration Management
27
27
  EXPECTED_START_DATE_FIELD_NAME: Expected Start
28
28
  IMPLEMENTATION_TEAM_FIELD_NAME: "Implementation Team"
29
29
  JAT_RATE_INTERVAL_IN_SECONDS:
30
- JAT_RATE_LIMIT_IN_SECONDS:
30
+ JAT_RATE_LIMIT_IMPLEMENTATION:
31
+ JAT_RATE_LIMIT_PER_INTERVAL:
31
32
  JAT_TICKETS_FOR_TEAM_SPRINT_TICKET_DISPATCHER_JQL: "project = <%= project_key %> AND <%= sprint_field_name %> IS EMPTY"
32
- JIRA_BOARD_NAME: "<%= project_key %> - Your board name"
33
+ # JIRA_BOARD_NAME: "<<<Name of one board if the project>>>"
34
+ JIRA_BOARD_NAME: "<%= project_key %> - Delivery"
33
35
  JIRA_BOARD_NAME_REGEX: "<%= project_key %>|ART 16|unconventional board name"
34
- JIRA_CONTEXT_PATH: /jira
36
+ #JIRA_CONTEXT_PATH: /jira
37
+ JIRA_CONTEXT_PATH:
35
38
  JIRA_HTTP_DEBUG:
36
39
  JIRA_PROJECT_KEY: <%= project_key %>
37
40
  JIRA_SITE_URL: http://cbroult.atlassian.net:443/
@@ -60,7 +63,7 @@ Feature: Environment Configuration Management
60
63
  Please remove first before running this again!
61
64
  """
62
65
 
63
- Scenario: Tool successfully loads the config
66
+ Scenario: Tool successfully loads the config from the current directory and hides secret values when listing them
64
67
  Given a file named "jira-auto-tool.env.yaml.erb" with:
65
68
  """
66
69
  ---
@@ -74,7 +77,8 @@ Feature: Environment Configuration Management
74
77
  EXPECTED_START_DATE_FIELD_NAME: Expected Start
75
78
  IMPLEMENTATION_TEAM_FIELD_NAME: "Implementation Team"
76
79
  JAT_RATE_INTERVAL_IN_SECONDS:
77
- JAT_RATE_LIMIT_IN_SECONDS:
80
+ JAT_RATE_LIMIT_IMPLEMENTATION:
81
+ JAT_RATE_LIMIT_PER_INTERVAL:
78
82
  JAT_TICKETS_FOR_TEAM_SPRINT_TICKET_DISPATCHER_JQL: "project = <%= project_key %> AND <%= sprint_field_name %> IS EMPTY"
79
83
  JIRA_API_TOKEN: "current API TOKEN"
80
84
  JIRA_BOARD_NAME: "Team Board"
@@ -97,9 +101,10 @@ Feature: Environment Configuration Management
97
101
  | EXPECTED_START_DATE_FIELD_NAME | Expected Start |
98
102
  | IMPLEMENTATION_TEAM_FIELD_NAME | Implementation Team |
99
103
  | JAT_RATE_INTERVAL_IN_SECONDS | |
100
- | JAT_RATE_LIMIT_IN_SECONDS | |
104
+ | JAT_RATE_LIMIT_IMPLEMENTATION | |
105
+ | JAT_RATE_LIMIT_PER_INTERVAL | |
101
106
  | JAT_TICKETS_FOR_TEAM_SPRINT_TICKET_DISPATCHER_JQL | project = PROJ AND Sprint IS EMPTY |
102
- | JIRA_API_TOKEN | current API TOKEN |
107
+ | JIRA_API_TOKEN | **** |
103
108
  | JIRA_BOARD_NAME | Team Board |
104
109
  | JIRA_BOARD_NAME_REGEX | ART 16|unconventional board name |
105
110
  | JIRA_CONTEXT_PATH | /jira |
@@ -111,7 +116,7 @@ Feature: Environment Configuration Management
111
116
  +---------------------------------------------------+------------------------------------+
112
117
  """
113
118
 
114
- Scenario: Tool looks first for configuration in the current directory
119
+ Scenario: Tool looks first for configuration in the current directory (hiding secret when listing)
115
120
  Given a file named "./jira-auto-tool.env.yaml.erb" with:
116
121
  """
117
122
  ---
@@ -131,8 +136,16 @@ Feature: Environment Configuration Management
131
136
  """
132
137
  Using configuration from ./jira-auto-tool.env.yaml.erb
133
138
  """
139
+ And the output should match:
140
+ """
141
+ JIRA_API_TOKEN\s+\|\s\*{4}
142
+ """
143
+ And the output should match:
144
+ """
145
+ JIRA_USERNAME\s+\|\scurrent@company.com
146
+ """
134
147
 
135
- Scenario: Tool looks for home directory config folder when no config file in the current directory
148
+ Scenario: Tool looks for home directory config folder when no config file in the current directory (hiding secret when listing)
136
149
  Given a file named "./jira-auto-tool.env.yaml.erb" does not exist
137
150
  And a file named "~/.config/jira-auto-tool/jira-auto-tool.env.yaml.erb" with:
138
151
  """
@@ -145,14 +158,23 @@ Feature: Environment Configuration Management
145
158
  """
146
159
  Using configuration from .+/.config/jira-auto-tool/jira-auto-tool.env.yaml.erb
147
160
  """
161
+ And the output should match:
162
+ """
163
+ JIRA_API_TOKEN\s+\|\s\*{4}\s+
164
+ """
165
+ And the output should match:
166
+ """
167
+ JIRA_USERNAME\s+\|\shome@company.com
168
+ """
148
169
 
149
- Scenario: Tool uses the existing environment values if no config file found
170
+ Scenario: Tool uses the existing environment values if no config file found (hiding secret when listing)
150
171
  Given the following files should not exist:
151
172
  | ./jira-auto-tool.env.yaml.erb |
152
173
  | ~/.config/jira-auto-tool/jira-auto-tool.env.yaml.erb |
153
174
  And the following environment variables are set:
154
- | name | value |
155
- | JIRA_API_TOKEN | token-value |
175
+ | name | value |
176
+ | JIRA_API_TOKEN | token-value |
177
+ | JIRA_USERNAME | env@company.com |
156
178
  When I successfully run `jira-auto-tool --env-list`
157
179
  Then the output should match:
158
180
  """
@@ -162,5 +184,28 @@ Feature: Environment Configuration Management
162
184
  """
163
185
  And the output should match:
164
186
  """
165
- JIRA_API_TOKEN\s+|token-value\s+
187
+ JIRA_API_TOKEN\s+\|\s\*{4}
166
188
  """
189
+ And the output should match:
190
+ """
191
+ JIRA_USERNAME\s+\|\senv@company.com
192
+ """
193
+
194
+ Scenario: Tool displays a useful error message in case of error
195
+ Given a file named "./jira-auto-tool.env.yaml.erb" with:
196
+ """
197
+ ---
198
+ JIRA_USERNAME: "error@company.com"
199
+ JIRA_API_TOKEN: "error-token"
200
+ JIRA_SITE_URL: "https://home.atlassian.net"
201
+ <%
202
+ raise "This is meant to fail while loading!"
203
+ %>
204
+ """
205
+ When I run `jira-auto-tool --env-list`
206
+ Then it should fail with:
207
+ """
208
+ ERROR Jira::Auto::Tool::EnvironmentLoader : ./jira-auto-tool.env.yaml.erb:6: failed to load with the following error:
209
+ This is meant to fail while loading!
210
+ """
211
+
@@ -5,13 +5,25 @@ Feature: Control the HTTP request rate limit
5
5
 
6
6
  Scenario Outline: Limiting the request rate
7
7
  Given the following environment variables are set:
8
- | name | value |
9
- | JAT_RATE_LIMIT_IN_SECONDS | <rate_limit> |
10
- | JAT_RATE_INTERVAL_IN_SECONDS | <rate_interval> |
8
+ | name | value |
9
+ | JAT_RATE_INTERVAL_IN_SECONDS | <rate_interval_in_seconds> |
10
+ | JAT_RATE_LIMIT_IMPLEMENTATION | <jat_rate_limit_implementation> |
11
+ | JAT_RATE_LIMIT_PER_INTERVAL | <rate_limit_per_interval> |
11
12
  Then successfully running `jira-auto-tool --board-list --sprint-prefix` takes between <minimal_time> and <maximal_time> seconds
12
13
 
13
14
  Examples:
14
- | rate_limit | rate_interval | minimal_time | maximal_time |
15
- | 0 | 0 | 0 | 5 |
16
- | 1 | 2 | 1 | 20 |
17
- | 1 | 10 | 18 | 120 |
15
+ | jat_rate_limit_implementation | rate_limit_per_interval | rate_interval_in_seconds | minimal_time | maximal_time |
16
+ | | 0 | 0 | 0 | 5 |
17
+ | in_process | 1 | 2 | 1 | 20 |
18
+ | redis | 1 | 2 | 1 | 20 |
19
+ | redis | 1 | 10 | 18 | 120 |
20
+
21
+ Scenario: Unexpected rate limiting implementation generates an error
22
+ Given the following environment variables are set:
23
+ | name | value |
24
+ | JAT_RATE_LIMIT_IMPLEMENTATION | UNKNOWN IMPLEMENTATION |
25
+ When I run `jira-auto-tool --board-list`
26
+ Then it should fail with:
27
+ """
28
+ RuntimeError: "UNKNOWN IMPLEMENTATION": unexpected rate limiting implementation specified!
29
+ """
@@ -5,14 +5,14 @@ Feature: Add sprints using existing ones as reference
5
5
 
6
6
  Background:
7
7
  Given a Jira Scrum board
8
- And the board only has the following sprints:
8
+
9
+ Scenario: Add several sprints using existing sprint prefixes
10
+ Given the board only has the following sprints:
9
11
  | comment | name | length | start_date | state |
10
12
  | none added since closed | Food_Supply_25.1.3 | 2-week | 2025-02-01 11:00:00 UTC | closed |
11
13
  | "sprints | Food_Delivery_25.1.4 | 4-day | 2025-02-01 11:00:00 UTC | future |
12
14
  | expected to be | Food_Market_25.2.1 | 3-week | 2025-02-01 11:00:00 UTC | active |
13
15
  | added" | Food_Restaurant_25.2.1 | 4-week | 2025-02-21 11:00:00 UTC | future |
14
-
15
- Scenario: Add several sprints using existing sprint prefixes
16
16
  When I successfully run `jira-auto-tool --sprint-add=25.3.1,4`
17
17
  Then afterwards the board only has the following sprints:
18
18
  | name | start_date | state |
@@ -34,7 +34,13 @@ Feature: Add sprints using existing ones as reference
34
34
  | Food_Restaurant_25.3.4 | 2025-06-13 11:00:00 UTC | future |
35
35
 
36
36
  Scenario: Add several planning interval sprints
37
- When I successfully run `jira-auto-tool --sprint-add=25.2.2,3 --sprint-add=25.3.1,4 --sprint-add=25.4.1,5`
37
+ Given the board only has the following sprints:
38
+ | comment | name | length | start_date | state |
39
+ | none added since closed | Food_Supply_25.1.3 | 2-week | 2025-02-01 11:00:00 UTC | closed |
40
+ | "sprints | Food_Delivery_25.1.4 | 4-day | 2025-02-01 11:00:00 UTC | future |
41
+ | expected to be | Food_Market_25.2.1 | 3-week | 2025-02-01 11:00:00 UTC | active |
42
+ | added" | Food_Restaurant_25.2.1 | 4-week | 2025-02-21 11:00:00 UTC | future |
43
+ When I successfully run `jira-auto-tool --sa=25.2.2,3 --sa=25.3.1,4 --sa=25.4.1,5`
38
44
  Then afterwards the board only has the following sprints:
39
45
  | name | start_date | state |
40
46
  | Food_Supply_25.1.3 | 2025-02-01 11:00:00 UTC | closed |
@@ -77,3 +83,25 @@ Feature: Add sprints using existing ones as reference
77
83
  | Food_Restaurant_25.4.3 | 2025-11-28 11:00:00 UTC | future |
78
84
  | Food_Restaurant_25.4.4 | 2025-12-26 11:00:00 UTC | future |
79
85
  | Food_Restaurant_25.4.5 | 2026-01-23 11:00:00 UTC | future |
86
+
87
+ Scenario: Adding sprints is not creating duplicates or ones anterior to last sprints of prefixes
88
+ Given the board only has the following sprints:
89
+ | comment | name | length | start_date | state |
90
+ | none added since closed | Food_Supply_25.1.3 | 2-week | 2025-02-01 11:00:00 UTC | closed |
91
+ | all sprints added | Food_Delivery_25.1.4 | 4-day | 2025-02-01 11:00:00 UTC | future |
92
+ | the last 3 added since the first already exist | Food_Market_25.2.1 | 3-week | 2025-02-01 11:00:00 UTC | active |
93
+ | none added because would be anterior existing sprint | Food_Restaurant_25.3.1 | 4-week | 2025-02-21 11:00:00 UTC | future |
94
+ When I successfully run `jira-auto-tool --sa=25.2.1,4`
95
+ Then afterwards the board only has the following sprints:
96
+ | name | start_date | state |
97
+ | Food_Supply_25.1.3 | 2025-02-01 11:00:00 UTC | closed |
98
+ | Food_Delivery_25.1.4 | 2025-02-01 11:00:00 UTC | future |
99
+ | Food_Delivery_25.2.1 | 2025-02-05 11:00:00 UTC | future |
100
+ | Food_Delivery_25.2.2 | 2025-02-09 11:00:00 UTC | future |
101
+ | Food_Delivery_25.2.3 | 2025-02-13 11:00:00 UTC | future |
102
+ | Food_Delivery_25.2.4 | 2025-02-17 11:00:00 UTC | future |
103
+ | Food_Market_25.2.1 | 2025-02-01 11:00:00 UTC | active |
104
+ | Food_Market_25.2.2 | 2025-02-22 11:00:00 UTC | future |
105
+ | Food_Market_25.2.3 | 2025-03-15 11:00:00 UTC | future |
106
+ | Food_Market_25.2.4 | 2025-04-05 11:00:00 UTC | future |
107
+ | Food_Restaurant_25.3.1 | 2025-02-21 11:00:00 UTC | future |
@@ -46,11 +46,18 @@ module Jira
46
46
  def tool_environment
47
47
  Environment.constants.sort.to_h do |constant|
48
48
  constant_as_string = constant.to_s
49
+ actual_value = ENV.fetch(constant_as_string, nil)
50
+ value_to_display = environment_variable_holds_a_secret?(constant_as_string) ? "****" : actual_value
49
51
 
50
- [constant_as_string, ENV.fetch(constant_as_string, nil)]
52
+ [constant_as_string, value_to_display]
51
53
  end
52
54
  end
53
55
 
56
+ def environment_variable_holds_a_secret?(env_var_name)
57
+ method_name = env_var_name.to_s.downcase
58
+ tool.send("#{method_name}_holds_a_secret?")
59
+ end
60
+
54
61
  def file_path
55
62
  File.exist?(current_dir_file_path) ? current_dir_file_path : config_dir_file_path
56
63
  end
@@ -81,10 +88,27 @@ module Jira
81
88
 
82
89
  def config_values
83
90
  @config_values ||= YAML.safe_load(config_file_content) || {}
91
+ rescue StandardError => e
92
+ error_line = e.backtrace_locations.first.lineno
93
+ message = <<~EOEMSG
94
+ #{file_path}:#{error_line}: failed to load with the following error:
95
+ #{e.message}
96
+ EOEMSG
97
+
98
+ raise message
84
99
  end
85
100
 
86
101
  def config_file_content
87
102
  @config_file_content ||= File.exist?(file_path) ? ERB.new(File.read(file_path)).result(binding) : ""
103
+ rescue StandardError => e
104
+ error_line = e.backtrace_locations.first.lineno
105
+
106
+ message = <<~EOEMSG
107
+ #{file_path}:#{error_line}: failed to load with the following error:
108
+ #{e.message}
109
+ EOEMSG
110
+
111
+ raise message
88
112
  end
89
113
 
90
114
  def table
@@ -6,12 +6,13 @@ module Jira
6
6
  module Helpers
7
7
  module EnvironmentBasedValue
8
8
  # TODO: overly complex - simplify by moving this to the Config and define a Configurable module
9
- def define_overridable_environment_based_value(method_name)
9
+ def define_overridable_environment_based_value(method_name, holds_a_secret)
10
10
  define_reader(method_name)
11
11
  define_predicate(method_name)
12
12
  define_reader_accepting_default_value(method_name)
13
13
  define_writer(method_name)
14
14
  define_environment_variable_name_constant(method_name)
15
+ define_holds_a_secret_predicate(method_name, holds_a_secret)
15
16
  end
16
17
 
17
18
  def define_reader(method_name)
@@ -32,6 +33,10 @@ module Jira
32
33
  end
33
34
  end
34
35
 
36
+ def define_holds_a_secret_predicate(method_name, holds_a_secret)
37
+ define_method(:"#{method_name}_holds_a_secret?") { holds_a_secret }
38
+ end
39
+
35
40
  def define_reader_accepting_default_value(method_name)
36
41
  define_method(:"#{method_name}_when_defined_else") do |value|
37
42
  if config.key?(method_name)
@@ -21,9 +21,10 @@ module Jira
21
21
  parsed_new_name = Sprint::Name.new_with(sprint_prefix.name, sprint_suffix)
22
22
 
23
23
  iteration_count.times do |_iteration|
24
- last_sprint = create_sprint_for(last_sprint, parsed_new_name.to_s)
25
-
26
- sprint_prefix << last_sprint
24
+ unless parsed_new_name <= last_sprint.parsed_name
25
+ last_sprint = create_sprint_for(last_sprint, parsed_new_name.to_s)
26
+ sprint_prefix << last_sprint
27
+ end
27
28
 
28
29
  parsed_new_name = parsed_new_name.next_in_planning_interval
29
30
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby-limiter"
4
+
5
+ require_relative "../rate_limited_jira_client"
6
+
7
+ module Jira
8
+ module Auto
9
+ class Tool
10
+ class RateLimitedJiraClient
11
+ class InProcessBased < RateLimitedJiraClient
12
+ def rate_limit(&block)
13
+ rate_queue.shift
14
+
15
+ block.call
16
+ end
17
+
18
+ def rate_queue
19
+ @rate_queue ||=
20
+ Limiter::RateQueue.new(rate_limit_per_interval, interval: rate_interval_in_seconds)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../rate_limited_jira_client"
4
+ require "ratelimit"
5
+ require "redis"
6
+
7
+ require "jira/auto/tool"
8
+
9
+ module Jira
10
+ module Auto
11
+ class Tool
12
+ class RateLimitedJiraClient
13
+ class RedisBased < RateLimitedJiraClient
14
+ def rate_limit(&block)
15
+ rate_limiter.exec_within_threshold(rate_limiter_key, interval: rate_interval_in_seconds,
16
+ threshold: rate_limit_per_interval) do
17
+ response = block.call
18
+
19
+ rate_limiter.add(rate_limiter_key)
20
+
21
+ response
22
+ end
23
+ end
24
+
25
+ def rate_limiter_key
26
+ "jira_auto_tool_api_requests"
27
+ end
28
+
29
+ def rate_limiter
30
+ self.class.rate_limiter(rate_limiter_key, rate_interval_in_seconds)
31
+ end
32
+
33
+ def self.rate_limiter(rate_limiter_key, rate_interval)
34
+ @rate_limiter ||= Ratelimit.new(rate_limiter_key, bucket_interval: rate_interval)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,48 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ratelimit"
4
- require "redis"
5
-
6
- require "jira/auto/tool"
7
-
8
3
  module Jira
9
4
  module Auto
10
5
  class Tool
11
6
  class RateLimitedJiraClient < JIRA::Client
12
- NO_RATE_LIMIT_IN_SECONDS = 0
7
+ require_relative "rate_limited_jira_client/in_process_based"
8
+ require_relative "rate_limited_jira_client/redis_based"
9
+
10
+ def self.implementation_class_for(tool)
11
+ requested_implementation = tool.jat_rate_limit_implementation_when_defined_else nil
12
+
13
+ case requested_implementation
14
+ when "in_process", "", nil
15
+ InProcessBased
16
+ when "redis"
17
+ RedisBased
18
+ else
19
+ raise %(#{requested_implementation.inspect}: unexpected rate limiting implementation specified!")
20
+ end
21
+ end
22
+
23
+ NO_RATE_LIMIT_PER_INTERVAL = 0
13
24
  NO_RATE_INTERVAL_IN_SECONDS = 0
14
25
 
15
- attr_reader :rate_interval, :rate_limit
26
+ attr_reader :rate_interval_in_seconds, :rate_limit_per_interval
16
27
 
17
- def initialize(options, rate_interval: 1, rate_limit: 1)
28
+ def initialize(options, rate_interval_in_seconds: 1, rate_limit_per_interval: 1)
18
29
  super(options)
19
- @rate_interval = rate_interval
20
- @rate_limit = rate_limit
30
+ @rate_interval_in_seconds = rate_interval_in_seconds
31
+ @rate_limit_per_interval = rate_limit_per_interval
21
32
  end
22
33
 
23
34
  alias original_request request
24
- def request(*args)
25
- return original_request(*args) if rate_limit == NO_RATE_LIMIT_IN_SECONDS
26
-
27
- rate_limiter.exec_within_threshold(rate_limiter_key, interval: rate_interval, threshold: rate_limit) do
28
- response = original_request(*args)
29
35
 
30
- rate_limiter.add(rate_limiter_key)
31
-
32
- response
36
+ def request(*args)
37
+ if rate_limit_per_interval == NO_RATE_LIMIT_PER_INTERVAL
38
+ original_request(*args)
39
+ else
40
+ rate_limit { original_request(*args) }
33
41
  end
34
42
  end
35
43
 
36
- def rate_limiter_key
37
- "jira_auto_tool_api_requests"
38
- end
39
-
40
- def rate_limiter
41
- self.class.rate_limiter(rate_limiter_key, rate_interval)
42
- end
43
-
44
- def self.rate_limiter(rate_limiter_key, rate_interval)
45
- @rate_limiter ||= Ratelimit.new(rate_limiter_key, bucket_interval: rate_interval)
44
+ def rate_limit(&)
45
+ raise "rate_limit must be implemented by a subclass"
46
46
  end
47
47
  end
48
48
  end
@@ -3,7 +3,7 @@
3
3
  module Jira
4
4
  module Auto
5
5
  class Tool
6
- VERSION = "1.1.5"
6
+ VERSION = "1.2.1"
7
7
  end
8
8
  end
9
9
  end