Node.js에서 Jira의 API에서 과제 정보 얻기

26361 단어 Jiratech

모티프

  • 지라의 과제에 스토리포인트를 설정했지만 지라의 화면에서만 필요한 형식으로 필요한 정보를 얻기 위해 미완성
  • 이번 단거리와 지난번 단거리가 얼마나 소화되는지 궁금하다(지라의 기본 기능에도 있지만 다양한 축소 조건을 정하고 싶다)
  • 프로젝트 전체의 StoryPoint를 소화하기 위해 또 어떤 단거리 경주의 필요성이 있는지 알고 싶다(프로젝트의 예측을 수치로 보고하기 위해)

  • Jira의 과제를 Excel로 출력하는 플러그인 있긴 하지만 데이터가 복잡해서 Excel에서 노력하는 것보다 API로 얻고 TypeScript로 하는 게 더 간단해
  • 이 같은 이유로 지라의 API에서 과제를 얻기로 했다.

    API 토큰 만들기


    먼저 API 토큰을 생성합니다.
    JIRA 화면 오른쪽 상단 프로필을 클릭
      ↓
    클릭하여 설정
      ↓
    계정 설정 클릭(계정 환경 설정)
      ↓
    왼쪽의 보안 탭을 클릭합니다.
      ↓
    API 토큰 생성 및 관리 클릭
      ↓
    클릭하여 API 토큰을 만듭니다.
    API 토큰을 만들고 복사합니다.

    jira-client로 액세스


    Jira의 API 사용jira-client 두드리기.
    npm i dotenv
    npm i jira-client
    npm i -D @types/jira-client
    
    .env는 파일에 다음과 같은 내용을 준비한다.
    JIRA_HOST="[会社のアカウント].atlassian.net"
    MAIL_ADDRESS="ユーザー名に使っているメールアドレス"
    JIRA_API_TOKEN="設定画面から取得したAPIトークン"
    PROJECT_NAME="Jiraのプロジェクト名。 課題のJQLでproject = 'XXX'で指定されているやつ"
    
    API에서 Jira과제의 샘플을 얻은 것은 다음과 같다.
    import JiraApi, { JsonResponse } from "jira-client";
    import dotenv from "dotenv";
    
    dotenv.config();
    
    const host = process.env.JIRA_HOST;
    const mailAddress = process.env.MAIL_ADDRESS;
    const apiToken = process.env.JIRA_API_TOKEN;
    const projectName = process.env.PROJECT_NAME;
    
    let jiraClient: JiraApi | undefined;
    function getJiraClient() {
      if (
        host === undefined ||
        mailAddress === undefined ||
        apiToken === undefined
      ) {
        throw new Error("環境変数が設定されていません。");
      }
      if (jiraClient === undefined) {
        jiraClient = new JiraApi({
          protocol: "https",
          host,
          username: mailAddress,
          password: apiToken,
          apiVersion: "2",
          strictSSL: true,
        });
      } else {
        console.log("jiraClient はキャッシュされています。");
      }
      return jiraClient;
    }
    
    export async function getAllIssues() {
      const client = getJiraClient();
      if (client === undefined) {
        throw new Error("jiraClient が生成されていません。");
      }
    
      if (projectName === undefined) {
        throw new Error("プロジェクト名が環境変数に設定されていません。");
      }
      const jql = `project = "${projectName}" ORDER BY created DESC`;
    
      const jiraResponse: JsonResponse = await client.searchJira(jql, {
        startAt: 0,
        maxResults: 10,
      });
    
      const jira: Jira = {
        startAt: jiraResponse.startAt,
        maxResults: jiraResponse.maxResults,
        total: jiraResponse.total,
        issues: jiraResponse.issues,
      };
    
      console.log(jira.total);
    }
    
    아래 부분에 maxResults를 설치했습니다.
    최대100.
    await client.searchJira(jql, {
      startAt: 1,
      maxResults: 10,
    });
    
    따라서 100개 이상의 과제를 모두 따내려면 요청(total / maxResults) + 1건을 제출해야 한다.

    Jira의 반응에서 필요한 것을 정형화하다


    지라의 반응은 니형이 정의했다.
    유형 정의는 다음과 같습니다.
    interface JsonResponse {
      [name: string]: any;
    }
    
    반응을 실제로 봤더라도 다음과 같은 불정형적인 속성으로 여겨지는 경우가 많다.
    customfield_10128: null,
    customfield_10007: null,
    customfield_10129: null,
    
    이러한 필드 이름에는 자체 프로젝트 뿐만 아니라 회사 내 다른 프로젝트에 설정된 필드도 포함됩니다.
    사내 프로젝트 간 지라의 사용법이 통일되지 않으면 자신의 프로젝트에 필요 없는(다른 프로젝트로 제작된) 맞춤형 필드가 대거 혼입된다는 것이다.
    내 프로젝트에 사용되지 않은 필드 값은 null입니다.
    그 밖에 issuesfields, 그fields가 가지고 있는 parentissue는 같은 유형으로 사용하기 어렵고 다양한 필드가 끼워져 있어 사용하기 어렵다.
    따라서 스스로 유형을 정의하고 그에 상응하는 반응을 형식적으로 적용하면 API로 얻은 데이터가 수월해진다.
    업무상 정보가 들어오지 않도록 코드를 발췌하면 이런 모양으로 만들어진다.
    lib/types/index.ts
    
    export type Jira = {
      startAt: number
      maxResults: number
      total: number
      issues: Issue[]
    }
    
    export type Issue = {
      id: string
      key: string
      fields: Fields
    }
    
    export type Fields = {
      parent: Parent
      summary: string
      status: Status
      targetServices: TargetService[] // ここは会社特有のもの。fields.customfield_xxxx の値を入れる
      sprints: Sprint[]
      storyPoint: number  // fields.customfield_yyyy の値を入れる
      created: string
      updated: string
      description: string
      statuscategorychangedate: string
    }
    
    위의 유형의 작업은 속성(필드)이 정해지지 않기 때문에 응답의 값을 보면서 각자 설정하려고 노력합니다.
    열심히 정형한 샘플은 다음과 같은 인상을 가지고 있다.
    lib/issues.ts
    // サンプルです
    function otharfunc() {
      const jira: Jira = {
        startAt: jiraResponse.startAt,
        maxResults: jiraResponse.maxResults,
        total: jiraResponse.total,
        issues: jiraResponse.issues,
      }
    
      // 型をつける関数を呼んでる
      const typedJira = getTypedJira(jira)
    }
    
    
    
    function getTypedJira(jira: any): Jira {
      const typedIssues: Issue[] = jira.issues.map((issue: Issue) => {
        const fields: any = issue.fields
        const sprints = fields.customfield_xxxx.map((sprint: any) => {
          return {
            name: sprint.name,
            state: sprint.state,
            startDate: sprint.startDate,
            endDate: sprint.endDate,
          }
        })
        const typedFields: Fields = {
          parent: {
            summary: fields.parent.fields.summary,
          },
          summary: fields.summary,
          status: fields.status,
          targetServices: fields.customfield_xxxx,
          sprints,
          storyPoint: fields.customfield_yyy,
          created: fields.created,
          updated: fields.updated,
          description: fields.description,
          statuscategorychangedate: fields.statuscategorychangedate,
        }
        return {
          id: issue.id,
          key: issue.key,
          fields: typedFields,
        }
      })
      const typedJira: Jira = {
        startAt: jira.startAt,
        maxResults: jira.maxResults,
        total: jira.total,
        issues: typedIssues,
      }
      return typedJira
    }
    
    
    위의 예에서 덧붙임형typedJira은 원지라의 반응을 반영한 형식으로 많이 끼워서 사용하기 어렵다.
    따라서 자신은typedJiraissues[n].fields에서 진정으로 원하는 정보를 얻어 다른 대상에 넣고 사용한다(문장 전달이 어렵다)
    기사에 코드의 예를 담고 싶지만 여기까지 오면 일에 너무 의존하기 때문에 울면서 사랑을 끊을 수밖에 없다.
    각자의 느낌에 틀을 박아서 지라를 사용하는 게 반응이 좋을 것 같아요.
    또 개인의 노력점으로 틀을 붙인 지라의 반응을 먼저 캐시해 JSON 파일에 날짜를 적어 저장했다.
    지라에게 여러 번 요청해도 결과가 그렇게 자주 나오지 않기 때문이다.
    같은 날의 반응은 캐시에서 로컬 JSON 파일을 읽고 캐시가 없을 때 되돌아오는 것이다.

    좋은 웹페이지 즐겨찾기