Lambda로 CodeCommiit 알림을 Teams로 건너뛰기

개시하다


다음 기사에 의해 촉발되어 Lambda에서python에서 CodeCommiit에 알림을 보내는 것을 실현하였다.zip바p가 귀찮아서pythn3.이루어지다
통지의 설정 등 세부 사항은 아래의 보도 내용을 확인해 주십시오.
https://qiita.com/aocm/items/8eb22939791691c19cde

일단 람다에서 이벤트 내용을 확인합니다.

lambda_handler() 이벤트에 전달된 내용은 Object로 전달됐는데 어떤 형태로 왔는지 알 수 없다.
코드Commiit의 PR 관련 트리거는 이벤트에서 어떤 정보가 유출되는지 먼저 확인했다.

Sns의 이벤트 확인 코드


다음 코드를 통해 Sns에서 전송된 이벤트를 확인했습니다.event['Records'][0]['Sns']['Message']는 유니버설 문자열로 식별되어 dict로 순조롭게 읽을 수 없기 때문에 끼워 넣기json.loads().
CloudWatchLogs에서 logger를 여러 줄로 바뀐 로그 출력 대신 기록 출력으로 설정합니다.
lambda deploy로 이쪽을 통과한 후 코드commiit에서 알림 내용을 확인하고 싶은 처리를 실시하고 클라우드 왓 로그를 확인하면 알림의 이벤트 내용을 확인할 수 있습니다.
import json
import os
import re
import requests
import sys
from logging import getLogger, INFO ,StreamHandler

logger = getLogger(__name__)
logger.setLevel(INFO)

def lambda_handler(event, context) -> None:
    sns_dict = event['Records'][0]['Sns']
    sns_dict['Message'] = json.loads(sns_dict['Message'])
    sns_dict_str = json.dumps(sns_dict, ensure_ascii=False)
    logger.info('sns message:')
    logger.info(sns_dict_str)
모든 조작 모델을 조사하는 것은 매우 어려워서 3개만 조사한다.
(조사가 까다로워 설명서를 요구한다)

이벤트 확인: PR 제작


{
    "Type": "Notification",
    "MessageId": "aaaaa-aaaaa-aaaaa-aaaa", #mask
    "TopicArn": "arn:aws:sns:ap-northeast-1:aaaaa:codcommit-notification", # mask
    "Subject": null,
    "Message": {
        "account": "aaaaa", #mask
        "detailType": "CodeCommit Pull Request State Change",
        "region": "ap-northeast-1",
        "source": "aws.codecommit",
        "time": "2021-10-31T16:20:26Z",
        "notificationRuleArn": "arn:aws:codestar-notifications:ap-northeast-1:aaaaa:notificationrule/aaaaa", # mask
        "detail": {
            "sourceReference": "refs/heads/feature/notification_test2",
            "lastModifiedDate": "Sun Oct 31 16:20:18 UTC 2021",
            "author": "arn:aws:iam::aaaaa:user/iam_user_name", #mask
            "isMerged": "False",
            "pullRequestStatus": "Open",
            "notificationBody": "A pull request event occurred in the following AWS CodeCommit repository: test-repository. User: aarn:aws:iam::aaaaa:user/iam_user_name. Event: Created. Pull request name: 12. Additional information: A pull request was created with the following ID: 12. The title of the pull request is: notification test 2. For more information, go to the AWS CodeCommit console {repogitory_link}",
            "description": "notification desictiption",
            "destinationReference": "refs/heads/master",
            "callerUserArn": "arn:aws:iam::aaaaa:user/iam_user_name", #mask
            "creationDate": "Sun Oct 31 16:20:18 UTC 2021",
            "pullRequestId": "12",
            "title": "notification test 2",
            "revisionId": "aaaaaa", # mask
            "repositoryNames": [
                "test-repogitory"
            ],
            "destinationCommit": "423f021893fa3233cf956f287ece47d0987be441",
            "event": "pullRequestCreated",
            "sourceCommit": "bcda8ac3245cf63388d61df6a16769f32b2de590"
        },
        "resources": [
            "arn:aws:codecommit:ap-northeast-1:aaaaa:test-repogitory" #mask
        ],
        "additionalAttributes": {
            "numberOfFilesAdded": "0",
            "numberOfFilesDeleted": "1",
            "numberOfFilesModified": "0",
            "changedFiles": [
                {
                    "changeType": "D",
                    "filePath": "test2.txt"
                }
            ]
        }
    },
    "Timestamp": "2021-10-31T16:20:28.873Z",
    "SignatureVersion": "1",
    "Signature": "aaaaa", # mask
    "SigningCertUrl": "{pem_link}", #mask
    "UnsubscribeUrl": "{link}", #mask
    "MessageAttributes": {}
}

이벤트 확인: PR 병합


{
    "Type": "Notification",
    "MessageId": "aaaaa-aaaaa-aaaaa-aaaa", #mask
    "TopicArn": "arn:aws:sns:ap-northeast-1:aaaaa:codcommit-notification", #mask
    "Subject": null,
    "Message": {
        "account": "aaaaa", #mask
        "detailType": "CodeCommit Pull Request State Change",
        "region": "ap-northeast-1",
        "source": "aws.codecommit",
        "time": "2021-10-31T16:03:49Z",
        "notificationRuleArn": "arn:aws:codestar-notifications:ap-northeast-1:aaaaa:notificationrule/aaaaa", #mask
        "detail": {
            "sourceReference": "refs/heads/feature/notification_test",
            "lastModifiedDate": "Sun Oct 31 16:03:39 UTC 2021",
            "author": "arn:aws:iam::aaaaa:user/iam_user_name",#mask
            "isMerged": "True",
            "pullRequestStatus": "Closed",
            "notificationBody": "A pull request event occurred in the following AWS CodeCommit repository: test-repogitory. User: arn:aws:iam::aaaa:iam_user_name. Event: Updated. Pull request name: 11. Additional information: The pull request merge status has been updated. The status is merged. For more information, go to the AWS CodeCommit console {repogitory_link}",#mask
            "description": "# notification実装テスト用PRの説明セクション\ntest\n## test\n- test\n  - test",
            "destinationReference": "refs/heads/master",
            "callerUserArn": "arn:aws:iam::aaaaa:user/iam_user_name", #mask
            "creationDate": "Sun Oct 31 14:46:05 UTC 2021",
            "pullRequestId": "11",
            "title": "notification実装テスト用PR",
            "revisionId": "aaaaa", # mask
            "repositoryNames": [
                "test-repogitory"
            ],
            "destinationCommit": "1da430df4696193ce4883bd029d7fa650606a078",
            "event": "pullRequestMergeStatusUpdated",
            "mergeOption": "SQUASH_MERGE",
            "sourceCommit": "ae1dd8f163e45e150d6074f78357d1ce6c030ab8"
        },
        "resources": [
            "arn:aws:codecommit:ap-northeast-1:aaaaa:test-repogitory" #mask
        ],
        "additionalAttributes": {}
    },
    "Timestamp": "2021-10-31T16:03:51.808Z",
    "SignatureVersion": "1",
    "Signature": "aaaaa", # mask
    "SigningCertUrl": "{pem_link}", #mask
    "UnsubscribeUrl": "{link}", #mask
    "MessageAttributes": {}
}

이벤트 확인: PR 리뷰 추가


{
    "Type": "Notification",
    "MessageId": "aaaaa", # mask
    "TopicArn": "arn:aws:sns:ap-northeast-1:aaaaa:codcommit-notification", # mask
    "Subject": null,
    "Message": {
        "account": "909287433301",
        "detailType": "CodeCommit Comment on Pull Request",
        "region": "ap-northeast-1",
        "source": "aws.codecommit",
        "time": "2021-10-31T15:20:36Z",
        "notificationRuleArn": "arn:aws:codestar-notifications:ap-northeast-1:aaaaa:notificationrule/aaaaa", #mask
        "detail": {
            "beforeCommitId": "1da430df4696193ce4883bd029d7fa650606a078",
            "notificationBody": "A pull request event occurred in the following AWS CodeCommit repository: test-repository. The user: arn:aws:iam::aaaaa:user/iam_user_name made a comment or replied to a comment. The comment was made on the following Pull Request: 11. For more information, go to the AWS CodeCommit console {repogitory_link}", # mask
            "repositoryId": "aaaaa", # mask
            "commentId": "aaaaa", # mask
            "afterCommitId": "c98211927b2d78bc7bad803b08221a0e0329ce20",
            "callerUserArn": "arn:aws:iam::aaaaa:user/iam_user_name", #mask
            "event": "commentOnPullRequestCreated",
            "pullRequestId": "11",
            "repositoryName": "test-repository"
        },
        "resources": [
             "arn:aws:codecommit:ap-northeast-1:aaaaa:test-repogitory" # mask
        ],
        "additionalAttributes": {
            "commentedLine": null,
            "resourceArn":  "arn:aws:codecommit:ap-northeast-1:aaaaa:test-repogitory", # mask
            "comments": [
                {
                    "authorArn": "arn:aws:iam::aaaaa:user/iam_user_name", #mask
                    "commentText": "変更に対するコメントテスト13"
                }
            ],
            "commentedLineNumber": null,
            "filePath": null
        }
    },
    "Timestamp": "2021-10-31T15:20:39.578Z",
    "SignatureVersion": "1",
    "Signature": "aaaaa", # mask
    "SigningCertUrl": "{pem_link}", #mask
    "UnsubscribeUrl": "{link}", #mask
    "MessageAttributes": {}
}

Teams 발언 형식


다음 함수에 정의된 발언 형식에 따라 실현되었습니다.
지정할 수 있는 포맷 옵션이 많았지만 쉽게 구현하고 싶어 실장 경험이 있는 포맷으로 구현했다.
https://docs.microsoft.com/ja-jp/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL
def post_teams(title: str, detail: list, link: list) -> None:
    payload = {
        '@type': 'MessageCard',
        "@context": "http://schema.org/extensions",
        "themeColor": "0076D7",
        "summary": f'{AWS_ACCOUNT}: {title}',
        "sections": [{
            "activityTitle": f'{AWS_ACCOUNT}: CodeCommit Notifiction',
            "activitySubtitle": f'{title}',
            "activityImage": f'{link["icon_url"]}',
            "facts": detail,
            "markdown": 'true',
            "potentialAction": [{
                "@type": "OpenUri",
                "name": f'{link["name"]}',
                "targets": [{
                    "os": "default",
                    "uri": f'{link["url"]}'
                }]
            }]
        }]
    }

    logger.info('post message:')
    logger.info(json.dumps(payload))

    try:
        response = requests.post(TEAMS_WEBHOOK_URL, data=json.dumps(payload))
    except requests.exceptions.RequestException as e:
        print(e)
    else:
        print(response.status_code)

최종 완성된 코드


상부의 환경 변수를 별도로 설정하면 동작한다.get_message()에서 각 이벤트 알림 모드에 대해 Teams 발언 데이터 형식에 따라 성형한 후 Teams에 투고했다.
여전히 아이콘 설정에 감각이 없어 아이콘을 모집 중입니다.
import json
import os
import re
import requests
import sys
from logging import getLogger, INFO ,StreamHandler

logger = getLogger(__name__)
logger.setLevel(INFO)

# SLACK_WEBHOOK_URL = os.environ['SLACK_WEBHOOK_URL']
TEAMS_WEBHOOK_URL = os.environ['TEAMS_WEBHOOK_URL']
AWS_ACCOUNT = os.environ['ACCOUNT_NAME']

def lambda_handler(event, context) -> None:
    sns_dict = event['Records'][0]['Sns']
    sns_dict['Message'] = json.loads(sns_dict['Message'])
    sns_dict_str = json.dumps(sns_dict, ensure_ascii=False)
    logger.info('sns message:')
    logger.info(sns_dict_str)
    title, detail, link = get_message(sns_dict['Message'])
    post_teams(title, detail, link)

def get_message(message: dict) -> (str, list, dict):
    title = message['detailType']
    https_pattern = "https?://[\w/:%#\$&\?\(\)~\.=\+\-]+"
    if title == 'CodeCommit Comment on Pull Request':
        # title
        title_fixed = title
        # detail
        user_arn = message['detail']['callerUserArn']
        user_name = user_arn.split('/')[1]

        repo_name = message['detail']['repositoryName']

        comment_line = message['additionalAttributes']['commentedLine'] or '---'
        comment_filepath = message['additionalAttributes']['filePath'] or '---'
        comment_text = message['additionalAttributes']['comments'][0]['commentText']

        detail = [
            {'name':'user', 'value':user_name},
            {'name':'repo_name', 'value':repo_name },
            {'name':'comment_filepath', 'value':comment_filepath},
            {'name':'comment_line', 'value':comment_line},
            {'name':'comment_text', 'value':comment_text}
        ]
        # link
        url_list = re.findall(https_pattern, message['detail']['notificationBody'])
        url = url_list[0]
        url = url[:-1] if url[-1] == '.' else url
        link = {
            'icon_url': 'https://img.icons8.com/external-flatart-icons-outline-flatarticons/64/000000/external-comment-chat-flatart-icons-outline-flatarticons-2.png',
            'name': 'PullRequest',
            'url': url
        }
    elif title == 'CodeCommit Pull Request State Change':
        if message['detail']['event'] == "pullRequestCreated":
            # title
            title_fixed = 'CodeCommit Pull Request Created'
            # detail
            repo_name = message['detail']['repositoryNames'][0]
            src_branch = message['detail']['sourceReference']
            dst_branch = message['detail']['destinationReference']
            author_arn = message['detail']['author']
            author_name = author_arn.split('/')[1]
            description = message['detail']['description']

            detail = [
                {'name':'repo_name', 'value':repo_name },
                {'name':'src_branch', 'value':src_branch},
                {'name':'dst_branch', 'value':dst_branch},
                {'name':'author', 'value':author_name},
                {'name':'description', 'value':description}
            ]
            # link
            url_list = re.findall(https_pattern, message['detail']['notificationBody'])
            url = url_list[0]
            url = url[:-1] if url[-1] == '.' else url
            link = {
                'icon_url': 'https://cdn-icons-png.flaticon.com/512/3659/3659866.png',
                'name': 'PullRequest',
                'url': url
            }
        elif message['detail']['isMerged'] == "True":
            # title
            title_fixed = 'CodeCommit Pull Request Mereged'
            # detail
            repo_name = message['detail']['repositoryNames'][0]
            src_branch = message['detail']['sourceReference']
            dst_branch = message['detail']['destinationReference']
            merge_option = message['detail']['mergeOption']

            detail = [
                {'name':'repo_name', 'value':repo_name},
                {'name':'src_branch', 'value':src_branch},
                {'name':'dst_branch', 'value':dst_branch}
            ]
            # link
            url_list = re.findall(https_pattern, message['detail']['notificationBody'])
            url = url_list[0]
            url = url[:-1] if url[-1] == '.' else url
            link = {
                'icon_url': 'https://cdn0.iconfinder.com/data/icons/octicons/1024/git-pull-request-512.png',
                'name': 'PullRequest',
                'url': url
            }
    else:
        # title
        title_fixed = title
        # detail
        detail = [
            {'name':'notificationBody', 'value':message['detail']['notificationBody']}
        ]
        # link
        url_list = re.findall(https_pattern, message['detail']['notificationBody'])
        url = url_list[0]
        url = url[:-1] if url[-1] == '.' else url
        link = {
            'icon_url': 'https://cdn-icons.flaticon.com/png/512/2076/premium/2076218.png?token=exp=1635696056~hmac=6f323fa1adc2e6d6de8d2b961c96984b',
            'name': 'PullRequest',
            'url': url
        }

    return title_fixed, detail, link

def post_teams(title: str, detail: list, link: list) -> None:

    payload = {
        '@type': 'MessageCard',
        "@context": "http://schema.org/extensions",
        "themeColor": "0076D7",
        "summary": f'{AWS_ACCOUNT}: {title}',
        "sections": [{
            "activityTitle": f'{AWS_ACCOUNT}: CodeCommit Notifiction',
            "activitySubtitle": f'{title}',
            "activityImage": f'{link["icon_url"]}',
            "facts": detail,
            "markdown": 'true',
            "potentialAction": [{
                "@type": "OpenUri",
                "name": f'{link["name"]}',
                "targets": [{
                    "os": "default",
                    "uri": f'{link["url"]}'
                }]
            }]
        }]
    }

    logger.info('post message:')
    logger.info(json.dumps(payload))

    try:
        response = requests.post(TEAMS_WEBHOOK_URL, data=json.dumps(payload))
    except requests.exceptions.RequestException as e:
        print(e)
    else:
        print(response.status_code)

끝맺다


이벤트 패턴이 무한해서 하나하나 조사하기 힘들어서 샘플을 원합니다.

좋은 웹페이지 즐겨찾기