feat: link commits, branches and pull requests to tickets

A project can turn on a webhook for GitHub, Gitea or GitLab. Pushes and
pull or merge requests that name a ticket key show on that ticket under
Desarrollo, with the state of each pull request; the secret is shown and
rotated from the project settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 15:28:12 +02:00
parent 24b37b6628
commit 046d77c813
48 changed files with 2638 additions and 12 deletions

View File

@@ -7561,6 +7561,316 @@
"Sprints"
]
}
},
"/api/projects/{project}/git-integration": {
"get": {
"operationId": "GitController_integration",
"parameters": [
{
"name": "project",
"required": true,
"in": "path",
"description": "Project id or key",
"schema": {
"example": "WEB",
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GitIntegrationDto"
}
}
}
},
"400": {
"description": "Invalid input",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"401": {
"description": "Missing or rejected Pireon token",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"403": {
"description": "Not a member of the project (or not allowed)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
}
},
"security": [
{
"pireon-oauth": []
},
{
"pireon": []
}
],
"summary": "Whether the Git webhook is on (and its secret, for admins)",
"tags": [
"Git"
]
},
"post": {
"operationId": "GitController_enable",
"parameters": [
{
"name": "project",
"required": true,
"in": "path",
"description": "Project id or key",
"schema": {
"example": "WEB",
"type": "string"
}
}
],
"responses": {
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GitIntegrationDto"
}
}
}
},
"400": {
"description": "Invalid input",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"401": {
"description": "Missing or rejected Pireon token",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"403": {
"description": "Not a member of the project (or not allowed)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"409": {
"description": "Someone changed it at the same time: retry",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"422": {
"description": "Business rule (e.g. a transition the workflow forbids)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
}
},
"security": [
{
"pireon-oauth": []
},
{
"pireon": []
}
],
"summary": "Turn the Git webhook on with a new secret (or rotate it)",
"tags": [
"Git"
]
},
"delete": {
"operationId": "GitController_disable",
"parameters": [
{
"name": "project",
"required": true,
"in": "path",
"description": "Project id or key",
"schema": {
"example": "WEB",
"type": "string"
}
}
],
"responses": {
"204": {
"description": ""
},
"400": {
"description": "Invalid input",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"401": {
"description": "Missing or rejected Pireon token",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"403": {
"description": "Not a member of the project (or not allowed)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"409": {
"description": "Someone changed it at the same time: retry",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
},
"422": {
"description": "Business rule (e.g. a transition the workflow forbids)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorDto"
}
}
}
}
},
"security": [
{
"pireon-oauth": []
},
{
"pireon": []
}
],
"summary": "Turn the Git webhook off",
"tags": [
"Git"
]
}
},
"/api/webhooks/git/{project}": {
"post": {
"description": "Push and pull/merge request events. GitHub and Gitea sign the body with the secret (HMAC-SHA256); GitLab sends it as X-Gitlab-Token. Other events are acknowledged and ignored.",
"operationId": "GitController_receive",
"parameters": [
{
"name": "project",
"required": true,
"in": "path",
"description": "Project id or key",
"schema": {
"example": "WEB",
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GitDeliveryResultDto"
}
}
}
},
"403": {
"description": "Unknown project, integration off or bad signature"
}
},
"summary": "Webhook for GitHub, Gitea or GitLab (called by the Git host)",
"tags": [
"Git"
],
"security": []
}
}
},
"info": {
@@ -8582,6 +8892,74 @@
"done"
]
},
"DevLinkKind": {
"type": "string",
"enum": [
"COMMIT",
"BRANCH",
"PULL_REQUEST"
]
},
"DevLinkState": {
"type": "string",
"enum": [
"OPEN",
"MERGED",
"CLOSED"
]
},
"DevLinkDto": {
"type": "object",
"properties": {
"kind": {
"allOf": [
{
"$ref": "#/components/schemas/DevLinkKind"
}
]
},
"url": {
"type": "string"
},
"title": {
"type": "string"
},
"ref": {
"type": "string",
"description": "Short SHA, branch or PR number"
},
"state": {
"nullable": true,
"allOf": [
{
"$ref": "#/components/schemas/DevLinkState"
}
]
},
"provider": {
"type": "string",
"example": "gitea"
},
"author": {
"type": "string",
"nullable": true
},
"at": {
"type": "string",
"format": "date-time"
}
},
"required": [
"kind",
"url",
"title",
"ref",
"state",
"provider",
"author",
"at"
]
},
"IssueDto": {
"type": "object",
"properties": {
@@ -8744,6 +9122,13 @@
"$ref": "#/components/schemas/ChecklistItemDto"
}
},
"devLinks": {
"description": "Commits, branches and pull requests that mention it",
"type": "array",
"items": {
"$ref": "#/components/schemas/DevLinkDto"
}
},
"commentCount": {
"type": "number"
},
@@ -8788,6 +9173,7 @@
"parent",
"rank",
"checklist",
"devLinks",
"commentCount",
"createdAt",
"updatedAt",
@@ -10395,6 +10781,40 @@
"required": [
"sprintId"
]
},
"GitIntegrationDto": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"secret": {
"type": "string",
"nullable": true,
"description": "Webhook secret; only owners and admins see it"
},
"webhookPath": {
"type": "string",
"example": "/api/webhooks/git/3f2c…"
}
},
"required": [
"enabled",
"secret",
"webhookPath"
]
},
"GitDeliveryResultDto": {
"type": "object",
"properties": {
"recorded": {
"type": "number",
"description": "Tickets that got something new"
}
},
"required": [
"recorded"
]
}
}
}