[PYTHON] I tried to notify slack of Redmine update

Introduction

This time, I decided to notify slack of Redmine ticket update in business, so I will summarize it.

Background of correspondence

My company uses Redmine for outsourcing a certain business, but when there is a remand from the outsourcer, the response to the ticket is slow! !! It was often said (although the words are a little softer ...).

After that, when I searched for the cause, it seemed that the main cause was ** I didn't notice the remand ** </ font> in the first place.

Well, you can only catch notifications when you renew your ticket on Redmine by email. .. I understand that feeling ...! If you can set notifications like Backlog, you will notice it even when you are still doing other work, but of course there is no such function.

I was wondering what to do, but if I get a notification to ** slack **, which is very active as a business chat tool at our company, I think I will notice it. I thought that I made this function.

This requirement

  1. Notify slack of tickets updated to a specific status in Redmine
  • Real-time cooperation if possible
  • The content of the notification is the title of Redmine and the link to the person in charge ticket. (I'm just expecting it to get confused if I notify slack of the remand content. It's important to notice first)

First, look for something that could be used with existing integration

Immediately came out https://www.sejuku.net/blog/852461 This article

Use RSS app

Result: ✕ Since the Redmine used by us is created in the intranet, I gave up because I can not connect to Redmine from slack using RSS in the first place.

Use Redmine plugin

Result: ✕ Notifying slack with a webhook using a plugin called "Redmine Slack" The content of this was exactly what I wanted to do this time, but the trigger is ** only when a new ticket is created ... **. It's delicious ... (Since it is a plug-in that seems to be in demand like this, I wanted you to have a little more freedom ...)

Correspondence policy

Finally, use Redmine API to actively acquire data (tickets) that meet the conditions and notify slack of it. I settled down to the correspondence. Since I hit the API as I like, it seems to be highly versatile in the future.

Requirements definition again

  1. Notify once every 30 minutes (run batch once every 30 minutes)
  2. Condition: Get a ticket with ticket status "Return" and renewal time within 30 minutes
  3. Items to be notified by slack are ticket number, URL, title, person in charge

Implementation details

Creating a processing Python file

sashimodoshi.py


# -*- coding: utf-8 -*-
import digdag
import requests
import sys
import os
from datetime import datetime, timedelta
import json

sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from .utils.util_slacker import UtilSlacker

class Main():
    def __init__(self, incoming_webhook_url, slack_token):
        self.incoming_webhook_url = incoming_webhook_url
        self.slack_token = slack_token
        self.slacker = UtilSlacker(self.incoming_webhook_url, self.slack_token)
    
    def main(self):
        redmine_api_key = "API access key" # 個人設定>API access keyから取得
        redmine_url = "http://URL of redmine"

        #Update date within 30 minutes
        now = datetime.utcnow() + timedelta(minutes=-30)
        now = now.strftime('%Y-%m-%dT%H:%M:%SZ')

        request_url_for_issues = redmine_url + "/issues.json"
        params = {
            "key": redmine_api_key,
            "project_id": "dd",
            "status_id": 4,
            "updated_on": ">=" + now
        }
        issues_res = requests.get(request_url_for_issues, params)
        issues_responses = json.loads(issues_res.text)
        print(issues_responses)

        fields = []

        if len(issues_responses["issues"]) == 0: #If it is 0, it will be processed
            return

        for issue in issues_responses["issues"]:
           issue_id = issue["id"]
           subject = issue["subject"]
           assigned_to_name = issue["assigned_to"]["name"]

           field = {
               "title": subject,
               "value": "Person in charge:" + assigned_to_name + "\r\nlink:<" + redmine_url + "/issues/{0}|{0}>".format(issue_id),
           }
           print(field)
           fields.append(field)

        msg = "`Remand`I have a ticket for.\r\n Please check the person in charge."
        channel = "#pj-〇〇"
        user = "redmine remand notification"
        icon_emoji = ":redmine:"
        fallback = "redmine"
        title = ""

        attachment1 = self.slacker.attachment_creater(
            fallback=fallback, title=title, color="danger", fields=fields)
        attachments = [attachment1]
        self.slacker.slack_messenger(
            msg, channel, user, icon_emoji, is_link_name=1, attachments=attachments)

I call this process in batch, but since we already have a digdag server, we decided to run it on it.

sashimodoshi.dig


timezone: Asia/Tokyo

schedule:
  cron>: 00,30 10-18 * * 1-5
  weekly>: Thu,10:30:00

_export:
  workflow_name: "sashimodoshi"

+sashimodoshi:
   py>: bin.python_project.sashimodoshi.Main.main
   incoming_webhook_url: ${env.incoming_webhook_url}
   slack_token: ${env.slack_token}

The dig file looks like this. In the schedule settings, it is set to run for 30 minutes between 10:00 and 18:00 from Monday to Friday. (I'm just imitating this place, but I haven't caught up with my understanding yet ...)

Actual slack notification

The implementation image looks like this. image.png I'm using attachment in the slack notification API this time, and it looks good!

Afterword

This time, we implemented slack notification with momentum to improve work efficiency and automation, but as a remaining issue

  • API key should be issued with a general-purpose account for notification, not a personal account of Redmine
  • Setting information should not be written in a Python file in the first place

It's around, so I'll fix it soon.

This is the first time I've touched Python properly, but I'm still studying because it seems that it will continue to play an active role in terms of work efficiency and automation, such as being able to connect APIs quickly and in some cases Excel operations. I will go! !!

Recommended Posts

I tried to notify slack of Redmine update
I tried to notify the update of "Hamelin" using "Beautiful Soup" and "IFTTT"
I tried to notify the update of "Become a novelist" using "IFTTT" and "Become a novelist API"
I tried to notify Zabbix Server of execution error of AWS Lambda function
I tried to find 100 million digits of pi
I tried to touch the API of ebay
I tried to correct the keystone of the image
I tried to debug.
I tried to paste
I tried to predict the price of ETF
I tried to vectorize the lyrics of Hinatazaka46!
I made a tool to notify Slack of Connpass events and made it Terraform
I tried to extract features with SIFT of OpenCV
I tried to summarize how to use matplotlib of python
I tried to summarize the basic form of GPLVM
I tried to visualize the spacha information of VTuber
I tried to erase the negative part of Meros
[Python] I tried to get Json of squid ring 2
I tried to notify the honeypot report on LINE
I tried to implement automatic proof of sequence calculation
I tried to classify the voices of voice actors
I tried to summarize the string operations of Python
I tried to learn PredNet
I tried to organize SVM.
I tried to implement PCANet
Notify Slack of GitHub push
I tried to reintroduce Linux
I tried to introduce Pylint
I tried to summarize SparseMatrix
I tried to touch jupyter
I tried to implement StarGAN (1)
I tried using Slack emojinator
I tried to automate the article update of Livedoor blog with Python and selenium.
I tried to find the entropy of the image with python
[Horse Racing] I tried to quantify the strength of racehorses
I tried to get the location information of Odakyu Bus
I tried to find the average of the sequence with TensorFlow
I tried to notify the train delay information with LINE Notify
I tried adding post-increment to CPython. List of all changes
[Python] I tried to visualize the follow relationship of Twitter
I tried to implement ListNet of rank learning with Chainer
[Machine learning] I tried to summarize the theory of Adaboost
I tried to fight the Local Minimum of Goldstein-Price Function
I tried to implement blackjack of card game in Python
[Natural language processing] I tried to visualize the remarks of each member in the Slack community
I tried to implement Deep VQE
I tried to create Quip API
I tried to touch Python (installation)
I tried using GrabCut of OpenCV
I tried to implement adversarial validation
I tried to explain Pytorch dataset
I tried Watson Speech to Text
I tried to touch Tesla's API
I tried to implement hierarchical clustering
I tried to organize about MCMC.
I tried to implement Realness GAN
I tried to move the ball
I tried to estimate the interval.
I tried to create an environment of MkDocs on Amazon Linux
[Linux] I tried to summarize the command of resource confirmation system
I tried to get a database of horse racing using Pandas