jira-agile

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Jira Agile Skill

Jira Agile Skill

Purpose

用途

Manage Jira Agile boards and sprints - list boards, manage sprints, move issues to sprints.
管理Jira Agile看板与Sprint——列出看板、管理Sprint、将问题移入/移出Sprint。

When to Use

使用场景

  • Listing Scrum/Kanban boards
  • Managing sprints (create, start, end)
  • Moving issues to/from sprints
  • Getting sprint issues
  • 列出Scrum/Kanban看板
  • 管理Sprint(创建、启动、结束)
  • 将问题移入/移出Sprint
  • 获取Sprint中的问题

Prerequisites

前提条件

  • Authenticated JiraClient (see jira-auth skill)
  • Board/sprint management permissions
  • Note: Uses
    /rest/agile/1.0/
    NOT
    /rest/api/3/
  • 已认证的JiraClient(详见jira-auth技能)
  • 拥有看板/Sprint管理权限
  • 注意:使用
    /rest/agile/1.0/
    而非
    /rest/api/3/

Implementation Pattern

实现模式

Step 1: Create Agile Client Extension

步骤1:创建Agile客户端扩展

typescript
class JiraAgileClient extends JiraClient {
  async agileRequest<T>(path: string, options: RequestInit = {}): Promise<T> {
    const url = `${this.baseUrl}/rest/agile/1.0${path}`;
    const response = await fetch(url, {
      ...options,
      headers: { ...this.headers, ...options.headers },
    });

    if (!response.ok) {
      const error = await response.json().catch(() => ({}));
      throw new Error(`Jira Agile API error: ${response.status} - ${JSON.stringify(error)}`);
    }

    return response.json();
  }
}
typescript
class JiraAgileClient extends JiraClient {
  async agileRequest<T>(path: string, options: RequestInit = {}): Promise<T> {
    const url = `${this.baseUrl}/rest/agile/1.0${path}`;
    const response = await fetch(url, {
      ...options,
      headers: { ...this.headers, ...options.headers },
    });

    if (!response.ok) {
      const error = await response.json().catch(() => ({}));
      throw new Error(`Jira Agile API error: ${response.status} - ${JSON.stringify(error)}`);
    }

    return response.json();
  }
}

Step 2: List Boards

步骤2:列出看板

typescript
interface Board {
  id: number;
  self: string;
  name: string;
  type: 'scrum' | 'kanban';
  projectKey?: string;
}

interface BoardsResponse {
  values: Board[];
  startAt: number;
  maxResults: number;
  total: number;
  isLast: boolean;
}

async function listBoards(
  client: JiraAgileClient,
  options: {
    type?: 'scrum' | 'kanban';
    projectKeyOrId?: string;
    maxResults?: number;
  } = {}
): Promise<Board[]> {
  const params = new URLSearchParams();
  if (options.type) params.set('type', options.type);
  if (options.projectKeyOrId) params.set('projectKeyOrId', options.projectKeyOrId);
  if (options.maxResults) params.set('maxResults', String(options.maxResults));

  const response = await client.agileRequest<BoardsResponse>(
    `/board?${params.toString()}`
  );
  return response.values;
}
typescript
interface Board {
  id: number;
  self: string;
  name: string;
  type: 'scrum' | 'kanban';
  projectKey?: string;
}

interface BoardsResponse {
  values: Board[];
  startAt: number;
  maxResults: number;
  total: number;
  isLast: boolean;
}

async function listBoards(
  client: JiraAgileClient,
  options: {
    type?: 'scrum' | 'kanban';
    projectKeyOrId?: string;
    maxResults?: number;
  } = {}
): Promise<Board[]> {
  const params = new URLSearchParams();
  if (options.type) params.set('type', options.type);
  if (options.projectKeyOrId) params.set('projectKeyOrId', options.projectKeyOrId);
  if (options.maxResults) params.set('maxResults', String(options.maxResults));

  const response = await client.agileRequest<BoardsResponse>(
    `/board?${params.toString()}`
  );
  return response.values;
}

Step 3: Get Board Sprints

步骤3:获取看板中的Sprint

typescript
interface Sprint {
  id: number;
  self: string;
  state: 'future' | 'active' | 'closed';
  name: string;
  startDate?: string;
  endDate?: string;
  goal?: string;
}

async function getBoardSprints(
  client: JiraAgileClient,
  boardId: number,
  state?: 'future' | 'active' | 'closed' | string
): Promise<Sprint[]> {
  const params = state ? `?state=${state}` : '';
  const response = await client.agileRequest<{ values: Sprint[] }>(
    `/board/${boardId}/sprint${params}`
  );
  return response.values;
}
typescript
interface Sprint {
  id: number;
  self: string;
  state: 'future' | 'active' | 'closed';
  name: string;
  startDate?: string;
  endDate?: string;
  goal?: string;
}

async function getBoardSprints(
  client: JiraAgileClient,
  boardId: number,
  state?: 'future' | 'active' | 'closed' | string
): Promise<Sprint[]> {
  const params = state ? `?state=${state}` : '';
  const response = await client.agileRequest<{ values: Sprint[] }>(
    `/board/${boardId}/sprint${params}`
  );
  return response.values;
}

Step 4: Get Sprint Issues

步骤4:获取Sprint中的问题

typescript
interface SprintIssue {
  id: string;
  key: string;
  self: string;
  fields: {
    summary: string;
    status: { name: string };
    assignee?: { displayName: string };
  };
}

async function getSprintIssues(
  client: JiraAgileClient,
  sprintId: number,
  options: {
    maxResults?: number;
    startAt?: number;
  } = {}
): Promise<SprintIssue[]> {
  const params = new URLSearchParams();
  if (options.maxResults) params.set('maxResults', String(options.maxResults));
  if (options.startAt) params.set('startAt', String(options.startAt));

  const response = await client.agileRequest<{ issues: SprintIssue[] }>(
    `/sprint/${sprintId}/issue?${params.toString()}`
  );
  return response.issues;
}
typescript
interface SprintIssue {
  id: string;
  key: string;
  self: string;
  fields: {
    summary: string;
    status: { name: string };
    assignee?: { displayName: string };
  };
}

async function getSprintIssues(
  client: JiraAgileClient,
  sprintId: number,
  options: {
    maxResults?: number;
    startAt?: number;
  } = {}
): Promise<SprintIssue[]> {
  const params = new URLSearchParams();
  if (options.maxResults) params.set('maxResults', String(options.maxResults));
  if (options.startAt) params.set('startAt', String(options.startAt));

  const response = await client.agileRequest<{ issues: SprintIssue[] }>(
    `/sprint/${sprintId}/issue?${params.toString()}`
  );
  return response.issues;
}

Step 5: Move Issues to Sprint

步骤5:将问题移入Sprint

typescript
async function moveIssuesToSprint(
  client: JiraAgileClient,
  sprintId: number,
  issueKeys: string[],
  options: {
    rankBeforeIssue?: string;
    rankAfterIssue?: string;
  } = {}
): Promise<void> {
  await client.agileRequest(`/sprint/${sprintId}/issue`, {
    method: 'POST',
    body: JSON.stringify({
      issues: issueKeys,
      ...options,
    }),
  });
}
typescript
async function moveIssuesToSprint(
  client: JiraAgileClient,
  sprintId: number,
  issueKeys: string[],
  options: {
    rankBeforeIssue?: string;
    rankAfterIssue?: string;
  } = {}
): Promise<void> {
  await client.agileRequest(`/sprint/${sprintId}/issue`, {
    method: 'POST',
    body: JSON.stringify({
      issues: issueKeys,
      ...options,
    }),
  });
}

Step 6: Create Sprint

步骤6:创建Sprint

typescript
interface CreateSprintInput {
  name: string;
  boardId: number;
  startDate?: string;
  endDate?: string;
  goal?: string;
}

async function createSprint(
  client: JiraAgileClient,
  input: CreateSprintInput
): Promise<Sprint> {
  return client.agileRequest<Sprint>('/sprint', {
    method: 'POST',
    body: JSON.stringify({
      name: input.name,
      originBoardId: input.boardId,
      startDate: input.startDate,
      endDate: input.endDate,
      goal: input.goal,
    }),
  });
}
typescript
interface CreateSprintInput {
  name: string;
  boardId: number;
  startDate?: string;
  endDate?: string;
  goal?: string;
}

async function createSprint(
  client: JiraAgileClient,
  input: CreateSprintInput
): Promise<Sprint> {
  return client.agileRequest<Sprint>('/sprint', {
    method: 'POST',
    body: JSON.stringify({
      name: input.name,
      originBoardId: input.boardId,
      startDate: input.startDate,
      endDate: input.endDate,
      goal: input.goal,
    }),
  });
}

Step 7: Start/End Sprint

步骤7:启动/结束Sprint

typescript
async function startSprint(
  client: JiraAgileClient,
  sprintId: number,
  startDate: string,
  endDate: string
): Promise<void> {
  await client.agileRequest(`/sprint/${sprintId}`, {
    method: 'POST',
    body: JSON.stringify({
      state: 'active',
      startDate,
      endDate,
    }),
  });
}

async function endSprint(
  client: JiraAgileClient,
  sprintId: number
): Promise<void> {
  await client.agileRequest(`/sprint/${sprintId}`, {
    method: 'POST',
    body: JSON.stringify({
      state: 'closed',
    }),
  });
}
typescript
async function startSprint(
  client: JiraAgileClient,
  sprintId: number,
  startDate: string,
  endDate: string
): Promise<void> {
  await client.agileRequest(`/sprint/${sprintId}`, {
    method: 'POST',
    body: JSON.stringify({
      state: 'active',
      startDate,
      endDate,
    }),
  });
}

async function endSprint(
  client: JiraAgileClient,
  sprintId: number
): Promise<void> {
  await client.agileRequest(`/sprint/${sprintId}`, {
    method: 'POST',
    body: JSON.stringify({
      state: 'closed',
    }),
  });
}

curl Examples

curl示例

List Boards

列出看板

bash
curl -X GET "https://mycompany.atlassian.net/rest/agile/1.0/board?type=scrum" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Accept: application/json"
bash
curl -X GET "https://mycompany.atlassian.net/rest/agile/1.0/board?type=scrum" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Accept: application/json"

Get Board Sprints

获取看板中的Sprint

bash
curl -X GET "https://mycompany.atlassian.net/rest/agile/1.0/board/1/sprint?state=active,future" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Accept: application/json"
bash
curl -X GET "https://mycompany.atlassian.net/rest/agile/1.0/board/1/sprint?state=active,future" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Accept: application/json"

Move Issues to Sprint

将问题移入Sprint

bash
curl -X POST "https://mycompany.atlassian.net/rest/agile/1.0/sprint/1/issue" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Content-Type: application/json" \
  -d '{"issues": ["PROJ-123", "PROJ-124"]}'
bash
curl -X POST "https://mycompany.atlassian.net/rest/agile/1.0/sprint/1/issue" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Content-Type: application/json" \
  -d '{"issues": ["PROJ-123", "PROJ-124"]}'

Create Sprint

创建Sprint

bash
curl -X POST "https://mycompany.atlassian.net/rest/agile/1.0/sprint" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Content-Type: application/json" \
  -d '{"name": "Sprint 1", "originBoardId": 1, "goal": "Complete MVP"}'
bash
curl -X POST "https://mycompany.atlassian.net/rest/agile/1.0/sprint" \
  -H "Authorization: Basic $(echo -n 'email:token' | base64)" \
  -H "Content-Type: application/json" \
  -d '{"name": "Sprint 1", "originBoardId": 1, "goal": "Complete MVP"}'

API Endpoints Summary

API端点汇总

OperationMethodPath
List boardsGET
/board
Get boardGET
/board/{boardId}
Get board sprintsGET
/board/{boardId}/sprint
Get sprintGET
/sprint/{sprintId}
Create sprintPOST
/sprint
Update sprintPUT
/sprint/{sprintId}
Delete sprintDELETE
/sprint/{sprintId}
Get sprint issuesGET
/sprint/{sprintId}/issue
Move issues to sprintPOST
/sprint/{sprintId}/issue
操作方法路径
列出看板GET
/board
获取看板GET
/board/{boardId}
获取看板中的SprintGET
/board/{boardId}/sprint
获取SprintGET
/sprint/{sprintId}
创建SprintPOST
/sprint
更新SprintPUT
/sprint/{sprintId}
删除SprintDELETE
/sprint/{sprintId}
获取Sprint中的问题GET
/sprint/{sprintId}/issue
将问题移入SprintPOST
/sprint/{sprintId}/issue

Common Mistakes

常见错误

  • Using
    /rest/api/3/
    instead of
    /rest/agile/1.0/
  • Trying to add issues to closed sprints
  • Kanban boards don't have sprints
  • Sprint IDs are board-specific
  • 使用
    /rest/api/3/
    而非
    /rest/agile/1.0/
  • 尝试向已关闭的Sprint添加问题
  • Kanban看板没有Sprint
  • Sprint ID是看板专属的

References

参考资料

Version History

版本历史

  • 2025-12-10: Created
  • 2025-12-10:创建