Trello로 완료된 티켓을 GAS로 자동 집계

5895 단어 trelloAPIgas
여러 회사나 프로젝트에 속하고 있지만, 자신이 얼마나 각각의 소속처에 대해 가치를 제공하고 있는지를 보이게 하고 싶어졌습니다.

개인적으로 작업 태스크의 관리는, Trello를 사용하고 있기 때문에 완료된 티켓의,
  • 가치 (피보나치 수열 포인트)
  • 작업 시간(예상)
  • 작업 시간 (실적)

  • 를 스프레드시트에 자동 집계해 보기로 했습니다.

    작업 시간의 예상과 실적을 모두 기록하고 있는 것은, 데이터가 어느 정도 모여 왔을 때에, 자신의 견적 제도를 정사해 보고 싶기 때문입니다.

    Trello 사용법



    라벨



    프로젝트별로 라벨을 만들고 있습니다. 라벨마다 집계를 하기 때문에 제 경우에는 1 카드에 1 라벨을 붙이도록 하고 있습니다. 또한 프로젝트와 관련이 없지만 "스킬"과 "LifeHack"의 라벨도 준비되어 있습니다.

    리스트



    제 경우에는 팀이 아닌 개인에서 사용하고 있으므로 목록을 다음과 같이 나누고 있습니다.
    - 기표 (IceBox에 가깝다, 생각하면 일단 기표 해 둔다)
    - 작업 중 (InProgress, 상대가 있거나 대기 상태이거나 하고 있지만 착수는 하고 있는 것)
    - 이번 주에 끝내기 (이번 주에 성과를 내고 싶은 것)
    - 습관화 중 (작업이 아니라 매일의 루틴에 섭취하고 싶은 좋은 행동, 주간이 되면 완료로 한다)
    - 완료(Done)



    카드 항목



    기본값으로 '포인트', '작업 시간(예상)', '근무 시간(실적)'을 입력할 수 없으므로 CustomFilter를 추가합니다. 어쩌면 이것은 유료 버전이 아니더라도 사용할 수있는 것 같습니다.



    스프레드시트로 보이기(집계)



    Trello에서 완료 목록에 들어있는 카드를 가져와 스프레드 시드에 열 데이터로 만듭니다. 다음은 그 데이터를 그래프로 집계하고 있는 것입니다. 그래프 자체는 GAS가 아닌 데이터 시트를 기반으로 스플릿 시트의 표 기능으로 표시하고 있습니다.



    아직 움직였을 뿐이므로, 조금 맛있습니다만, 음, 라이프 해크만 하고 있다. . .

    GAS



    TrelloAPI 을 사용하여 스플릿 시트로 데이터를 전환합니다.

    프로젝트 트리거는 시간 수동으로 2시간마다 설정을 합니다.

    다음은 코드입니다.

    Trello의 APIKey와 Token은 여기에서 얻을 수 있습니다.
    h tps : // t ぉ. 코 m / 1 / 아 p y / 게네라 테
    const SHEET = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('データ');
    
    const TRELLO_API_KEY = '[api key]'
    const TRELLO_API_TOKEN = '[api token]'
    const BOAD_ID = '[boad id]'
    
    const POINT_CUSTOM_FILED_ID = '[カスタムフィールド(ポイント)のID]'
    const EXPECTED_WORKING_HOURS_CUSTOM_FILED_ID = '[カスタムフィールド(作業時間・予想)のID]'
    const PERFORM_WORKING_HOURS_CUSTOM_FILED_ID = '[カスタムフィールド(作業時間・実績)のID]'
    
    const LIST_NAME = '完了'
    const LABELS = ['スキル', 'LifeHack.', 'プロジェクト1', 'プロジェクト2', 'プロジェクト3', 'プロジェクト4' ]
    
    const ID_COL = 1
    const LABEL_COL = 2
    const NAME_COL = 3
    const CLOSED_DATE_COL = 4
    const POINT_COL = 5
    const EXPECTED_WORKING_HOURS_COL = 6
    const ERFORM_WORKING_HOURS_COL = 7
    
    const INIT_ROW = 2
    
    function myFunction() {
      let list = get_list()
      let trelloCardIds = get_card_ids(list)
      let sheetCardIds = SHEET.getRange(1, 1, SHEET.getDataRange().getLastRow()).getValues().flat()
    
      let newClosedCardIds = trelloCardIds.filter(i => sheetCardIds.indexOf(i) == -1)
    
      newClosedCardIds.forEach(function(cardId) {
        lastRow = SHEET.getDataRange().getLastRow()
    
        if (lastRow === 1) {
          create_workLog(cardId, INIT_ROW)
        } else {
          create_workLog(cardId, lastRow+1)
        }
      })
    }
    
    function get_list() {
      let listUrl = 'https://api.trello.com/1/boards/' + BOAD_ID + '/lists?key=' + TRELLO_API_KEY + '&token=' + TRELLO_API_TOKEN + '&fields=name'
      let jsonLists = UrlFetchApp.fetch(listUrl, {'method':'get'})
      let lists = JSON.parse(jsonLists.getContentText())
    
      let list = lists.find(function(l) {
        return l.name === LIST_NAME
      })
    
      return list
    }
    
    function get_card_ids(list) {
      let cardUrl = "https://trello.com/1/lists/" + list.id + "/cards?key=" + TRELLO_API_KEY + "&token=" + TRELLO_API_TOKEN + "&fields=name"
      let jsonCards = UrlFetchApp.fetch(cardUrl, {'method':'get'})
      let cards = JSON.parse(jsonCards.getContentText())
    
      let card_ids = Array()
      cards.forEach(function(card) {
        card_ids.push(card.id)
      })
    
      return card_ids
    }
    
    function create_workLog(card_id, row) {
      Logger.log(card_id)
    
      let today = new Date();
    
      let cardUrl = "https://trello.com/1/cards/" + card_id + "?key=" + TRELLO_API_KEY + "&token=" + TRELLO_API_TOKEN + "&fields=name,dateLastActivity,labels&customFieldItems=true"
      let jsonCard = UrlFetchApp.fetch(cardUrl, {'method':'get'})
      let card = JSON.parse(jsonCard.getContentText())
    
      let labels = ''
      card.labels.forEach(function(label) {
        labels += label['name'] + ', '
      })
    
      SHEET.getRange(row, ID_COL).setValue(card.id);
      SHEET.getRange(row, LABEL_COL).setValue(labels);
      SHEET.getRange(row, NAME_COL).setValue(card.name);
      SHEET.getRange(row, CLOSED_DATE_COL).setValue(today);
    
      card.customFieldItems.forEach(function(item) {
        if (item['idCustomField'] === POINT_CUSTOM_FILED_ID) {
          SHEET.getRange(row, POINT_COL).setValue(item['value']['number'])
    
        } else if (item['idCustomField'] === EXPECTED_WORKING_HOURS_CUSTOM_FILED_ID) {
          SHEET.getRange(row, EXPECTED_WORKING_HOURS_COL).setValue(item['value']['number'])
    
        } else if (item['idCustomField'] === PERFORM_WORKING_HOURS_CUSTOM_FILED_ID) {
          SHEET.getRange(row, ERFORM_WORKING_HOURS_COL).setValue(item['value']['number'])
    
        }
      })
    }
    

    요약



    이 예는, 사용법이 너무 지나치게 너무 많은 사람에게는 사용되지 않는다고 생각합니다만, 서버리스로 빨리 스크립트를 써, 조금이라도 나날의 작업의 카이젠을 할 수 있으면, 개인적으로는 동기 부여가 올라 합니다.

    좋은 웹페이지 즐겨찾기