actionhandler.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. #! /usr/bin/env python
  2. # -*- coding: utf8 -*-
  3. #
  4. # gitlab irc sender
  5. # Copyright (C) 2016-2017 Andrei Karas (4144)
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 3 of the License, or
  10. # any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. import json
  20. import re
  21. from code.codeshipirchandler import CodeshipIrcHandler
  22. from code.core import Core
  23. from code.githubirchandler import GithubIrcHandler
  24. from code.irchandler import IrcHandler
  25. from code.logger import Logger
  26. eolSplit = re.compile("\n")
  27. class ActionHandler():
  28. def printInfo(self, text):
  29. if Core.config.show_info == True:
  30. Logger.addLog(text)
  31. def saveJson(self, data):
  32. Core.log.info(json.dumps(data, indent = 2))
  33. def findProject(self, path):
  34. if path in Core.config.projects:
  35. self.project = Core.config.projects[path]
  36. return self.project
  37. self.project = None
  38. Logger.addError("Wrong url")
  39. return None
  40. def checkProject(self, data):
  41. if "project" in data:
  42. # gitlab project name
  43. prj = data["project"]["name"]
  44. elif "repository" in data:
  45. # gitlab or github project name
  46. prj = data["repository"]["name"]
  47. elif "build" in data:
  48. # codeship project name
  49. prj = data["build"]["project_name"]
  50. else:
  51. prj = "Unknown"
  52. if prj != self.project.name:
  53. Logger.addError("Wrong project. Asked for project {0} but we found {1}".format(prj, self.project.name))
  54. return False
  55. return True
  56. def isEnabled(self, object_kind):
  57. if object_kind in self.project.actions:
  58. return True
  59. return False
  60. def validate(self, path, data):
  61. self.project = self.findProject(path)
  62. if self.project is None:
  63. return False
  64. if self.checkProject(data) == False:
  65. return False
  66. return True
  67. def shortenBranch(self, branch):
  68. if len(branch) > 11 and branch[:11] == "refs/heads/":
  69. branch = branch[11:]
  70. return branch
  71. def isAllowBranch(self, branch, allow_list, deny_list):
  72. if branch in allow_list:
  73. return True
  74. if branch in deny_list:
  75. return False
  76. if "*" in allow_list:
  77. return True
  78. if "*" in deny_list:
  79. return False
  80. def processAction(self, path, data, headers):
  81. Logger.addLog("Request: " + path)
  82. Logger.addLog("Accesing project: " + self.project.name)
  83. service = self.project.options.service
  84. if service == "gitlab":
  85. self.processGitlabAction(path, data)
  86. elif service == "github":
  87. self.processGithubAction(path, data, headers["X-GitHub-Event"])
  88. elif service == "codeship":
  89. self.processCodeshipAction(path, data)
  90. else:
  91. Logger.addLog("Unknown service: " + service)
  92. def processCodeshipAction(self, path, data):
  93. if "build" not in data:
  94. Logger.addLog("Unknown json for CodeShip")
  95. return
  96. build = data["build"]
  97. branch = self.shortenBranch(build["branch"])
  98. channels = self.project.channels
  99. allow_branches = self.project.allow_branches
  100. deny_brancges = self.project.deny_branches
  101. if self.isAllowBranch(branch, allow_branches, deny_brancges) == False:
  102. return
  103. self.printInfo(build["build_url"])
  104. commit_id = build["commit_id"]
  105. commit_url = build["commit_url"]
  106. url = build["build_url"]
  107. build_id = build["build_id"]
  108. build_status = build["status"]
  109. ircHandler = CodeshipIrcHandler()
  110. if build_status == "error":
  111. for channel in channels:
  112. options = self.project.channels[channel]
  113. ircHandler.printBuildFailed(channel, self.project.name, branch, data, commit_id, commit_url, url, build_id)
  114. if len(options.build_fail_custom_message) > 0:
  115. ircHandler.printCustomMessage(channel, options.build_fail_custom_message)
  116. return
  117. elif build_status == "success":
  118. found = False
  119. for channel in channels:
  120. ircHandler.printBuildSuccess(channel, self.project.name, branch, data, commit_id, commit_url, url, build_id)
  121. found = True
  122. if found == True:
  123. return
  124. elif build_status == "waiting":
  125. pass
  126. else:
  127. if Core.config.global_options.http_save_json == "unsupported":
  128. self.saveJson(data)
  129. Logger.addLog("Skipping unsupported build status {0}.".format(build_status))
  130. return
  131. Logger.addLog("Unused build status {0}.".format(build_status))
  132. def processGitlabAction(self, path, data):
  133. object_kind = data["object_kind"]
  134. if self.isEnabled(object_kind) == False:
  135. Logger.addLog("Ignoring action: " + object_kind)
  136. return
  137. Logger.addLog("Accepting action: " + object_kind)
  138. channels = self.project.actions[object_kind]
  139. allow_branches = self.project.allow_branches
  140. deny_brancges = self.project.deny_branches
  141. if len(channels) == 0:
  142. Logger.addLog("no channels in action")
  143. return
  144. if object_kind == "push":
  145. branch = self.shortenBranch(data["ref"])
  146. if self.isAllowBranch(branch, allow_branches, deny_brancges) == True:
  147. self.push(data, channels, branch)
  148. elif object_kind == "tag_push":
  149. self.tag_push(data, channels)
  150. elif object_kind == "note":
  151. self.note(data, channels)
  152. elif object_kind == "build":
  153. branch = self.shortenBranch(data["ref"])
  154. if self.isAllowBranch(branch, allow_branches, deny_brancges) == True:
  155. self.build(data, channels, branch)
  156. elif object_kind == "pipeline":
  157. branch = self.shortenBranch(data["object_attributes"]["ref"])
  158. if self.isAllowBranch(branch, allow_branches, deny_brancges) == True:
  159. self.pipeline(data, channels, branch)
  160. elif object_kind == "merge_request":
  161. self.merge_request(data, channels)
  162. elif object_kind == "issue":
  163. self.issue(data, channels)
  164. else:
  165. Logger.addLog("Ignoring unsupported action: " + object_kind)
  166. if Core.config.global_options.http_save_json == "unsupported":
  167. self.saveJson(data)
  168. def processGithubAction(self, path, data, object_kind):
  169. if self.isEnabled(object_kind) == False:
  170. Logger.addLog("Ignoring github action: " + object_kind)
  171. return
  172. Logger.addLog("Accepting github action: " + object_kind)
  173. channels = self.project.actions[object_kind]
  174. allow_branches = self.project.allow_branches
  175. deny_brancges = self.project.deny_branches
  176. if len(channels) == 0:
  177. Logger.addLog("no channels in action")
  178. return
  179. if object_kind == "status":
  180. branches = data["branches"]
  181. for br in branches:
  182. branch = self.shortenBranch(br["name"])
  183. if self.isAllowBranch(branch, allow_branches, deny_brancges) == True:
  184. self.github_status(data, channels, branch)
  185. elif object_kind == "issues":
  186. self.github_issues(data, channels)
  187. elif object_kind == "issue_comment":
  188. self.github_issue_comment(data, channels)
  189. elif object_kind == "check_suite":
  190. branch = data["check_suite"]["head_branch"]
  191. if self.isAllowBranch(branch, allow_branches, deny_brancges) == True:
  192. self.github_check_suite(data, channels, branch)
  193. else:
  194. Logger.addLog("Ignoring unsupported github action: " + object_kind)
  195. if Core.config.global_options.http_save_json == "unsupported":
  196. self.saveJson(data)
  197. def splitMessageToParts(self, data):
  198. parts = eolSplit.split(data)
  199. lines = []
  200. for part in parts:
  201. if len(part) == 0:
  202. continue
  203. lines.append(part)
  204. return lines
  205. def push(self, data, channels, branch):
  206. self.printInfo(data["project"]["homepage"])
  207. commitsCount = data["total_commits_count"]
  208. commits = data["commits"]
  209. url = data["project"]["homepage"]
  210. ircHandler = IrcHandler()
  211. if len(commits) > 0:
  212. for channel in channels:
  213. options = self.project.channels[channel]
  214. ircHandler.printPushHeader(channel, self.project.name, branch, url, data, commits, commitsCount)
  215. if options.show_commits == False:
  216. continue
  217. # if first push and fix enabled
  218. if options.push_first_push_fix == True and data["before"] == "0000000000000000000000000000000000000000":
  219. commits_list = reversed(commits)
  220. else:
  221. commits_list = commits
  222. for commit in commits_list:
  223. messages = self.splitMessageToParts(commit["message"])
  224. if len(messages) == 0:
  225. continue
  226. ircHandler.printCommitAuthor(channel, self.project.name, data, commit, messages[0])
  227. if options.show_commit_messages == True:
  228. del messages[0]
  229. if options.max_message_lines_per_commit != 0:
  230. while len(messages) > options.max_message_lines_per_commit:
  231. del messages[len(messages) - 1]
  232. ircHandler.printCommitMessage(channel, messages)
  233. else:
  234. for channel in channels:
  235. ircHandler.printCreateBranch(channel, self.project.name, data, branch, url)
  236. def tag_push(self, data, channels):
  237. self.printInfo(data["project"]["homepage"])
  238. commits = data["commits"]
  239. tag = data["ref"]
  240. if len(tag) > 10 and tag[:10] == "refs/tags/":
  241. tag = tag[10:]
  242. url = data["project"]["homepage"]
  243. ircHandler = IrcHandler()
  244. for channel in channels:
  245. ircHandler.printPushTag(channel, self.project.name, data, commits, tag, url)
  246. def note(self, data, channels):
  247. self.printInfo(data["project"]["homepage"])
  248. attrs = data["object_attributes"]
  249. url = attrs["url"]
  250. if "commit" in data:
  251. commit = data["commit"]
  252. url = data["project"]["homepage"]
  253. iid = attrs["id"]
  254. ircHandler = IrcHandler()
  255. for channel in channels:
  256. ircHandler.printAddCommitNote(channel, self.project.name, data, commit, url, iid)
  257. elif "merge_request" in data:
  258. ircHandler = IrcHandler()
  259. merge_request = data["merge_request"]
  260. iid = merge_request["iid"]
  261. branch = merge_request["target_branch"]
  262. source = merge_request["source"]
  263. title = merge_request["title"]
  264. source_branch = merge_request["source_branch"]
  265. source_namespace = source["namespace"]
  266. for channel in channels:
  267. ircHandler.printAddMRNote(channel, self.project.name, branch, source_namespace, source_branch, data, url, iid)
  268. elif "issue" in data:
  269. ircHandler = IrcHandler()
  270. issue = data["issue"]
  271. iid = issue["iid"]
  272. title = issue["title"]
  273. for channel in channels:
  274. ircHandler.printAddIssueNote(channel, self.project.name, data, url, iid, title)
  275. elif "snippet" in data:
  276. ircHandler = IrcHandler()
  277. snippet = data["snippet"]
  278. iid = snippet["id"]
  279. title = snippet["title"]
  280. for channel in channels:
  281. ircHandler.printAddSnippetNote(channel, self.project.name, data, url, iid, title)
  282. else:
  283. Logger.addLog("Skipping unsupported note type");
  284. if Core.config.global_options.http_save_json == "unsupported":
  285. self.saveJson(data)
  286. def build(self, data, channels, branch):
  287. self.printInfo(data["repository"]["homepage"])
  288. commit = data["commit"]
  289. url = data["repository"]["homepage"]
  290. build_id = data["build_id"]
  291. build_status = data["build_status"]
  292. ircHandler = IrcHandler()
  293. build_stage = data["build_stage"]
  294. build_name = data["build_name"]
  295. build_allow_failure = data["build_allow_failure"]
  296. if build_status == "failed":
  297. options = self.project.options
  298. build_retry = options.build_retry
  299. if options.gitlab_api_token != "" and build_retry != "never" and build_retry != "":
  300. Core.apiHandler.retry_build(data["project_id"], build_id, data["sha"], options)
  301. for channel in channels:
  302. options = self.project.channels[channel]
  303. if len(options.last_build_fail_stage) > 0 and data["build_stage"] == options.last_build_fail_stage:
  304. ircHandler.printStageFailed(channel, self.project.name, branch, data, commit, url, build_id)
  305. if options.show_build_failures_for_allowed_to_fail == True and data["build_allow_failure"] == True:
  306. ircHandler.printBuildFailed(channel, self.project.name, branch, data, commit, url, build_id, build_stage, build_name)
  307. if len(options.build_fail_custom_message) > 0:
  308. ircHandler.printCustomMessage(channel, options.build_fail_custom_message)
  309. continue # for prevent double messages
  310. if options.show_build_failures == False:
  311. continue
  312. if options.build_accept_allow_failure == False or build_allow_failure == False:
  313. ircHandler.printBuildFailed(channel, self.project.name, branch, data, commit, url, build_id, build_stage, build_name)
  314. if len(options.build_fail_custom_message) > 0:
  315. ircHandler.printCustomMessage(channel, options.build_fail_custom_message)
  316. return
  317. elif build_status == "success":
  318. found = False
  319. for channel in channels:
  320. options = self.project.channels[channel]
  321. if len(options.last_build_fail_stage) > 0 and data["build_stage"] == options.last_build_fail_stage:
  322. ircHandler.printStageFailed(channel, self.project.name, branch, data, commit, url, build_id)
  323. found = True
  324. if len(options.last_build_stage) > 0 and data["build_stage"] == options.last_build_stage:
  325. ircHandler.printBuildSuccess(channel, self.project.name, branch, data, commit, url, build_id)
  326. found = True
  327. if options.show_build_success_for_allowed_to_fail == True and data["build_allow_failure"] == True:
  328. ircHandler.printBuildSuccess(channel, self.project.name, branch, data, commit, url, build_id)
  329. found = True
  330. if found == True:
  331. return
  332. elif build_status == "pending":
  333. pass
  334. elif build_status == "running":
  335. pass
  336. elif build_status == "canceled":
  337. pass
  338. else:
  339. if Core.config.global_options.http_save_json == "unsupported":
  340. self.saveJson(data)
  341. Logger.addLog("Skipping unsupported build status {0}.".format(build_status))
  342. return
  343. Logger.addLog("Unused build status {0}.".format(build_status))
  344. def pipeline(self, data, channels, branch):
  345. self.printInfo(data["project"]["web_url"])
  346. commit = data["commit"]
  347. url = data["project"]["web_url"]
  348. pipeline_status = data["object_attributes"]["status"]
  349. ircHandler = IrcHandler()
  350. pipeline_id = data["object_attributes"]["id"]
  351. if pipeline_status == "failed":
  352. if self.isPipelineComplete(data) == True:
  353. for channel in channels:
  354. options = self.project.channels[channel]
  355. if options.show_pipeline_failures == False:
  356. continue
  357. ircHandler.printPipelineFailed(channel, self.project.name, branch, data, commit, url, pipeline_id)
  358. if len(options.pipeline_fail_custom_message) > 0:
  359. ircHandler.printCustomMessage(channel, options.pipeline_fail_custom_message)
  360. return
  361. elif pipeline_status == "success":
  362. if self.isPipelineComplete(data) == True:
  363. for channel in channels:
  364. options = self.project.channels[channel]
  365. if options.show_pipeline_success == False:
  366. continue
  367. ircHandler.printPipelineSuccess(channel, self.project.name, branch, data, commit, url, pipeline_id)
  368. return
  369. elif pipeline_status == "pending":
  370. pass
  371. elif pipeline_status == "running":
  372. pass
  373. elif pipeline_status == "canceled":
  374. pass
  375. else:
  376. if Core.config.global_options.http_save_json == "unsupported":
  377. self.saveJson(data)
  378. Logger.addLog("Skipping unsupported pipeline status {0}.".format(pipeline_status))
  379. return
  380. Logger.addLog("Unused pipeline status {0}.".format(pipeline_status))
  381. def merge_request(self, data, channels):
  382. self.printInfo(data["project"]["homepage"])
  383. ircHandler = IrcHandler()
  384. attrs = data["object_attributes"]
  385. url = attrs["url"]
  386. action = attrs["action"]
  387. iid = attrs["iid"]
  388. branch = attrs["target_branch"]
  389. source = attrs["source"]
  390. title = attrs["title"]
  391. source_branch = attrs["source_branch"]
  392. source_namespace = source["namespace"]
  393. if action == "open":
  394. for channel in channels:
  395. ircHandler.printMROpened(channel, self.project.name, branch, source_branch, source_namespace, data, url, iid, title)
  396. elif action == "close":
  397. for channel in channels:
  398. ircHandler.printMRClosed(channel, self.project.name, branch, source_branch, source_namespace, data, url, iid, title)
  399. elif action == "reopen":
  400. for channel in channels:
  401. ircHandler.printMRReopened(channel, self.project.name, branch, source_branch, source_namespace, data, url, iid, title)
  402. elif action == "update":
  403. for channel in channels:
  404. ircHandler.printMRUpdated(channel, self.project.name, branch, source_branch, source_namespace, data, url, iid, title)
  405. elif action == "merge":
  406. for channel in channels:
  407. ircHandler.printMRMerged(channel, self.project.name, branch, source_branch, source_namespace, data, url, iid, title)
  408. else:
  409. Logger.addLog("Skipping unsupported action {0}.".format(action))
  410. if Core.config.global_options.http_save_json == "unsupported":
  411. self.saveJson(data)
  412. def issue(self, data, channels):
  413. self.printInfo(data["project"]["homepage"])
  414. ircHandler = IrcHandler()
  415. attrs = data["object_attributes"]
  416. url = attrs["url"]
  417. action = attrs["action"]
  418. iid = attrs["iid"]
  419. title = attrs["title"]
  420. if action == "open":
  421. for channel in channels:
  422. ircHandler.printIssueOpened(channel, self.project.name, data, url, iid, title)
  423. elif action == "close":
  424. for channel in channels:
  425. ircHandler.printIssueClosed(channel, self.project.name, data, url, iid, title)
  426. elif action == "reopen":
  427. for channel in channels:
  428. ircHandler.printIssueReopened(channel, self.project.name, data, url, iid, title)
  429. elif action == "update":
  430. for channel in channels:
  431. ircHandler.printIssueUpdated(channel, self.project.name, data, url, iid, title)
  432. else:
  433. Logger.addLog("Skipping unsupported action {0}.".format(action))
  434. if Core.config.global_options.http_save_json == "unsupported":
  435. self.saveJson(data)
  436. def github_status(self, data, channels, branch):
  437. self.printInfo(data["repository"]["html_url"])
  438. ircHandler = GithubIrcHandler()
  439. action = data["state"]
  440. description = data["description"]
  441. commit = data["commit"]["sha"]
  442. url = data["target_url"]
  443. if action == "pending":
  444. pass
  445. elif action == "success":
  446. for channel in channels:
  447. ircHandler.printBuildSuccess(channel, self.project.name, branch, data, commit, url, description)
  448. elif action == "failure" or action == "error":
  449. for channel in channels:
  450. options = self.project.channels[channel]
  451. if options.show_build_failures == False:
  452. continue
  453. ircHandler.printBuildFailed(channel, self.project.name, branch, data, commit, url, description)
  454. if len(options.build_fail_custom_message) > 0:
  455. ircHandler.printCustomMessage(channel, options.build_fail_custom_message)
  456. else:
  457. Logger.addLog("Skipping unsupported github status action {0}.".format(action))
  458. if Core.config.global_options.http_save_json == "unsupported":
  459. self.saveJson(data)
  460. def github_check_suite(self, data, channels, branch):
  461. self.printInfo(data["repository"]["html_url"])
  462. ircHandler = GithubIrcHandler()
  463. action = data["action"]
  464. conclusion = data["check_suite"]["conclusion"]
  465. status = data["check_suite"]["status"]
  466. commit = data["check_suite"]["head_sha"]
  467. # tested only on azure pipelines, and here actual url missing
  468. url = data["repository"]["html_url"] + "/commits/" + commit
  469. # tested only on azure pipelines, and here actual description missing
  470. description = data["check_suite"]["app"]["name"]
  471. if action == "completed":
  472. if conclusion == "failure" or conclusion == "cancelled" or conclusion == "timed_out":
  473. description = description + " build " + conclusion.replace("_", " ")
  474. for channel in channels:
  475. options = self.project.channels[channel]
  476. if options.show_build_failures == False:
  477. continue
  478. ircHandler.printBuildFailed(channel, self.project.name, branch, data, commit, url, description)
  479. if len(options.build_fail_custom_message) > 0:
  480. ircHandler.printCustomMessage(channel, options.build_fail_custom_message)
  481. elif conclusion == "success" or conclusion == "action_required":
  482. description = description + " build " + conclusion.replace("_", " ")
  483. for channel in channels:
  484. ircHandler.printBuildSuccess(channel, self.project.name, branch, data, commit, url, description)
  485. else:
  486. Logger.addLog("Skipping unsupported github check_suite action {0} / {1} / {2}.".format(action, status, conclusion))
  487. if Core.config.global_options.http_save_json == "unsupported":
  488. self.saveJson(data)
  489. else:
  490. Logger.addLog("Skipping unsupported github check_suite action {0} / {1} / {2}.".format(action, status, conclusion))
  491. if Core.config.global_options.http_save_json == "unsupported":
  492. self.saveJson(data)
  493. def github_issues(self, data, channels):
  494. self.printInfo(data["repository"]["html_url"])
  495. ircHandler = GithubIrcHandler()
  496. action = data["action"]
  497. url = data["issue"]["html_url"]
  498. description = data["issue"]["title"]
  499. iid = data["issue"]["number"]
  500. if action == "opened":
  501. for channel in channels:
  502. ircHandler.printIssuesOpened(channel, self.project.name, data, url, iid, description)
  503. elif action == "edited":
  504. for channel in channels:
  505. ircHandler.printIssuesEdited(channel, self.project.name, data, url, iid, description)
  506. elif action == "closed":
  507. for channel in channels:
  508. ircHandler.printIssuesClosed(channel, self.project.name, data, url, iid, description)
  509. elif action == "reopened":
  510. for channel in channels:
  511. ircHandler.printIssuesReopened(channel, self.project.name, data, url, iid, description)
  512. else:
  513. Logger.addLog("Skipping unsupported github issues action {0}.".format(action))
  514. if Core.config.global_options.http_save_json == "unsupported":
  515. self.saveJson(data)
  516. def github_issue_comment(self, data, channels):
  517. self.printInfo(data["repository"]["html_url"])
  518. ircHandler = GithubIrcHandler()
  519. action = data["action"]
  520. url = data["issue"]["html_url"]
  521. description = data["issue"]["title"]
  522. iid = data["issue"]["number"]
  523. if action == "created":
  524. for channel in channels:
  525. ircHandler.printIssueCommentCreated(channel, self.project.name, data, url, iid, description)
  526. elif action == "edited":
  527. for channel in channels:
  528. ircHandler.printIssueCommentEdited(channel, self.project.name, data, url, iid, description)
  529. elif action == "deleted":
  530. for channel in channels:
  531. ircHandler.printIssueCommentDeleted(channel, self.project.name, data, url, iid, description)
  532. else:
  533. Logger.addLog("Skipping unsupported github issue_comment action {0}.".format(action))
  534. if Core.config.global_options.http_save_json == "unsupported":
  535. self.saveJson(data)
  536. def isPipelineComplete(self, data):
  537. for build in data["builds"]:
  538. status = build["status"]
  539. if status != "success" and status != "failed" and status != "canceled" and status != "skipped":
  540. return False
  541. return True