From 47248968fc2716486c2a055877028fe6da1891c7 Mon Sep 17 00:00:00 2001 From: Ching Date: Thu, 21 Mar 2024 14:59:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8F=90=E4=BA=A4=20commit=20=E6=97=B6?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E5=85=B3=E8=81=94=20linear=20issue=20TUN-24?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index d692317..bd94890 100644 --- a/app.py +++ b/app.py @@ -1,7 +1,10 @@ -from flask import Flask, request, jsonify -import apprise import os +import re + +import apprise +from flask import Flask, request, jsonify from loguru import logger +import requests import sentry_sdk @@ -9,6 +12,8 @@ DISCORD_WEBHOOK_URL = os.environ.get('DISCORD_WEBHOOK_URL') DISCORD_WEBHOOK_ID = DISCORD_WEBHOOK_URL.split('/')[-2] DISCORD_WEBHOOK_TOKEN = DISCORD_WEBHOOK_URL.split('/')[-1] SENTRY_DSN = os.environ.get('SENTRY_DSN') +LINEAR_API_URL = 'https://api.linear.app/graphql' +LINEAR_API_KEY = os.environ.get('LINEAR_API_KEY') sentry_sdk.init( dsn=SENTRY_DSN, @@ -54,5 +59,62 @@ def linear_issue(): return jsonify({'message': 'Ok'}), 200 +@app.route('/gitea/push', methods=['POST']) +def gitea_push(): + """ https://docs.gitea.io/en-us/webhooks/ + """ + data = request.json + logger.info('Received gitea push webhook: %s' % data) + if request.headers.get('X-Gitea-Event') != 'push': + logger.error('Invalid event type: %s' % request.headers.get('X-Gitea-Event')) + return jsonify({'message': 'Invalid event type'}), 400 + # check if it's a Linear issue + # linear issue id is like 'TUN-21' + headers = {'Authorization': LINEAR_API_KEY} + state_query = {'query': '{workflowStates(includeArchived:false) { edges { node { id name type } }}}'} + state_resp = requests.post(LINEAR_API_URL, json=state_query, headers=headers) + if state_resp.status_code != 200: + logger.error('Failed to get workflow states: %s' % state_resp.text) + return jsonify({'message': 'Failed to get workflow states'}), 500 + states = state_resp.json().get('data').get('workflowStates').get('edges') + completed_state = None + for state in states: + if state['node']['type'] == 'completed': + completed_state = state['node']['id'] + break + if not completed_state: + logger.error('Failed to get completed state') + return jsonify({'message': 'Failed to get completed state'}), 500 + + # check if the commit message contains a linear issue id + # if yes, update the issue state to completed + for commit in data['commits']: + issue = re.search(r'TUN-\d+', commit['message']) + if issue: + issue_id = issue.group() + data_ = {'query': '{ issue(id: "%s") { title state { name }}}' % issue_id} + resp = requests.post(LINEAR_API_URL, json=data_, headers=headers) + if resp.status_code != 200: + logger.error('Failed to get issue: %s' % resp.text) + return jsonify({'message': 'Failed to get issue'}), 500 + issue_data = resp.json().get('data') + if not issue_data: + logger.error('Issue not found: %s' % issue_id) + return jsonify({'message': 'Issue not found'}), 400 + issue_data = issue_data['issue'] + if issue_data['state']['type'] == 'completed': + return jsonify({'message': 'Issue already completed'}), 200 + update_data = {'query': 'mutation { issueUpdate(input: { stateId: "%s" } id: "%s") { success } }' % (completed_state, issue_id)} + update_resp = requests.post(LINEAR_API_URL, json=update_data, headers=headers) + if update_resp.status_code != 200: + logger.error('Failed to update issue: %s' % update_resp.text) + return jsonify({'message': 'Failed to update issue'}), 500 + if not update_resp.json().get('data', {}).get('issueUpdate', {}).get('success'): + logger.error('Failed to update issue: %s' % update_resp.text) + return jsonify({'message': 'Failed to update issue'}), 500 + + return jsonify({'message': 'Ok'}), 200 + + if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)