[PYTHON] Regularly notify Slack of missed Backlog issues

Trigger

I always see Slack. I don't see much email or backlog. And forget about the issues assigned in Backlog. .. Alright, let's get in touch with Backlog issues that aren't Slack-enabled every morning. I wonder if I can pull the list of relevant issues from Google Apps Script with Backlog API and throw it to Slack.

Get issue information with Backlog API

How to get Backlog issue list is [Get official issue list](https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-list/#%E8%AA%B2% E9% A1% 8C% E4% B8% 80% E8% A6% A7% E3% 81% AE% E5% 8F% 96% E5% BE% 97) Since it is listed on the page, try to get it with GAS for reference. I will.

Backlog API key

Oops, before that, we'll get the Backlog API key. Click ** Personalization ** in the menu where you clicked your icon in the upper right corner of the Backlog page, and get it from ** API ** in the left menu. After getting the API key, hit the API from GAS immediately to get the list of issues.

function myFunction() {
  const baseUrl = 'https://xxxxx.backlog.jp';  //Backlog domain you are using
  const apiKey = 'xxxxxxxxxxxxxxxxxxxxxxx';  //API key obtained from Backlog
  const endpoint = '/api/v2/issues';  //URL listed in Obtaining the official issue list

  const url = baseUrl + endpoint + '?apiKey=' + apiKey;  //Make the URL to inquire
  const response = UrlFetchApp.fetch(url);  //Send HTTP request with fetch method
  const json = JSON.parse(response.getContentText());  //Extract text data

  Logger.log(json);  //Output to log
}

It was output to various logs. If this is the case, the amount of logs for each issue is too large to see, so we will temporarily display only the issue ID of each issue.

function myFunction() {
  const baseUrl = 'https://xxxxx.backlog.jp';  //Backlog domain you are using
  const apiKey = 'xxxxxxxxxxxxxxxxxxxxxxx';  //API key obtained from Backlog
  const endpoint = '/api/v2/issues';  //URL listed in Obtaining the official issue list

  const url = baseUrl + endpoint + '?apiKey=' + apiKey;  //Make the URL to inquire
  const response = UrlFetchApp.fetch(url);  //Send HTTP request with fetch method
  const json = JSON.parse(response.getContentText());  //Extract text data
  
  for (let i in json) {  //Turn the loop as many times as the number of tasks
    Logger.log(json[i]['issueKey']);  //Output issue ID to log
  }
}

It's easier to see because there are no extra logs, but since it is acquired for the entire Backlog, extra issues are mixed. Therefore, filter under the following conditions and acquire only the necessary issues.

Find the user ID of the person in charge

It seems that the user ID of the person in charge is required to narrow down the person in charge, but it seems that it does not work to output the user ID of the person in charge with GAS ... There is no help for it, so refer to How to find out the user ID (numerical value) using API in Backlog and hit Backlog API from Python to get the user ID. To do. In this method, you specify an issue and get the user ID of the person in charge of that issue, so you get the issue ID to specify the issue. That said, it's easy, it's at the end of the URL (xxxx-xx) when you open the issue. Specifically, it will be the bold part at the end of the issue URL. (Xx at the back is a number) xxxxx.backlog.jp/view/xxxx-xx Once you know the issue ID, get the user ID of the person in charge in Python.

import requests

baseUrl = 'https://xxxxx.backlog.jp';  #Backlog domain you are using
apiKey = 'xxxxxxxxxxxxxxxxxxxxxxx';  #API key obtained from Backlog
ticket_id = 'xxxx-xx'  #Issue ID

url = base_url + ticket_id  #Make the URL to inquire
json = requests.get(url, {'apiKey': apiKey}).json() #Extract text data

print(json['assignee']['id'])  #Output the user ID of the person in charge of the acquisition result

Narrow down by person in charge

Now that we know the user ID of the person in charge, we will narrow down by person in charge with GAS. Add & assigneeId [] = user ID of the person in charge to the parameter of the URL to be queried as shown below.

function myFunction() {
  const baseUrl = 'https://xxxxx.backlog.jp';
  const apiKey = 'xxxxxxxxxxxxxxxxxxxxxxx';
  const endpoint = '/api/v2/issues';

  const url = baseUrl + endpoint + '?apiKey=' + apiKey + '&assigneeId[]=' + xxxxxxx;  //Make the URL to inquire
  
//(Omitted below. Same as above.)
}

Narrow down by issue type

Next, narrow down by type (task, bug, request ..). The type is narrowed down by ʻissueTypeId. Checking the issueTypeId is also easy, click the type you want to check on the ** Type ** tab of ** Project Settings ** on the left menu of Backlog. It will be ** issueType.id ** in the URL of the edit page of the type displayed by clicking. Now that we know the issueTypeId, we will narrow it down by GAS. This adds ʻissueTypeId [] = issueType.id to the parameter of the query URL.

function myFunction() {
  const baseUrl = 'https://xxxxx.backlog.jp';
  const apiKey = 'xxxxxxxxxxxxxxxxxxxxxxx';
  const endpoint = '/api/v2/issues';

  const url = baseUrl + endpoint + '?apiKey=' + apiKey + '&assigneeId[]=' + xxxxxxx + '&issueTypeId[]=' + xxxxxxx;  //Make the URL to inquire
  
//(Omitted below. Same as above.)
}

Narrow down by issue status

At the end, narrow down by issue status (unsupported, processed, processed, completed). The status is narrowed down by statusId. The statusId can be checked using the API, but I think it is fixed below.

function myFunction() {
  const baseUrl = 'https://xxxxx.backlog.jp';
  const apiKey = 'xxxxxxxxxxxxxxxxxxxxxxx';
  const endpoint = '/api/v2/issues';

  const url = baseUrl + endpoint + '?apiKey=' + apiKey + '&assigneeId[]=' + xxxxxxx + '&issueTypeId[]=' + xxxxxxx + '&statusId[]=' + 1;  //Make the URL to inquire
  
//(Omitted below. Same as above.)
}

Send to Slack

Now that you have the information you need in the Backlog API, you can send it to Slack.

Slack Incoming Webhooks Settings

First, set the Webhooks required for sending Slack. I used to make Incoming Webhooks with Slack's custom integration, but now it seems that I will make an Slack app and set Incoming Webhooks as a function in it, so I will do it that way. (Reference: Slack custom integration is deprecated and [Slack's Incoming webhook was new, so I summarized it](https://qiita. com / kshibata101 / items / 0e13c420080a993c5d16)) In particular

  1. Go to https://api.slack.com/apps
  2. Click the ** Create New App ** button
  3. Enter the information of the Slack app you want to create and click the ** Create App ** button -** App Name : Slack app name to create - Development Slack Workspace **: Space to install the Slack app to create (select from the pull-down menu)
  4. Click ** Incoming Webhooks ** from the menu on the left
  5. Turn on Activate Incoming Webhooks
  6. Click the ** Add New Webhook to Workspace ** button
  7. Select the channel or DM you want to send Slack to and click the ** Allow ** button
  8. The following message is displayed on the corresponding Slack channel or DM

added an integration to this channel: * Set app name *

After setting up Incoming Webhooks, copy the URL of the Webhook. Set this URL in GAS to make it a Slack destination. The display name and image of the Slack app when Slack is notified by Incoming Webhooks can be set in ** Display Information ** of ** Basic Information ** in the left menu. To delete the Slack app, go to ** Basic Information **, ** Delete App **.

GAS code

Paste the obtained Webhook URL into ** postUrl ** and write as follows.

function sendSlack() {
  const postUrl = 'Obtained Webhook URL';
  
  const json = {
    'text': 'Message you want to send to Slack'
  };
  const payload = JSON.stringify(json);
  
  const options = {
    'method': 'post',
    'contentType': 'application/json',
    'payload': payload
  };
  
  UrlFetchApp.fetch(postUrl, options);
}

Since it is a promise, I will omit the explanation.

Change settings from spreadsheet

I'm using the spreadsheet GAS, so I tried using the spreadsheet itself. I made it possible to set as follows in the spreadsheet. スクリーンショット 2020-04-26 22.00.14.png I will narrow down by the ones checked on the spreadsheet.

//Get settings from spreadsheet
function getConfig() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const range = sheet.getRange(1, 1, 5, 2);
  const values = range.getValues();
  
  //Get status settings
  let statusId = '';
  for (let i in [...Array(4).keys()]) {
    let row = Number(i) + 1;
    if (true == values[row][0]) {
      statusId += '&statusId[]=' + row;
    }
  }
  return statusId;
}

Complete

It looks like this when all are combined.

const baseUrl = 'https://xxxxx.backlog.jp';
const apiKey = 'xxxxxxxxxxxxxxxxxxxxxxx';

function myFunction() {
  const statusId = getConfig();
  issues(statusId)
}

//Get a list of issues
function issues(statusId) {
  //Get a list of issues from Backlog
  const endpoint = '/api/v2/issues';
  const url = baseUrl + endpoint + '?apiKey=' + apiKey + statusId + '&issueTypeId[]=' + xxxxxx + '&assigneeId[]=' + xxxxxx;
  const resp = UrlFetchApp.fetch(url);
  const json = JSON.parse(resp.getContentText());
  
  //Extract necessary information (issue ID, issue subject, issue URL) from the issue list obtained from Backlog
  let message = '';
  for (let i in json) {
    const issueKey = json[i]['issueKey'];  //Issue ID
    const summary = json[i]['summary'];  //Issue subject
    message += issueKey + ' ' + summary + '\n' + baseUrl + '/view/' + issueKey;
    //If there are multiple issues, insert a line break for each loop
    if (json[i] != json[json.length - 1]) {
      message += '\n';
    }
  }
  //Pass the content (message) you want to send in Slack
  sendSlack(message);
}

//Send to Slack
function sendSlack(message) {
  //Test webhook URL
  const postUrl = 'Obtained Webhook URL';
  const json = {
    'text': message
  };
  const payload = JSON.stringify(json);
  const options = {
    'method': 'post',
    'contentType': 'application/json',
    'payload': payload
  };
  UrlFetchApp.fetch(postUrl, options);
}

//Get settings from spreadsheet
function getConfig() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const range = sheet.getRange(1, 1, 5, 2);
  const values = range.getValues();
  
  //Get status settings
  let statusId = '';
  for (let i in [...Array(4).keys()]) {
    let row = Number(i) + 1;
    if (true == values[row][0]) {
      statusId += '&statusId[]=' + row;
    }
  }
  return statusId;
}

If you set this to start at 9 am every morning with a trigger, the following notification will come to Slack every morning. スクリーンショット 2020-04-26 22.28.58.png

We're hiring! We are developing an AI chatbot. If you are interested, please feel free to contact us from the Wantedly page!

Reference article

[Getting a list of issues (official)](https://developer.nulab.com/ja/docs/backlog/api/2/get-issue-list/#%E8%AA%B2%E9%A1%8C% E4% B8% 80% E8% A6% A7% E3% 81% AE% E5% 8F% 96% E5% BE% 97) [Acquisition of issue information (official)](https://developer.nulab.com/ja/docs/backlog/api/2/get-issue/#%E8%AA%B2%E9%A1%8C%E6% 83% 85% E5% A0% B1% E3% 81% AE% E5% 8F% 96% E5% BE% 97) Slack Custom Integration Deprecated Slack's Incoming webhook was new, so I summarized it How to find out the user's ID (numerical value) using API in Backlog Add issues with Backlog API using Python

Recommended Posts

Regularly notify Slack of missed Backlog issues
Notify Slack of GitHub push
Notify Slack of how Keras is learning
I tried to notify slack of Redmine update
Notify Slack of process state changes using Supervisor's EventListener
Post images of Papillon regularly on Python + AWS Lambda + Slack