Fix jira init 404 at configuring metadata step on Jira Cloud - #11
Fix jira init 404 at configuring metadata step on Jira Cloud#11rethab wants to merge 18 commits into
Conversation
The Jira wiki-to-markdown parser corrupted non-ASCII characters (Greek, Cyrillic, CJK, accented Latin, emoji, etc.) whenever they appeared on a line that also contained wiki markup such as *bold*, a heading, or a list marker. In secondPass's tokenized-line loop, the fallback branch for bytes that don't start a recognized token wrote `out.WriteRune(rune(line[beg]))` while advancing one byte at a time. This treats every raw UTF-8 byte as its own Unicode code point and re-encodes it, mangling any multibyte sequence. Lines without any markup skip this loop entirely (they're written verbatim), which is why the bug only showed up on lines mixing wiki syntax with non-ASCII text. The fix decodes a full rune at the current byte offset with `utf8.DecodeRuneInString` and advances by its actual byte width instead of a fixed one byte, so multibyte characters pass through intact regardless of what markup surrounds them on the line. Added a test case mixing bold markup with Greek, Cyrillic, and Japanese text to lock in the fix. Addresses ankitpokhrel#1003.
…utput (#9) \`jira issue view\` currently only supports the full pretty/plain rendering (emoji header, subtasks, linked issues, comments, and a Jira URL footer) or \`--raw\`, which dumps the entire Jira API JSON response. There was no way to get just the subject and description as clean text, so users resorted to piping \`issue list --columns\` output through custom jq/sed scripts. This adds a \`--description\` flag that fetches the issue and prints only the summary and the translated description text (reusing the existing description-translation logic used by the pretty view), with no header, footer, comments, or emoji decoration. This makes the output easy to consume from scripts or other tools. Addresses ankitpokhrel#933.
When an issue has a parent, \`jira issue view\` currently gives no indication of it — you'd have to open the issue in the browser to find out. The API response already includes the parent key (\`Fields.Parent\`), it just wasn't being rendered. This adds a \`👪 <PARENT-KEY>\` entry to the header line, right after the issue key, but only when a parent exists so unparented issues (epics, top-level stories) keep the existing layout unchanged. Addresses ankitpokhrel#766.
IssueList.header() in internal/view/issues.go always prepended the KEY column to the requested --columns list whenever it wasn't already present, with no exception for --plain mode. This meant \`jira issue list --plain --columns type\` (for example) would still print a KEY column the user never asked for. KEY is only needed by the interactive TUI to drive its view/move/copy actions. Plain output has no such interactive actions, so this change only forces KEY in when not in --plain mode, and respects the user-supplied --columns list as-is otherwise, including letting KEY be omitted entirely. Addresses ankitpokhrel#747.
`go.mod` still declared the module as `github.com/ankitpokhrel/jira-cli`, so this fork's own packages were all imported through the upstream path. Anyone `go install`-ing or importing from `rethab/jira-cli` would get a module whose declared path disagrees with where it actually lives, and the two would be treated as separate modules if both ended up in one build graph. The build configs hardcoded the same path, which is the part that could ship broken silently: the `-X` ldflags in `Makefile` and `.goreleaser.yml` inject version/commit into `internal/version`, and a `-X` against a package path that isn't in the binary is a no-op rather than an error. Left as-is after a module rename, releases would build fine and report an empty version. Verified by building through the Makefile and confirming `jira version` still reports the injected values. README badges and links to upstream discussions/issues are deliberately untouched — those point at the upstream project's community, not at code, and are a separate call to make.
Jira Cloud can return a 500 Internal Server Error (instead of an empty list) when `jira init` fetches boards for a project that doesn't support Jira Software boards, e.g. a Business/JWM project. This is a known quirk on Jira's side, not something the CLI can fix server-side. The existing code in `getBoardSuggestions` already handles the "no boards available" case gracefully for local/on-prem installs by falling back to a "None" board option (added to handle installs without the agile add-on returning 404), but for Cloud it special-cased the error and aborted `init` entirely, leaving the user unable to finish setup at all. This change drops the Cloud-specific hard-fail and applies the same fallback used for local instances: if the board fetch fails, skip it and offer "None" as the board choice. The fallback is no longer silent: a warning including the response status (e.g. `500 Internal Server Error`) is printed so users can tell why only "None" is offered. This is safe because credentials and server details are already validated earlier in the init flow via `Me()`, so a failed board fetch at this point reflects the project/board API, not auth. Addresses ankitpokhrel#1001.
The Snapshot workflow publishes a GitHub release tagged `snapshot-<version>` on every push to main, which creates a real git tag. That tag isn't valid semver, so on the next run GoReleaser picks it up as the current tag via `git describe`, fails to parse it, and `incpatch` in the snapshot `version_template` blows up with `invalid semantic version`. The very first snapshot run worked fine (no tags existed yet, so GoReleaser defaulted to `0.0.0`), but it permanently poisoned every run after it — every Snapshot workflow run since has failed, while the regular Build/CI workflow is unaffected. Fix: add `git.ignore_tags: ["snapshot-*"]` to `.goreleaser.yml` so GoReleaser never considers its own snapshot release tags when computing the current/previous version. Verified locally with `goreleaser release --snapshot --clean` (v2.17.0, matching the pinned CI version) — it now correctly falls back to `v0.0.0` and builds successfully.
Adds a \`--board\` flag to \`jira sprint list\` that lets you fetch sprints from a board other than the one configured during \`jira init\`, without needing to reconfigure. Previously the board ID used for sprint listing was read exclusively from the stored config, so users working across multiple boards had no way to query a different one for a single invocation. When the flag is used, the board name shown in the interactive sprint explorer falls back to displaying the overridden board's ID, since the configured board name no longer applies and fetching the name would require an extra API call. Addresses ankitpokhrel#847.
The `--raw` flag is registered on both `sprint list` and `epic list` (inherited from `issue list`) and shows up in `--help`, but neither command ever read it, so `--raw` still rendered the interactive/table view instead of JSON. `epic list` was only half-broken in an easy-to-miss way: piping it happened to work, because the non-TTY branch delegates to the issue list handler, which does honor `--raw`. On a TTY, and for `epic list <KEY>` in every case, the flag was silently ignored. Printing the already-fetched epics directly keeps the piped output identical while fixing the cases that were broken. The JSON printing now lives in `cmdutil` so all three list commands share one helper, rather than `issue list` keeping a private copy and the new callers adding more. Tests drive the real command handlers through the real flag set against a stubbed Jira server, so they cover the flag plumbing that was actually broken — including the `--current`/`--prev`/`--next` paths, where `--raw` has to survive the hand-off to the single-sprint view. Addresses ankitpokhrel#931.
The fork inherited upstream's Docker workflow, which publishes to `ghcr.io` only when a release is cut. Between releases there was nothing to pull, even though every merge to `main` already produces a snapshot release and a Homebrew snapshot cask. Merges to `main` now publish an image too. `latest` follows `main`, and releases publish version tags (`1.2.3`, `1.2`). That is the opposite of the Docker default, where `latest` means "newest release", so it is called out in the README: pin a version tag if you want a stable image. Merges additionally get an immutable `main-<sha>` tag. Building four platforms on every merge is only affordable if the build is fast, so the Dockerfile now cross-compiles with Go from the build platform instead of running anything under QEMU emulation. The runtime stage is kept free of `RUN` instructions to make that complete — its `apk` install of ca-certificates was redundant anyway, since Alpine ships the certificate bundle in the base image since 3.9 — so nothing ever executes on the target platform and the workflow needs no QEMU/binfmt setup at all. Cross-compiling meant swapping `go install` for `go build`, since `go install` refuses to cross-compile into `GOBIN`; the linker flags still come from the Makefile (new `ldflags` target), with the tag's `v` prefix stripped, so the version stamped into an image matches a release binary (`1.2.3`, not `v1.2.3`). Smaller things that fall out of that: - `linux/arm/v8` is dropped from the platform list. No client asks for it — ARMv8 hardware reports `linux/arm64`, which we already build — so it was a redundant entry in the manifest. - The runtime base moves from `alpine:3.19` to `3.23`, the release the builder already uses. - The image now carries a signed provenance attestation, matching what the release and snapshot workflows already do for their artifacts. There is deliberately no build cache: a cache that any branch can write to is a way into the images we publish, which is the same reasoning that already keeps the Go cache off the release builds.
jira sprint list only skipped the interactive TUI explorer when --table was passed. Passing --plain alone was silently ignored: the explorer still opened, and the output was never rendered in plain mode. This is inconsistent with jira sprint list <SPRINT_ID> --plain, which always renders directly with no TUI/table gating, and with jira issue list --plain, which is sufficient on its own to get plain output. The fix makes --plain imply the non-interactive table render, same as --table, --dumb-terminal, and non-TTY output already do. The branching logic was pulled into a small pure function so the flag combinations can be unit tested without depending on the actual terminal state. Addresses ankitpokhrel#968.
Adds a --raw flag to jira project list that prints the raw JSON output instead of the rendered table view, matching the existing --raw behavior already available on jira issue list. Addresses ankitpokhrel#885.
`jira issue view --plain` (and non-TTY output that auto-detects plain mode) still leaked non-ASCII decorations into piped output. Parts of the view — `separator()` and `footer()` — already branch on `Display.Plain`, but the rest didn't. Plain output should be safe to pipe, grep, and render in a non-UTF-8 locale like `LC_ALL=C`, so no decoration the view adds around issue data may be non-ASCII. Two changes: - `header()` now follows the same pattern as the rest of the view: when `Display.Plain` is set it renders ASCII labels (`Type:`, `Status:`, `Assignee:`, …) instead of emoji-decorated fields. - The remaining decorations go ASCII in plain mode too: subtask, linked-issue, and comment fields are separated by `|` instead of `•`, and truncated summaries end in `...` instead of `…` (`shortenAndPad` now takes the ellipsis as a parameter and keeps the same column width either way, so alignment is unaffected). Non-plain output is unchanged. A new test asserts the plain issue view contains no non-ASCII characters at all, so future decorations can't silently regress this; a counterpart test pins that the non-plain view keeps its decorations. Addresses ankitpokhrel#213.
Addresses ankitpokhrel#930. `jira init` reads the debug setting via `viper.GetBool("debug")`, so `JIRA_DEBUG` works there. Every other subcommand instead reads debug directly off the pflag object with `cmd.Flags().GetBool("debug")` or `flags.GetBool("debug")`, which never consults viper or the env var, only the `--debug` flag on the command line. As a result `JIRA_DEBUG=true jira issue view ...` (and the equivalent for every other subcommand) silently did nothing. This switches all remaining call sites (issue, epic, sprint, board, project, release and serverinfo commands, plus the sprint query params) to `viper.GetBool("debug")`, mirroring the pattern already used in `internal/config/generator.go`. Since `--debug` is already bound via `viper.BindPFlag("debug", ...)` in `internal/cmd/root/root.go`, and `viper.AutomaticEnv()` + `SetEnvPrefix("jira")` are configured there too, this makes `JIRA_DEBUG` resolve consistently everywhere while leaving existing `--debug` flag behavior unchanged. Also added a test in `internal/query/sprint_test.go` covering that `JIRA_DEBUG` is picked up when constructing sprint query params.
Jira Cloud has sunset the bulk GET /issue/createmeta endpoint with the
issuetypes.fields expand, causing `jira init` to fail with a 404 at the
"Configuring metadata" step. Jira Server 9+ already worked around the
same deprecation by using GET /issue/createmeta/{project}/issuetypes
instead. Route Cloud installations through that same call, since the
issue type id/name/subtask data it returns is all configureMetadata
actually needs (the Fields data from the old bulk call was never used).
|
Rebased onto current One thing to fix before this merges: the per-project endpoint silently drops The PR body says the
Cloud's Smaller things, none blocking:
|
Jira Cloud has deprecated the bulk `GET /issue/createmeta` endpoint (with the `expand=projects.issuetypes.fields` parameter) that `jira init` uses to fetch issue types. This causes the "Configuring metadata" step to fail with a 404 for genuine Cloud tenants, as reported by multiple users.
Jira Server 9+ hit the same deprecation earlier and was already worked around by using the newer per-project `GET /issue/createmeta/{project}/issuetypes` endpoint instead, but that code path was only enabled for local/on-prem installations.
This change routes Cloud installations through the same per-project endpoint. The issue type `id`/`name`/`subtask` data it returns is all `configureMetadata` actually consumes from the old bulk response — the `Fields` data fetched via the old endpoint's `expand` was never read downstream (custom field metadata is fetched separately via `GetField()` in `configureFields`), so this is a safe, no-new-endpoint substitution.
Adds a test verifying that a Cloud installation hits the new per-project endpoint instead of the deprecated bulk one.
Addresses ankitpokhrel#757.