forked from ogrodnek/code-pipeline-slack
/
notifier.py
109 lines (82 loc) · 2.97 KB
/
notifier.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# -*- coding: utf-8 -*-
from __future__ import print_function
import json
import boto3
import time
from test_events import TEST_EVENTS, TEST_ERROR_EVENTS
from build_info import BuildInfo, CodeBuildInfo
from slack_helper import post_build_msg, find_message_for_build
from message_builder import MessageBuilder
import re
import sys
client = boto3.client('codepipeline')
def parse(event):
if event['source'] == 'aws.codebuild':
ini = event['detail']['additional-information']['initiator']
m = re.match('codepipeline/(.+)', ini)
if m:
pipeline = m.group(1)
r = client.get_pipeline_state(name=pipeline)
buildInfo = BuildInfo.fromEvent(event)
return buildInfo
def findRevisionInfo(info):
r = client.get_pipeline_execution(
pipelineName=info.pipeline,
pipelineExecutionId=info.executionId
)['pipelineExecution']
revs = r.get('artifactRevisions',[])
if len(revs) > 0:
return revs[0]
return None
def pipelineFromBuild(codeBuildInfo):
r = client.get_pipeline_state(name=codeBuildInfo.pipeline)
for s in r['stageStates']:
for a in s['actionStates']:
executionId = a.get('latestExecution', {}).get('externalExecutionId')
if executionId and codeBuildInfo.buildId.endswith(executionId):
pe = s['latestExecution']['pipelineExecutionId']
return (s['stageName'], pe, a)
return (None, None, None)
def processCodePipeline(event):
buildInfo = BuildInfo.fromEvent(event)
existing_msg = find_message_for_build(buildInfo)
builder = MessageBuilder(buildInfo, existing_msg)
builder.updatePipelineEvent(event)
if builder.needsRevisionInfo():
revision = findRevisionInfo(buildInfo)
builder.attachRevisionInfo(revision)
post_build_msg(builder)
def processCodeBuild(event):
cbi = CodeBuildInfo.fromEvent(event)
(stage, pid, actionStates) = pipelineFromBuild(cbi)
if not pid:
return
buildInfo = BuildInfo(pid, cbi.pipeline)
existing_msg = find_message_for_build(buildInfo)
builder = MessageBuilder(buildInfo, existing_msg)
if 'phases' in event['detail']['additional-information']:
phases = event['detail']['additional-information']['phases']
builder.updateBuildStageInfo(stage, phases, actionStates)
logs = event['detail'].get('additional-information', {}).get('logs')
if logs:
builder.attachLogs(event['detail']['additional-information']['logs'])
post_build_msg(builder)
def process(event):
if event['source'] == "aws.codepipeline":
processCodePipeline(event)
if event['source'] == "aws.codebuild":
processCodeBuild(event)
# https://www.christopherrung.com/2017/05/04/slack-build-notifications/
def run(event, context):
print(json.dumps(event, indent=2, default=str))
m = process(event)
if __name__ == "__main__":
max_events = len(TEST_ERROR_EVENTS)
print(len(sys.argv))
if len(sys.argv) > 1:
max_events = int(sys.argv[1])
for i in xrange(0, max_events):
print(i)
event = TEST_ERROR_EVENTS[i]
run(event, {})
time.sleep(1)