[Feature][Webhook] Allow closing incidents via request body (fixes #8910)#8921
Closed
bujjibabukatta wants to merge 10 commits into
Closed
[Feature][Webhook] Allow closing incidents via request body (fixes #8910)#8921bujjibabukatta wants to merge 10 commits into
bujjibabukatta wants to merge 10 commits into
Conversation
Contributor
Author
|
Hi @klesh could you please review and approve the PR? |
Contributor
|
Hi. Please fix the linting first. |
Contributor
Author
|
Hi @klesh thank you for the feedback! I have fixed the linting issues corrected the indentation from spaces to tabs and removed the trailing whitespace. The golangci-lint should pass now. Please take a look. |
klesh
requested changes
Jun 16, 2026
| } | ||
| domainIssue.Status = ticket.DONE | ||
| domainIssue.OriginalStatus = `` | ||
| now := time.Now() |
Contributor
Author
There was a problem hiding this comment.
Sorry about that! The ResolutionDate logic was accidentally removed
during a merge. It has been restored now.
* feat(gh-copilot): close API gaps for per-user metrics, teams, CLI, code review, and PR fields Add missing GitHub Copilot Metrics API fields to achieve full API parity: Enterprise/Org metrics: - CLI active user counts and CLI breakdown (sessions, requests, tokens) - Code review user counts (daily/weekly/monthly × active/passive) - Chat panel mode breakdown (agent/ask/custom/edit/plan/unknown) - Expanded PR metrics (merged, merge time, suggestions, Copilot impact) Per-user metrics: - used_cli, used_copilot_code_review_active/passive boolean flags - CLI breakdown per user (sessions, requests, tokens) User-team mapping (new): - New collector/extractor for user-teams-1-day endpoint - Enables team-level metrics via JOIN with per-user tables Seat assignments: - Team assignment fields (assigning_team id/name/slug) - User detail fields (name, email) Includes migration script 20260527 and comprehensive docs in COPILOT_METRICS_GAPS.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(copilot-metrics): remove outdated metrics gaps documentation and implement new user-team mapping and metrics enhancements Signed-off-by: Jarek <jaroslaw.gajewski@atos.net> --------- Signed-off-by: Jarek <jaroslaw.gajewski@atos.net> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ion (apache#8907) (apache#8912) * refactor(plugin-circleci): extract unfinished-jobs input clauses into a helper Signed-off-by: Volodymyr Zahorniak <v.zahorniak@gmail.com> * fix(plugin-circleci): populate workflow id for unfinished-job collection (apache#8907) The collectJobs 'unfinished details' collector built its URL from '/v2/workflow/{{ .Input.Id }}/job' but its iterator selected 'DISTINCT workflow_id' into a models.CircleciJob, leaving .Id empty and producing '/v2/workflow//job' (HTTP 500) whenever a job was running/queued/on_hold. Alias the projection to 'workflow_id AS id' so .Id carries the workflow id, mirroring the new-records collector. Adds an e2e regression test. Signed-off-by: Volodymyr Zahorniak <v.zahorniak@gmail.com> --------- Signed-off-by: Volodymyr Zahorniak <v.zahorniak@gmail.com> Co-authored-by: Klesh Wong <klesh@qq.com>
* fix(github-graphql): prevent panic in graphql rate limit polling goroutine Replace panic in GraphqlAsyncClient rate-limit polling goroutine with graceful error handling. Previously, any error while fetching rate limit (e.g., transient network issues or 401 responses) would trigger a panic inside a background goroutine, crashing the entire DevLake process. Now, errors are logged and the client retries in the next cycle while retaining the last known rate limit. Design decisions: - Avoid panic in background goroutines: rate-limit polling is non-critical and should not bring down the entire pipeline. - Use last known rateRemaining on runtime failures instead of resetting or blocking, ensuring continued progress with eventual consistency. - Retry via existing polling mechanism instead of immediate retry to prevent tight retry loops and unnecessary API pressure. - Introduce a default fallback (5000) only for initial rate-limit fetch failures, since no prior state exists at startup. - Separate handling of initial vs runtime failures: - Initial failure → fallback to default (5000) - Runtime failure → retain previous value Fixes apache#8788 (bug 1) * fix(github-graphql): reuse ApiClient transport for GraphQL to enable token refresh Replace oauth2.StaticTokenSource-based HTTP client with the underlying http.Client from ApiAsyncClient. Previously, the GraphQL client constructed its own HTTP client using StaticTokenSource, which froze the access token at task start time. This caused GitHub App installation tokens (which expire after ~1 hour) to become invalid during long-running pipelines, leading to persistent 401 errors. Now, the GraphQL client reuses apiClient.GetClient(), which is already configured with RefreshRoundTripper and TokenProvider. This enables automatic token refresh on 401 responses, aligning GraphQL behavior with the REST client. Design decisions: - Reuse transport layer instead of duplicating authentication logic to ensure consistency across REST and GraphQL clients. - Avoid StaticTokenSource, as it prevents token refresh and breaks long-running pipelines. - Leverage existing RefreshRoundTripper for transparent token rotation without modifying GraphQL query logic. - Keep protocol-specific logic (GraphQL vs REST) separate while sharing the underlying HTTP transport. This ensures GraphQL pipelines using GitHub App authentication can run beyond token expiry without failure. Fixes apache#8788 (bug 2) * refactor(github): extract shared authenticated http client from api client - moved token provider and refresh round tripper setup into a reusable helper - introduced CreateAuthenticatedHttpClient to centralize auth + transport logic - updated CreateApiClient to use shared http client instead of inline setup Rationale: - decouples authentication (transport layer) from REST-specific client logic - enables reuse for GraphQL client without duplicating token refresh logic - aligns architecture with separation of concerns (http transport vs api clients) * feat(github-graphql): introduce graphql client with shared auth and integrate into task flow - added CreateGraphqlClient to encapsulate graphql client construction - reused CreateAuthenticatedHttpClient from github/tasks to inject token refresh via RoundTripper - replaced manual graphql client setup in PrepareTaskData with new factory function - preserved existing rate limit handling via getRateRemaining callback - preserved query cost calculation using SetGetRateCost Technical details: - graphql client now uses http transport with TokenProvider and RefreshRoundTripper - removes dependency on oauth2 client and avoids token expiration issues - decouples graphql client from REST ApiClient by avoiding reuse of apiClient.GetClient() - maintains compatibility with github.com and enterprise graphql endpoints Note: - shared auth logic remains in github/tasks and is imported with alias to avoid package name collision - introduces cross-plugin dependency (github_graphql → github/tasks) as a pragmatic tradeoff to avoid duplication * feat(github): support static token transport for GraphQL and REST clients add StaticRoundTripper for PAT authentication and use it in the shared http client. since the same client is used by both REST and GraphQL, auth handling must distinguish between refreshable tokens and static tokens. avoid applying refresh/retry logic to PAT. ensures correct behavior across clients and prevents unnecessary retries for static auth. * feat(github-graphql): introduce hierarchical fallback for GraphQL rate limit Implement a layered fallback mechanism for GraphQL rate limiting: 1. Dynamic rate limit from provider (getRateRemaining) 2. Per-client override (WithFallbackRateLimit) 3. Config override (GRAPHQL_RATE_LIMIT) 4. Default fallback (1000) Also moved GitHub-specific fallback (5000) via WithFallbackRateLimit to the Graphql client. * feat(github-graphql): Add graphql rate limit to .env example * fix(github): Fix leaked debug statement * fix(github-graphql): reuse http.Client proxy, auth configurations Reused `http.Client` inside the apiClient returned by `CreateApiClient` method, so keeping the proxy and auth configurations the same.That also keep the centralized management of logic. * fix(helpers): fix the priority order of fallback rate limit Priority order fixed for fallback rate limit, priority order is: 1.Env variable 2.Value set with `WithFallbackRateLimit` 3.default value in the code This all works only when the `getRateRemaining` fails: hence the fallback * fix(github): StaticRoundTripper now owns token splitting and rotation for AccessToken connections Previously, connection.Token (comma-separated PATs) was injected as-is into the Authorization header, sending "Bearer tok1,tok2,tok3" instead of a single rotated token. StaticRoundTripper now splits the raw token string on comma and rotates through tokens round-robin using an atomic counter. For REST: StaticRoundTripper operates at transport level and always overwrites the Authorization header set by SetupAuthentication. SetupAuthentication is retained because conn.tokens is still required by GetTokensCount() for rate limit calculation — but its header write is superseded by StaticRoundTripper on every request. For GraphQL: SetupAuthentication is never called by the graphql client, so StaticRoundTripper is the only auth mechanism on this path — without this fix, GraphQL requests were sent with the full unsplit token string. * refactor(github-graphql): Downgrade fetch failure logs from Warn to Info * fix(helper): use inline func type for GraphqlClientOption to avoid mock cycle Replace exported GraphqlClientOption type with inline func(*GraphqlAsyncClient) in CreateAsyncGraphqlClient signature. The named type caused mockery to generate a mock file (GraphqlClientOption.go) that created an import cycle in tests. * style(github): fix linting * fix(github): token rotation start from index * fix(helper): prevent graphql deadlock when rate limit fetch keeps failing --------- Co-authored-by: Klesh Wong <klesh@qq.com>
…#8886) (apache#8894) * fix(github): create domain accounts for non-committer authors (apache#8886) ConvertAccounts sourced the domain `accounts` table FROM _tool_github_accounts, which is only populated for users we collected full profiles for (effectively, committers). Issue and PR authors who never committed were written into _tool_github_repo_accounts but never converted, so issues.creator_id and pull_requests.author_id pointed at accounts rows that didn't exist. Source ConvertAccounts FROM _tool_github_repo_accounts LEFT JOIN _tool_github_accounts instead, so every user the repo references gets a domain account, enriched with profile detail when we have it and login-only otherwise. The domain id uses the same generator the issue/PR convertors use, so the FKs line up. Also emit a repo_account for a PR's merged_by user so pull_requests.merged_by_id resolves too. The query stays MySQL/PostgreSQL-agnostic (COALESCE, no backtick quoting, parameterized via the dal) and mirrors the join already in account_org_collector.go. Adds the non-committer orphan case to the e2e fixture plus a referential- integrity assertion in TestAccountDataFlow. Verified on both MySQL and PostgreSQL. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(github): carry _raw_data provenance and guard zero account ids Review feedback on apache#8894: the rewritten ConvertAccounts dropped the _raw_data fields from converted accounts. Select them with COALESCE, preferring the enriched _tool_github_accounts row and falling back to the _tool_github_repo_accounts row for non-committers. The e2e fixture now carries the _raw_data columns like every other tool fixture, and the regenerated snapshot pins the pre-existing provenance for enriched accounts plus the issue-extractor provenance for the non-committer case. Also guard PR author and merged-by id generation against zero ids: an unmerged PR or a deleted user otherwise yields the domain id github:GithubAccount:<conn>:0, the same orphan-FK shape this PR fixes. issue_convertor already guards its AuthorId the same way. Verified with the full github e2e suite on both MySQL and PostgreSQL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(linear): add tool-layer models and init migration
Add the Linear plugin's tool-layer data models (connection, team scope,
scope config, account, issue, comment, issue label, workflow state, cycle,
issue history) and the initial schema migration with archived snapshots.
The connection authenticates with a personal API key passed verbatim in the
Authorization header (Linear uses no Bearer prefix).
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): add plugin skeleton, connection API and GraphQL client
Wire the Linear plugin entry point and implement all required plugin
interfaces (meta, init, task, api, model, source, migration, blueprint v200,
closeable). Add connection/scope/scope-config CRUD via the data-source helper,
a test-connection endpoint that runs a GraphQL viewer query, and a rate-limited
async GraphQL client that injects the API key via a bare Authorization header.
SubTaskMetas is intentionally empty; collectors are added per entity in
following commits.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): collect, extract and convert users to accounts
Add the users GraphQL collector (paginated), extractor to
_tool_linear_accounts, and convertor to the domain crossdomain.Account
table, wired as the first three subtasks. Includes an e2e dataflow test
with raw fixtures and verified snapshots.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): collect and extract workflow states
Add the team-scoped workflow states GraphQL collector and extractor into
_tool_linear_workflow_states. These states (backlog/unstarted/started/
completed/canceled) drive deterministic issue status mapping. Includes an
e2e test covering all five state types.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): collect, extract and convert issues
Add the team-scoped issues GraphQL collector (incremental via updatedAt
ordering, inline labels), extractor to _tool_linear_issues and
_tool_linear_issue_labels, and convertor to domain ticket.Issue and
ticket.BoardIssue.
Status maps deterministically from Linear's WorkflowState.type
(backlog/unstarted->TODO, started->IN_PROGRESS, completed/canceled->DONE);
priority maps to its label; lead time falls back to resolution minus
creation. Includes an e2e test spanning all state types, unassigned issues,
issues without a cycle, and multi-label issues.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): collect, extract and convert issue comments
Add a per-issue comments GraphQL collector (driven by an input iterator over
collected issues, with pagination), an extractor that recovers the owning
issue id from the raw input column, and a convertor to domain
ticket.IssueComment. Includes an e2e dataflow test.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): convert issue labels to domain layer
Add the convertor from _tool_linear_issue_labels (populated inline by the
issue extractor) into the domain ticket.IssueLabel table. Includes an e2e
test covering issues with multiple labels and with none.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): collect cycles and convert to sprints
Add the team-scoped cycles GraphQL collector and extractor, plus convertors
producing domain ticket.Sprint and ticket.BoardSprint (status derived from
completedAt), and ticket.SprintIssue linking issues to their cycle. Includes
an e2e dataflow test covering closed/active cycles and issues with/without a
cycle.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): collect issue history and convert to changelogs
Add a per-issue history GraphQL collector (input iterator over issues, with
pagination), an extractor capturing state transitions including state types,
and a convertor to domain ticket.IssueChangelogs with mapped from/to status
values. Lead time is already derived from the issue's native
startedAt/completedAt. Includes an e2e test of a full
backlog->started->completed lifecycle.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* test(linear): add blueprint v200 scope generation tests
Cover makeScopesV200: a team scope with the ticket entity produces the
expected domain board scope id, and a scope without the ticket entity
produces none.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* docs(linear): add plugin README
Document the Linear plugin: supported entities, tool/domain mapping tables,
deterministic status mapping, priority/type/lead-time handling, API-key auth,
connection/scope/pipeline setup examples, rate limiting, and the roadmap
(OAuth, label-based type mapping, config-ui integration).
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* fix(linear): guard lead-time fallback against resolution before creation
A resolution timestamp (completedAt/canceledAt) earlier than createdAt —
from clock skew or migrated/imported issues — produced a negative duration
that, cast to uint, yields platform-dependent garbage (0 on arm64, ~1.8e19
on amd64). Skip the fallback unless the resolution is after creation so lead
time stays unset instead.
Adds an isolated e2e dataflow test with a fixture whose canceledAt precedes
createdAt, asserting lead_time_minutes is empty.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* fix(linear): map Linear triage state type to TODO
The WorkflowState.type 'triage' (the inbox state issues land in before being
accepted) previously fell through to OTHER, contradicting the documented total
mapping and silently mislabeling triage issues. Map it to TODO; keep OTHER as
the fallback for genuinely unrecognized types so unexpected API values surface.
Adds a unit test covering every documented state type plus triage and an
unknown value.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* refactor(linear): remove unused GraphqlInlineAccount struct
The struct was documented as the shared inline-user shape but was never
referenced; each collector declares its own inline user struct. Removing it
avoids misleading a maintainer into editing a type nothing reads.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* perf(linear): raise issue collector page size to 100
Every other Linear collector uses a page size of 100; issues used 50, which
doubled the number of issue-page round-trips and the iterator size that drives
the per-issue comment/history collectors. Linear permits first: 250.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): populate issue assignee/creator names and issue_assignees
The issue convertor set only assignee_id/creator_id, leaving the denormalized
assignee_name/creator_name columns blank and writing no issue_assignees rows,
so dashboards reading those columns or joining through issue_assignees showed
blank names. Preload account display names (matching the account convertor's
displayName-then-name rule) and emit an IssueAssignee per assigned issue.
The issue dataflow test now loads accounts before conversion and asserts the
names plus issue_assignees; the lead-time test flushes accounts to stay
order-independent on the shared test DB.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* fix(linear): clear stale sprint_issues when issues leave their cycle
Sprint membership is derived from each issue's cycle_id, and the batch divider
only deletes outdated rows when it produces at least one row of the type. When
every issue is moved out of its cycle the convertor emits nothing, so the
divider never fires and prior sprint_issues rows linger, leaving issues shown
in sprints they no longer belong to. Delete the team's sprint_issues up front
so the result is correct regardless of how many issues remain in a cycle.
Adds a two-run e2e test that empties every issue's cycle and asserts
sprint_issues is empty afterward.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): derive issue lead time from state-transition history
The LinearIssue.LeadTimeMinutes field was never populated, so lead time always
fell back to the coarse createdAt -> resolutionDate span. Derive it instead from
the recorded history: the span from an issue's first transition into an
in-progress state to its first transition into a done state thereafter (active
cycle time), which is the value that genuinely requires history. ConvertIssues
still seeds the fallback; ConvertIssueHistory now overrides it when the
transitions exist, and issues lacking them keep the fallback.
Adds an e2e test asserting issue-1 (started 05-02, completed 05-03) resolves to
1440 minutes from history rather than its 2880-minute created->resolved span.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): add remote-scopes endpoints to enumerate teams
Other first-party ticket plugins (jira, asana, github) expose
connections/:connectionId/remote-scopes so the config UI can browse and select
scopes from the API. Linear had none, forcing users to hand-craft a PUT /scopes
with raw team UUIDs they had no in-product way to discover. Wire the standard
DsRemoteApiProxyHelper + DsRemoteApiScopeListHelper and a lister that queries
the GraphQL teams connection (flat list, cursor-paginated) through the
connection's authenticated client.
Adds unit tests for the response->scope-entry mapping, the pagination cursor,
and the route registration.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* perf(linear): make comment and history collection incremental
Both child collectors used a plain GraphqlCollector and swept every issue in
the team on every run, issuing one request per issue with no since filter -
tens of thousands of requests per run on a large team against Linear's ~1500
req/hour budget. Switch them to a stateful collector and restrict the driving
cursor to issues updated since the last successful collection, so steady-state
runs scale with the change delta rather than the whole backlog. A full sync
(since == nil) still sweeps every issue.
Adds a unit test for the incremental cursor-clause builder.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* fix(linear): filter issues server-side by updatedAt for incremental sync
Incremental collection relied on the issues query returning newest-first and a
client-side early-stop, but the query pinned no sort direction (Linear's orderBy
is a scalar enum with no direction operand). If the server default were
ascending, the early-stop would fire on the first (oldest) row and collect
almost nothing. Pass a server-side IssueFilter { updatedAt: { gt: since } }
instead and drop the early-stop, so correctness no longer depends on an
undocumented default ordering. A full sync passes an empty filter (match all).
Adds a unit test pinning the filter's JSON shape to Linear's IssueFilter input.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* refactor(linear): drop dead LeadTimeMinutes tool-layer field
The _tool_linear_issues.lead_time_minutes column was never populated (the
collector never requested it and no extractor set it). Now that lead time is
derived into the domain ticket.Issue directly -- from state-transition history
when available, otherwise the createdAt->resolutionDate fallback in the issue
convertor -- the tool-layer field is pure dead weight. Remove it from the model,
the init migration's archived model, the convertor, and the extractor snapshot.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(config-ui): register Linear plugin
Adds the Linear data source to config-ui so it appears in the connection
picker: connection form (endpoint + personal API key + proxy + rate limit),
a flat Teams data-scope backed by the plugin's remote-scopes endpoint, and the
Linear logo. No scope-config transformation — Linear's status mapping is
deterministic. Wired into the plugin registry.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* fix(config-ui): map Linear scope id to teamId
getPluginScopeId fell through to the default (scope.id) for Linear, but a
LinearTeam scope is keyed by teamId and has no id field — so the blueprint
referenced an undefined scopeId and patching failed with 'LinearTeam not found'.
Add a linear case returning scope.teamId.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): add Grafana dashboard
Adds grafana/dashboards/Linear.json (cloned from the Asana ticket-dashboard
template) so Linear ships a per-tool dashboard like every other ticket plugin.
Its board picker is scoped to Linear (boards id like 'linear%'); the 13 panels
(throughput, lead/cycle time, status distribution, delivery rate, sprints) read
the shared domain tables. Auto-loaded via Grafana file provisioning.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* fix(linear): convert team scope to a domain board
board_issues and sprint_issues referenced a board_id (boardIdGen over
LinearTeam), but nothing ever created the ticket.Board row itself, so the
domain boards table stayed empty. Board-scoped dashboards (whose board picker
is 'boards where id like linear%') and any board join therefore returned no
data. Add a ConvertTeams subtask that converts the team scope in
_tool_linear_teams into a ticket.Board keyed identically to those references.
Adds an e2e test asserting the board is produced with the matching id.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* fix(linear): widen issue title/url columns to avoid truncation
_tool_linear_issues.title and .url were varchar(255), but Linear titles can
exceed 255 chars (and the issue URL embeds a title slug), so extraction failed
with 'Error 1406: Data too long for column title'. Drop the varchar limit so
both are longtext, matching the domain issues.title and jira's tool summary.
Adds an e2e test extracting a 300-char title without truncation.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* fix(linear): recover owning issue id for comments and history
The GraphQL collector stores the query variables (which carry issueId) in the
raw row's input column, but the comment and history extractors parsed it as
{"Id":...} (SimpleLinearIssue.Id), so the owning issue id came out empty and
the convertor joins produced zero domain comments/changelogs on real data. The
e2e fixtures hand-wrote {"Id":...}, masking it. Parse issueId (with an Id
fallback) and update the fixtures to the real collector shape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* test: flush LinearIssueLabel before issue extraction in e2e tests
The issue extractor writes both _tool_linear_issues and
_tool_linear_issue_labels, but comment_test, cycle_test and
issue_history_test only flushed LinearIssue before running
ExtractIssuesMeta. On a clean database (as in CI) the table
_tool_linear_issue_labels was never auto-migrated, so the extractor's
DELETE on that table panicked and aborted the whole package. Flush
LinearIssueLabel too, matching the other linear e2e tests and the jira
plugin convention.
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* test: register linear plugin in Test_GetPluginTablesInfo
The plugin count check failed in CI (actual 41 vs tested 40) because the
linear plugin was not listed in table_info_test.go. Add its import and
FeedIn call so every Go plugin is covered.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
* feat(linear): map issues to ticket types via label-based scope config
Linear has no native issue type, so the issue convertor previously
hardcoded every issue to REQUIREMENT. Add optional regex fields to the
Linear scope config (issueTypeIncident/Bug/Requirement) matched against
an issue's label names, with precedence INCIDENT > BUG > REQUIREMENT and
a REQUIREMENT default when nothing matches. This lets DORA classify
Linear bugs as incidents for change-failure-rate / time-to-restore.
Also fix two gaps that made scope configs unusable for Linear:
- thread the scope's ScopeConfigId into the pipeline task options so the
convertor can load the config at runtime
- register the standard scope-config/:scopeConfigId/projects route that
every other plugin serves (config-ui 404'd on the scope config page)
Tested: new e2e TestLinearIssueIncidentMapping (Bug label -> INCIDENT,
other issues REQUIREMENT) plus a blueprint plan test asserting
ScopeConfigId is passed through; full plugins/linear suite green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
---------
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pache#8903) * fix(jira): rename Jira Server to Jira Data Center in UI labels * fix(jira): show both Jira Server and Jira Data Center labels
5fa326a to
cfca074
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #8910
Kibana v8.x webhook connectors require a fixed URL per connector and
cannot dynamically construct URLs using alert context values. This made
it impossible to implement a "create + close" incident workflow in Kibana
because the existing close endpoint requires
issueKeyin the URL path.Changes
Added two new endpoints that accept
issueKeyin the JSON request bodyinstead of the URL path, while keeping all existing endpoints untouched
for full backward compatibility.
New endpoints
POST /connections/:connectionId/issue/closeCloseIssueByBodyPOST /connections/by-name/:connectionName/issue/closeCloseIssueByBodyByNameFiles changed
backend/plugins/webhook/api/issues.go— addedCloseIssueByBodyRequeststruct,CloseIssueByBodyandCloseIssueByBodyByNamehandlersbackend/plugins/webhook/impl/impl.go— registered 3 new routes (including legacy prefix variant)How it works
Both new handlers decode
issueKeyfrom the request body and inject itinto
input.Params["issueKey"]before delegating to the existing sharedcloseIssue()helper — zero business logic duplicated.Usage (Kibana or any fixed-URL client)
Notes
/issue/closepriority over wildcard
/issue/:issueKey/closemake swagType of change