feat: automation rules

Owners and admins can set rules of the kind «when a ticket is created,
moves, gets assigned, gets a comment or its pull request merges; if it is
of this type, priority, area or label; then move it, assign it, label it,
change its priority, comment or put it in the active sprint». Rules act as
TaskStream within the workflow, run once per event and trigger no others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 15:53:31 +02:00
parent 1076205acc
commit 8994590b54
30 changed files with 2543 additions and 4 deletions

View File

@@ -46,6 +46,82 @@ type Attachment {
uploadedBy: UserRef!
}
"""When this happens to a ticket, if it is like this, do that"""
type Automation {
action: AutomationActionSpec!
active: Boolean!
conditions: AutomationConditions!
createdAt: String!
createdBy: UserRef!
id: ID!
"""Why the last run did nothing"""
lastError: String
lastRunAt: String
name: String!
projectId: ID!
runs: Int!
trigger: AutomationTriggerSpec!
}
"""What a rule does to the ticket"""
enum AutomationAction {
ADD_COMMENT
ADD_LABEL
ADD_TO_ACTIVE_SPRINT
ASSIGN
ASSIGN_REPORTER
SET_PRIORITY
SET_STATUS
}
input AutomationActionInput {
kind: AutomationAction!
value: String
}
type AutomationActionSpec {
kind: AutomationAction!
"""Status, member id, label, priority or comment text"""
value: String
}
type AutomationConditions {
areas: [String!]
label: String
priorities: [IssuePriority!]
types: [String!]
}
input AutomationConditionsInput {
areas: [String!]
label: String
priorities: [IssuePriority!]
types: [String!]
}
"""What starts a rule"""
enum AutomationTrigger {
COMMENT_ADDED
ISSUE_ASSIGNED
ISSUE_CREATED
PULL_REQUEST_MERGED
STATUS_CHANGED
}
input AutomationTriggerInput {
kind: AutomationTrigger!
status: String
}
type AutomationTriggerSpec {
kind: AutomationTrigger!
"""STATUS_CHANGED: only into this status"""
status: String
}
type BoardColumn {
issues: [Issue!]!
status: String!
@@ -133,6 +209,14 @@ type CountByStatus {
key: String!
}
input CreateAutomationInput {
action: AutomationActionInput!
conditions: AutomationConditionsInput
name: String!
projectId: ID!
trigger: AutomationTriggerInput!
}
input CreateIssueInput {
"""An area id"""
area: String
@@ -466,6 +550,11 @@ type Mutation {
Close the sprint under way. Unfinished tickets move to carryOverToSprintId, or back to the backlog when it is null.
"""
closeSprint(carryOverToSprintId: ID, sprintId: ID!): CommandResult!
"""
Add a rule. It acts as TaskStream, within the workflow, and what it does triggers no other rule.
"""
createAutomation(input: CreateAutomationInput!): Automation!
createIssue(input: CreateIssueInput!): CommandResult!
createProject(input: CreateProjectInput!): CommandResult!
createRelease(input: CreateReleaseInput!): CommandResult!
@@ -473,6 +562,7 @@ type Mutation {
"""Plan a sprint (owners and admins)"""
createSprint(input: CreateSprintInput!): CommandResult!
createWebhook(input: CreateWebhookInput!): WebhookCreated!
deleteAutomation(automationId: ID!): Boolean!
"""Author or project admin"""
deleteComment(commentId: ID!): CommandResult!
@@ -539,6 +629,9 @@ type Mutation {
"""Stop following a ticket"""
unwatchIssue(issueId: ID!): CommandResult!
"""Rename, pause or resume"""
updateAutomation(active: Boolean, automationId: ID!, name: String): Automation!
"""Reword, tick or untick a checklist step"""
updateChecklistItem(input: UpdateChecklistItemInput!): CommandResult!
updateIssue(input: UpdateIssueInput!): CommandResult!
@@ -737,6 +830,7 @@ type Query {
limit: Int! = 50
projectId: ID!
): [Activity!]!
automations(projectId: ID!): [Automation!]!
"""
A project's epics: top-level tickets that group others, with the progress of those