jira-transitions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseJira Transitions Skill
Jira 问题状态流转 Skill
Purpose
用途
Move issues through workflow states. Get available transitions and execute status changes.
在工作流状态中流转问题,获取可用的状态转换选项并执行状态变更。
When to Use
适用场景
- Moving issues to different statuses (To Do → In Progress → Done)
- Getting available transitions for an issue
- Bulk transitioning issues
- Setting resolution when closing issues
- 将问题在不同状态间转换(待处理 → 进行中 → 已完成)
- 查询某一问题的可用状态转换选项
- 批量转换问题状态
- 关闭问题时设置解决结果
Prerequisites
前置条件
- Authenticated JiraClient (see jira-auth skill)
- Issue transition permissions
- Knowledge of workflow structure
- 已完成认证的JiraClient(参考jira-auth skill)
- 拥有问题状态转换权限
- 了解工作流结构
Important Notes
重要说明
Transition IDs are NOT standardized - they vary by:
- Jira instance
- Project
- Workflow configuration
Always query available transitions first before attempting to transition.
转换ID没有统一标准 - 会因以下因素不同而变化:
- Jira实例
- 项目
- 工作流配置
在执行状态转换前,请务必先查询可用的转换选项。
Implementation Pattern
实现模式
Step 1: Define Types
步骤1:定义类型
typescript
interface Transition {
id: string;
name: string;
to: {
id: string;
name: string;
statusCategory: {
id: number;
key: string;
name: string;
};
};
fields?: Record<string, {
required: boolean;
name: string;
allowedValues?: Array<{ id: string; name: string }>;
}>;
}
interface TransitionsResponse {
transitions: Transition[];
}typescript
interface Transition {
id: string;
name: string;
to: {
id: string;
name: string;
statusCategory: {
id: number;
key: string;
name: string;
};
};
fields?: Record<string, {
required: boolean;
name: string;
allowedValues?: Array<{ id: string; name: string }>;
}>;
}
interface TransitionsResponse {
transitions: Transition[];
}Step 2: Get Available Transitions
步骤2:获取可用的状态转换选项
typescript
async function getTransitions(
client: JiraClient,
issueKeyOrId: string
): Promise<Transition[]> {
const response = await client.request<TransitionsResponse>(
`/issue/${issueKeyOrId}/transitions?expand=transitions.fields`
);
return response.transitions;
}typescript
async function getTransitions(
client: JiraClient,
issueKeyOrId: string
): Promise<Transition[]> {
const response = await client.request<TransitionsResponse>(
`/issue/${issueKeyOrId}/transitions?expand=transitions.fields`
);
return response.transitions;
}Step 3: Find Transition by Name
步骤3:按名称查找转换选项
typescript
async function findTransitionByName(
client: JiraClient,
issueKeyOrId: string,
targetStatusName: string
): Promise<Transition | null> {
const transitions = await getTransitions(client, issueKeyOrId);
return transitions.find(
t => t.name.toLowerCase() === targetStatusName.toLowerCase() ||
t.to.name.toLowerCase() === targetStatusName.toLowerCase()
) || null;
}typescript
async function findTransitionByName(
client: JiraClient,
issueKeyOrId: string,
targetStatusName: string
): Promise<Transition | null> {
const transitions = await getTransitions(client, issueKeyOrId);
return transitions.find(
t => t.name.toLowerCase() === targetStatusName.toLowerCase() ||
t.to.name.toLowerCase() === targetStatusName.toLowerCase()
) || null;
}Step 4: Execute Transition
步骤4:执行状态转换
typescript
interface TransitionOptions {
resolution?: { name: string } | { id: string };
comment?: string;
fields?: Record<string, any>;
}
async function transitionIssue(
client: JiraClient,
issueKeyOrId: string,
transitionId: string,
options: TransitionOptions = {}
): Promise<void> {
const body: any = {
transition: { id: transitionId },
};
if (options.resolution || options.fields) {
body.fields = { ...options.fields };
if (options.resolution) {
body.fields.resolution = options.resolution;
}
}
if (options.comment) {
body.update = {
comment: [
{
add: {
body: {
type: 'doc',
version: 1,
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: options.comment }],
},
],
},
},
},
],
};
}
await client.request(`/issue/${issueKeyOrId}/transitions`, {
method: 'POST',
body: JSON.stringify(body),
});
}typescript
interface TransitionOptions {
resolution?: { name: string } | { id: string };
comment?: string;
fields?: Record<string, any>;
}
async function transitionIssue(
client: JiraClient,
issueKeyOrId: string,
transitionId: string,
options: TransitionOptions = {}
): Promise<void> {
const body: any = {
transition: { id: transitionId },
};
if (options.resolution || options.fields) {
body.fields = { ...options.fields };
if (options.resolution) {
body.fields.resolution = options.resolution;
}
}
if (options.comment) {
body.update = {
comment: [
{
add: {
body: {
type: 'doc',
version: 1,
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: options.comment }],
},
],
},
},
},
],
};
}
await client.request(`/issue/${issueKeyOrId}/transitions`, {
method: 'POST',
body: JSON.stringify(body),
});
}Step 5: High-Level Transition Helper
步骤5:高层级转换辅助函数
typescript
async function moveIssueTo(
client: JiraClient,
issueKeyOrId: string,
targetStatus: string,
options: TransitionOptions = {}
): Promise<boolean> {
const transition = await findTransitionByName(client, issueKeyOrId, targetStatus);
if (!transition) {
console.error(`No transition found to status: ${targetStatus}`);
return false;
}
// Check if resolution is required
if (transition.fields?.resolution?.required && !options.resolution) {
// Default to "Done" resolution
options.resolution = { name: 'Done' };
}
await transitionIssue(client, issueKeyOrId, transition.id, options);
return true;
}typescript
async function moveIssueTo(
client: JiraClient,
issueKeyOrId: string,
targetStatus: string,
options: TransitionOptions = {}
): Promise<boolean> {
const transition = await findTransitionByName(client, issueKeyOrId, targetStatus);
if (!transition) {
console.error(`No transition found to status: ${targetStatus}`);
return false;
}
// 检查是否需要设置解决结果
if (transition.fields?.resolution?.required && !options.resolution) {
// 默认使用“已完成”解决结果
options.resolution = { name: 'Done' };
}
await transitionIssue(client, issueKeyOrId, transition.id, options);
return true;
}Step 6: Bulk Transition
步骤6:批量转换
typescript
async function bulkTransition(
client: JiraClient,
issueKeys: string[],
targetStatus: string,
options: TransitionOptions = {}
): Promise<{ success: string[]; failed: string[] }> {
const results = { success: [] as string[], failed: [] as string[] };
for (const issueKey of issueKeys) {
try {
const success = await moveIssueTo(client, issueKey, targetStatus, options);
if (success) {
results.success.push(issueKey);
} else {
results.failed.push(issueKey);
}
} catch (error) {
results.failed.push(issueKey);
}
}
return results;
}typescript
async function bulkTransition(
client: JiraClient,
issueKeys: string[],
targetStatus: string,
options: TransitionOptions = {}
): Promise<{ success: string[]; failed: string[] }> {
const results = { success: [] as string[], failed: [] as string[] };
for (const issueKey of issueKeys) {
try {
const success = await moveIssueTo(client, issueKey, targetStatus, options);
if (success) {
results.success.push(issueKey);
} else {
results.failed.push(issueKey);
}
} catch (error) {
results.failed.push(issueKey);
}
}
return results;
}Common Transitions
常见状态转换
Most Jira projects have these standard transitions:
| From Status | Transition Name | To Status |
|---|---|---|
| To Do | Start Progress | In Progress |
| In Progress | Done | Done |
| In Progress | Stop Progress | To Do |
| Done | Reopen | To Do |
Note: These names vary by workflow configuration.
大多数Jira项目都有以下标准转换:
| 原状态 | 转换名称 | 目标状态 |
|---|---|---|
| 待处理 | 开始处理 | 进行中 |
| 进行中 | 已完成 | 已完成 |
| 进行中 | 暂停处理 | 待处理 |
| 已完成 | 重新打开 | 待处理 |
注意:这些名称会因工作流配置不同而变化。
Resolution Values
解决结果选项
When transitioning to "Done", you often need a resolution:
| Resolution | Description |
|---|---|
| Done | Work completed |
| Won't Do | Not planning to do |
| Duplicate | Already exists |
| Cannot Reproduce | Cannot reproduce issue |
转换到“已完成”状态时,通常需要设置解决结果:
| 解决结果 | 说明 |
|---|---|
| 已完成 | 工作已完成 |
| 不处理 | 不计划处理该问题 |
| 重复问题 | 已存在相同问题 |
| 无法复现 | 无法复现该问题 |
curl Examples
curl 示例
Get Available Transitions
获取可用的状态转换选项
bash
curl -X GET "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions?expand=transitions.fields" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Accept: application/json"bash
curl -X GET "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions?expand=transitions.fields" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Accept: application/json"Execute Transition (Simple)
执行状态转换(简单版)
bash
curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Content-Type: application/json" \
-d '{
"transition": { "id": "21" }
}'bash
curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Content-Type: application/json" \
-d '{
"transition": { "id": "21" }
}'Transition with Resolution (for Done)
带解决结果的转换(用于已完成状态)
bash
curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Content-Type: application/json" \
-d '{
"transition": { "id": "31" },
"fields": {
"resolution": { "name": "Done" }
}
}'bash
curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Content-Type: application/json" \
-d '{
"transition": { "id": "31" },
"fields": {
"resolution": { "name": "Done" }
}
}'Transition with Comment
带评论的转换
bash
curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Content-Type: application/json" \
-d '{
"transition": { "id": "21" },
"update": {
"comment": [
{
"add": {
"body": {
"type": "doc",
"version": 1,
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Moving to In Progress" }]
}
]
}
}
}
]
}
}'bash
curl -X POST "$JIRA_BASE_URL/rest/api/3/issue/SCRUM-123/transitions" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Content-Type: application/json" \
-d '{
"transition": { "id": "21" },
"update": {
"comment": [
{
"add": {
"body": {
"type": "doc",
"version": 1,
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Moving to In Progress" }]
}
]
}
}
}
]
}
}'API Response (204 No Content)
API响应(204 无内容)
A successful transition returns 204 No Content with an empty body.
成功的状态转换会返回204 No Content,响应体为空。
Error Handling
错误处理
Common Errors
常见错误
| Error | Cause | Solution |
|---|---|---|
| 400 Bad Request | Invalid transition ID | Query transitions first |
| 400 Bad Request | Missing required resolution | Add resolution field |
| 403 Forbidden | No permission to transition | Check workflow permissions |
| 404 Not Found | Issue doesn't exist | Verify issue key |
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 400 请求错误 | 无效的转换ID | 先查询可用的转换选项 |
| 400 请求错误 | 缺少必填的解决结果 | 添加解决结果字段 |
| 403 禁止访问 | 没有状态转换权限 | 检查工作流权限 |
| 404 未找到 | 问题不存在 | 验证问题键 |
Error Response Example
错误响应示例
json
{
"errorMessages": [
"You must specify a resolution when transitioning issues to the 'Done' status."
],
"errors": {
"resolution": "Resolution is required."
}
}json
{
"errorMessages": [
"You must specify a resolution when transitioning issues to the 'Done' status."
],
"errors": {
"resolution": "Resolution is required."
}
}Workflow Discovery Pattern
工作流发现模式
typescript
async function discoverWorkflow(
client: JiraClient,
issueKeyOrId: string
): Promise<Map<string, Transition[]>> {
// Get transitions from current state
const transitions = await getTransitions(client, issueKeyOrId);
console.log(`Available transitions from current state:`);
for (const t of transitions) {
console.log(` ${t.id}: ${t.name} → ${t.to.name}`);
if (t.fields?.resolution?.required) {
console.log(` (requires resolution)`);
}
}
return new Map([
['current', transitions]
]);
}typescript
async function discoverWorkflow(
client: JiraClient,
issueKeyOrId: string
): Promise<Map<string, Transition[]>> {
// 获取当前状态的转换选项
const transitions = await getTransitions(client, issueKeyOrId);
console.log(`Available transitions from current state:`);
for (const t of transitions) {
console.log(` ${t.id}: ${t.name} → ${t.to.name}`);
if (t.fields?.resolution?.required) {
console.log(` (requires resolution)`);
}
}
return new Map([
['current', transitions]
]);
}Common Mistakes
常见错误
- Using transition ID without querying first
- Forgetting resolution when moving to Done
- Assuming transition IDs are same across projects
- Not handling 204 response (empty body is success)
- 未先查询就直接使用转换ID
- 转换到已完成状态时忘记设置解决结果
- 假设不同项目的转换ID相同
- 未正确处理204响应(空响应体代表成功)
References
参考资料
Version History
版本历史
- 2025-12-10: Created
- 2025-12-10: 创建