Conversation
|
@seflue wanna do a code review on this one? |
|
Sure. I will give it a look. 👍 |
seflue
left a comment
There was a problem hiding this comment.
Thanks for asking me to take a look. A few questions and small readability suggestions below, nothing blocking.
Caveat: I can't verify the Server/DC behavior from my end, so my review is effectively code-only on that side.
One bigger ask up front: would you consider a table-driven test for parseSprintRaw / parseLegacySprint? A handful of cases (modern, legacy, empty, malformed) would double as documentation. I could only vaguely guess from the regex what the legacy input is supposed to look like.
| return attributes | ||
| } | ||
|
|
||
| func assignLegacyAttribute(attributes map[string]string, pair string) { |
There was a problem hiding this comment.
Small readability nit: would strings.IndexByte work here? The manual loop is correct but a bit more to parse on first read:
| func assignLegacyAttribute(attributes map[string]string, pair string) { | |
| func assignLegacyAttribute(attributes map[string]string, pair string) { | |
| eq := strings.IndexByte(pair, '=') | |
| if eq <= 0 { | |
| return | |
| } | |
| attributes[pair[:eq]] = pair[eq+1:] | |
| } |
There was a problem hiding this comment.
beautiful, gonna use yours!
| "strconv" | ||
| ) | ||
|
|
||
| var legacySprintPattern = regexp.MustCompile(`\[([^\[\]]*)\]$`) |
There was a problem hiding this comment.
Although I could guess that you are interested in the trailing [...]
of a Jira legacy sprint string, it would improve readability to have
an example here or in the function documentation of what such a string
actually looks like.
There was a problem hiding this comment.
You're right, gonna add one
| switch sprint.State { | ||
| case "active", "ACTIVE": | ||
| return sprint | ||
| case "future", "FUTURE": | ||
| if future == nil { | ||
| future = sprint | ||
| } | ||
| case "closed", "CLOSED": | ||
| if closed == nil { | ||
| closed = sprint | ||
| } | ||
| } |
There was a problem hiding this comment.
Would normalizing the state once up front read a bit cleaner than
listing both casings per case?
| switch sprint.State { | |
| case "active", "ACTIVE": | |
| return sprint | |
| case "future", "FUTURE": | |
| if future == nil { | |
| future = sprint | |
| } | |
| case "closed", "CLOSED": | |
| if closed == nil { | |
| closed = sprint | |
| } | |
| } | |
| switch strings.ToLower(sprint.State) { | |
| case "active": | |
| return sprint | |
| case "future": | |
| if future == nil { | |
| future = sprint | |
| } | |
| case "closed": | |
| if closed == nil { | |
| closed = sprint | |
| } | |
| } |
There was a problem hiding this comment.
you are right. My version is a bit faster, but your suggestion is much more robust and cleaner, gonna use it
| } | ||
| var modern []Sprint | ||
| if err := json.Unmarshal(data, &modern); err == nil { | ||
| filtered := modern[:0] |
There was a problem hiding this comment.
Minor question: With filtered := modern[:0] you reuse the input slices backing array. It works but surprised me a bit. The allocation saving is tiny (usually a handful of sprints), so I would have expected var filtered []Sprint. No pushback if you prefer the current form, just flagging it as something that made me pause.
There was a problem hiding this comment.
wanna keep it, here it is https://go.dev/wiki/SliceTricks#filtering-without-allocating
| cmds = append(cmds, fetchBoards(a.client)) | ||
| if cmd := a.fetchActiveTab(); cmd != nil { | ||
| cmds = append(cmds, cmd) | ||
| } |
There was a problem hiding this comment.
I noticed fetchActiveTab() moved out of the initial tea.Batch and now fires only after fieldsDiscoveredMsg arrives. That means the first issue fetch waits for fetchFieldDiscovery to complete, where previously the two ran in parallel. Was that intentional? What happens to startup latency if field discovery is slow?
There was a problem hiding this comment.
it was just a bad decision, nice catch. Gonna put back parallel fetch and just remap after active tab finishes
| payload := fields | ||
| if value, ok := fields[sprintFieldAlias]; ok { | ||
| resolved := c.SprintFieldID() | ||
| if resolved != sprintFieldAlias { | ||
| payload = make(map[string]any, len(fields)) | ||
| for key, current := range fields { | ||
| if key == sprintFieldAlias { | ||
| continue | ||
| } | ||
| payload[key] = current | ||
| } | ||
| payload[resolved] = value | ||
| } | ||
| } |
There was a problem hiding this comment.
Previously this method was a thin passthrough, now it does quite a bit. Honestly I got a bit lost here. Would you like to walk me through so I can learn what actually happens? It feels a bit magical.
There was a problem hiding this comment.
Jira on some versions can't work with just 'sprint' field so we need to identify real sprint field (like customfield_10020) and replace pretty field with real one before sending. Maybe there is more elegant solution, I just brute-forced it though
There was a problem hiding this comment.
If you're asking about the technical side, we just identify sprint field, if it isn't 'sprint' we replace field map with new one, which copies previous but skips 'sprint' and adds detected sprint field
There was a problem hiding this comment.
Would be great, if we could move the intent a bit closer to the actual code (or the other way around). That you need to replace a hard-coded field by a custom-defined field of a specific format is intent which I prefer to have well encapsulated and documented to avoid surprising the reader of the code (which often is my future me 😉 ).
|
@seflue thanks for the review! Really nice catches. I'll try to be more active next week, so I think I'll resolve this one by then |
| if sprintField == sprintFieldAlias { | ||
| fields += ",customfield_10010,customfield_10020" | ||
| } |
There was a problem hiding this comment.
Just a small nit: a one-liner explaining the ids would help. Currently reads like magic constants.
| if sprintField == sprintFieldAlias { | |
| fields += ",customfield_10010,customfield_10020" | |
| } | |
| // Default sprint custom-field ids: 10020 (Cloud), 10010 (older Server/DC). | |
| if sprintField == sprintFieldAlias { | |
| fields += ",customfield_10010,customfield_10020" | |
| } |
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [textfuel/lazyjira](https://github.com/textfuel/lazyjira) | minor | `v2.9.0` → `v2.13.0` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>textfuel/lazyjira (textfuel/lazyjira)</summary> ### [`v2.13.0`](https://github.com/textfuel/lazyjira/releases/tag/v2.13.0) [Compare Source](textfuel/lazyjira@v2.12.0...v2.13.0) #### Changelog - [`16a6dd6`](textfuel/lazyjira@16a6dd6) Merge branch 'hotfixes-of-demo-check' - [`11ba667`](textfuel/lazyjira@11ba667) Reach parents and children from the task list ([#​68](textfuel/lazyjira#68)) - [`26afc79`](textfuel/lazyjira@26afc79) Show parent-link children in Sub tab on Cloud ([#​66](textfuel/lazyjira#66)) - [`d5f63df`](textfuel/lazyjira@d5f63df) changelog - [`34ab861`](textfuel/lazyjira@34ab861) changelog - [`5dbd650`](textfuel/lazyjira@5dbd650) codowners adjustments - [`6aa089d`](textfuel/lazyjira@6aa089d) fixes - [`d22816b`](textfuel/lazyjira@d22816b) release v2.13.0 *** **Full changelog:** [CHANGELOG.md](https://github.com/textfuel/lazyjira/blob/main/CHANGELOG.md) ### [`v2.12.0`](https://github.com/textfuel/lazyjira/releases/tag/v2.12.0) [Compare Source](textfuel/lazyjira@v2.11.1...v2.12.0) #### Changelog - [`6af4d03`](textfuel/lazyjira@6af4d03) Feat/task status icons ([#​64](textfuel/lazyjira#64)) - [`a19773b`](textfuel/lazyjira@a19773b) changelog - [`4ca1ee7`](textfuel/lazyjira@4ca1ee7) release v2.12.0 - [`c476e2b`](textfuel/lazyjira@c476e2b) sprint fields ([#​48](textfuel/lazyjira#48)) *** **Full changelog:** [CHANGELOG.md](https://github.com/textfuel/lazyjira/blob/main/CHANGELOG.md) ### [`v2.11.1`](https://github.com/textfuel/lazyjira/releases/tag/v2.11.1) [Compare Source](textfuel/lazyjira@v2.11.0...v2.11.1) #### Changelog - [`29ca5ae`](textfuel/lazyjira@29ca5ae) Route to tracking only on exact remote match ([#​62](textfuel/lazyjira#62)) - [`5516244`](textfuel/lazyjira@5516244) release v2.11.1 *** **Full changelog:** [CHANGELOG.md](https://github.com/textfuel/lazyjira/blob/main/CHANGELOG.md) ### [`v2.11.0`](https://github.com/textfuel/lazyjira/releases/tag/v2.11.0) [Compare Source](textfuel/lazyjira@v2.10.2...v2.11.0) #### Changelog - [`382fe06`](textfuel/lazyjira@382fe06) changelog - [`23b6d49`](textfuel/lazyjira@23b6d49) feat: add catppuccin theme support ([#​59](textfuel/lazyjira#59)) - [`ced4b10`](textfuel/lazyjira@ced4b10) readme v2 path - [`9d434fc`](textfuel/lazyjira@9d434fc) release v2.11.0 - [`e570d8b`](textfuel/lazyjira@e570d8b) some dev QOL ([#​60](textfuel/lazyjira#60)) *** **Full changelog:** [CHANGELOG.md](https://github.com/textfuel/lazyjira/blob/main/CHANGELOG.md) ### [`v2.10.2`](https://github.com/textfuel/lazyjira/releases/tag/v2.10.2) [Compare Source](textfuel/lazyjira@v2.10.1...v2.10.2) #### Changelog - [`94fafd7`](textfuel/lazyjira@94fafd7) fix of v2 version naming ([#​57](textfuel/lazyjira#57)) - [`86f48fe`](textfuel/lazyjira@86f48fe) release v2.10.2 *** **Full changelog:** [CHANGELOG.md](https://github.com/textfuel/lazyjira/blob/main/CHANGELOG.md) ### [`v2.10.1`](https://github.com/textfuel/lazyjira/releases/tag/v2.10.1) [Compare Source](textfuel/lazyjira@v2.10.0...v2.10.1) #### Changelog - [`fe34157`](textfuel/lazyjira@fe34157) changelog - [`5728a57`](textfuel/lazyjira@5728a57) pkg/config: accept string shorthand for the projects list ([#​53](textfuel/lazyjira#53)) - [`cce7280`](textfuel/lazyjira@cce7280) release v2.10.1 *** **Full changelog:** [CHANGELOG.md](https://github.com/textfuel/lazyjira/blob/main/CHANGELOG.md) ### [`v2.10.0`](https://github.com/textfuel/lazyjira/releases/tag/v2.10.0) [Compare Source](textfuel/lazyjira@v2.9.0...v2.10.0) #### Changelog - [`45afec5`](textfuel/lazyjira@45afec5) Add configurable custom commands ([#​42](textfuel/lazyjira#42)) - [`851bfa1`](textfuel/lazyjira@851bfa1) Context-sensitive preview for Sub/Lnk tabs ([#​55](textfuel/lazyjira#55)) - [`f546bc7`](textfuel/lazyjira@f546bc7) Make maxResults configurable globally and per tab ([#​45](textfuel/lazyjira#45)) - [`672fb6d`](textfuel/lazyjira@672fb6d) changelog - [`67bdf1a`](textfuel/lazyjira@67bdf1a) changelog - [`d14fb0e`](textfuel/lazyjira@d14fb0e) perl for make release - [`b04c7a8`](textfuel/lazyjira@b04c7a8) release v2.10.0 *** **Full changelog:** [CHANGELOG.md](https://github.com/textfuel/lazyjira/blob/main/CHANGELOG.md) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNjguNSIsInVwZGF0ZWRJblZlciI6IjQzLjE2OC41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWlub3IiXX0=-->
What
Discover the Sprint custom field id at startup and use it everywhere instead of the hardcoded name sprint. Parse both modern JSON and legacy stringified sprint payloads. Rewrite the sprint key in update requests to the real custom field id
Why
On Jira Cloud Sprint is usually customfield_10020. On older Server and Data Center it is often customfield_10010. Many instances resolve the alias sprint back to the right id but some do not. On those the Sprint field shows None even when the issue has one set. Fixes #33
How to test