123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- #! /usr/bin/env python
- # -*- coding: utf8 -*-
- #
- # gitlab irc sender
- # Copyright (C) 2016-2017 Andrei Karas (4144)
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 3 of the License, or
- # any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- import copy
- import logging
- import logging.handlers
- import yaml
- from collections import OrderedDict
- from code.dictconfig import DictConfig
- from code.project import ProjectClass
- class Configuration:
- # log file
- log_file = "./hooks.log"
- # maximum log size
- log_max_size = 104857600
- # log level
- log_level = logging.INFO
- # web server name and version
- http_web_server_name = "nginx"
- # gitlab compare commits url
- gitlab_compare_path = "{homepage}/compare/{commit1}...{commit2}"
- # gitlab commit url
- gitlab_commit_path = "{homepage}/commit/{commit}"
- # gitlab commits group or branch
- gitlab_commits_path = "{homepage}/commits/{name}"
- # gitlab build url
- gitlab_build_path = "{homepage}/builds/{build}"
- # gitlab pipeline url
- gitlab_pipeline_path = "{homepage}/pipelines/{pipeline}"
- # commit size in letters in compare gitlab link
- gitlab_compare_commit_size = 6
- # number of letters showed from commit id
- commit_size = 7
- # pause after each irc message
- irc_message_pause = 2
- # pause in gitlab api thread
- api_sleep_time = 3
- # first irc message about push
- irc_push_header_message = "[\x0302{project}\x0f] \x0307{author}\x0f pushed {count} commits \x0303{branch}\x0f {url}"
- # main push commit message, if comment to big, it continue in next line
- irc_push_commit_message = "[\x0302{project}\x0f] \x0307{author}\x0f \x0303{shortid}\x0f - {message}"
- # continue push commit message
- irc_push_commit_message_continue = "{message}"
- # irc message about pushed tag
- irc_push_add_tag_message = "[\x0302{project}\x0f] \x0307{author}\x0f pushed tag \x0303{tag}\x0f on commit \x0303{shortid}\x0f {url}"
- # irc message about removed tag
- irc_push_remove_tag_message = "[\x0302{project}\x0f] \x0307{author}\x0f deleted tag \x0303{tag}\x0f"
- # irc message about created branch
- irc_push_create_branch_message = "[\x0302{project}\x0f] \x0307{author}\x0f created/changed branch \x0303{branch}\x0f on commit \x0303{shortid}\x0f {url}"
- # irc message about deleted branch
- irc_push_delete_branch_message = "[\x0302{project}\x0f] \x0307{author}\x0f deleted branch \x0303{branch}\x0f"
- # irc message about new note
- irc_push_add_note_message = "[\x0302{project}\x0f] \x0307{author}\x0f add note on commit \x0303{shortid}\x0f {url}"
- # irc message about failed build
- irc_build_failed_message = "[\x0302{project}\x0f] Build \x0307#{build} {name}\x0f for commit \x0303{shortid}\x0f from \x0303{branch}\x0f failed {url}"
- # irc message about success build
- irc_build_success_message = "[\x0302{project}\x0f] Build \x0307#{build}\x0f for commit \x0303{shortid}\x0f from \x0303{branch}\x0f success {url}"
- # irc message about failure stage
- irc_stage_failed_message = "[\x0302{project}\x0f] Build \x0307#{build}\x0f for commit \x0303{shortid}\x0f from \x0303{branch}\x0f failed {url}"
- # irc message about success pipeline
- irc_pipeline_success_message = "[\x0302{project}\x0f] Pipeline \x0307#{pipeline}\x0f for commit \x0303{shortid}\x0f from \x0303{branch}\x0f success {url}"
- # irc message about failed pipeline
- irc_pipeline_failed_message = "[\x0302{project}\x0f] Pipeline \x0307#{pipeline}\x0f for commit \x0303{shortid}\x0f from \x0303{branch}\x0f failed {url}"
- # irc message about opened merge request
- irc_merge_request_opened_message = "[\x0302{project}\x0f] \x0307{author}\x0f opened merge request \x0303!{id}\x0f: {title} {url}"
- # irc message about closed merge request
- irc_merge_request_closed_message = "[\x0302{project}\x0f] \x0307{author}\x0f closed merge request \x0303!{id}\x0f: {title} {url}"
- # irc message about reopened merge request
- irc_merge_request_reopened_message = "[\x0302{project}\x0f] \x0307{author}\x0f reopened merge request \x0303!{id}\x0f: {title} {url}"
- # irc message about updated merge request
- irc_merge_request_updated_message = "[\x0302{project}\x0f] \x0307{author}\x0f updated merge request \x0303!{id}\x0f: {title} {url}"
- # irc message about merged merge request
- irc_merge_request_merged_message = "[\x0302{project}\x0f] \x0307{author}\x0f merged merge request \x0303!{id}\x0f: {title} {url}"
- # irc message about note in merge request
- irc_merge_request_add_note_message = "[\x0302{project}\x0f] \x0307{author}\x0f add note into merge request \x0303!{id}\x0f (\x0303{source_namespace}:{source_branch}\x0f to \x0303{branch}\x0f) {url}"
- # irc message about note in issue
- irc_issue_add_note_message = "[\x0302{project}\x0f] \x0307{author}\x0f add note into issue \x0303#{id}\x0f {url}"
- # irc message about note in snippet
- irc_snippet_add_note_message = "[\x0302{project}\x0f] \x0307{author}\x0f add note into snippet \x0303${id}\x0f {url}"
- # irc message about opened issue
- irc_issue_opened_message = "[\x0302{project}\x0f] \x0307{author}\x0f opened issue \x0303#{id}\x0f: {title} {url}"
- # irc message about closed issue
- irc_issue_closed_message = "[\x0302{project}\x0f] \x0307{author}\x0f closed issue \x0303#{id}\x0f: {title} {url}"
- # irc message about reopened issue
- irc_issue_reopened_message = "[\x0302{project}\x0f] \x0307{author}\x0f reopened issue \x0303#{id}\x0f: {title} {url}"
- # irc message about updated issue
- irc_issue_updated_message = "[\x0302{project}\x0f] \x0307{author}\x0f updated issue \x0303#{id}\x0f: {title} {url}"
- web_hook_default_service = "gitlab"
- # codeship messages
- # irc message about failed build
- irc_codeship_build_failed_message = "[\x0302{project}\x0f] Build for commit \x0303{shortid}\x0f from \x0303{branch}\x0f failed {url}"
- # irc message about success build
- irc_codeship_build_success_message = "[\x0302{project}\x0f] Build for commit \x0303{shortid}\x0f from \x0303{branch}\x0f success {url}"
- # github messages
- # irc message about failed build
- irc_github_build_failed_message = "[\x0302{project}\x0f] {description} for commit \x0303{shortid}\x0f from \x0303{branch}\x0f {url}"
- # irc message about success build
- irc_github_build_success_message = "[\x0302{project}\x0f] {description} for commit \x0303{shortid}\x0f from \x0303{branch}\x0f {url}"
- # irc message about opened issue
- irc_github_issues_opened_message = "[\x0302{project}\x0f] \x0307{author}\x0f opened issue \x0303#{id}\x0f: {title} {url}"
- # irc message about edited issue
- irc_github_issues_edited_message = "[\x0302{project}\x0f] \x0307{author}\x0f edited issue \x0303#{id}\x0f: {title} {url}"
- # irc message about closed issue
- irc_github_issues_closed_message = "[\x0302{project}\x0f] \x0307{author}\x0f closed issue \x0303#{id}\x0f: {title} {url}"
- # irc message about reopened issue
- irc_github_issues_reopened_message = "[\x0302{project}\x0f] \x0307{author}\x0f reopened issue \x0303#{id}\x0f: {title} {url}"
- # irc message about created issue comment
- irc_github_issue_comment_created_message = "[\x0302{project}\x0f] \x0307{author}\x0f add comment to issue \x0303#{id}\x0f: {title} {url}"
- # irc message about edited issue comment
- irc_github_issue_comment_edited_message = "[\x0302{project}\x0f] \x0307{author}\x0f edited comment in issue \x0303#{id}\x0f: {title} {url}"
- # irc message about deleted issue comment
- irc_github_issue_comment_deleted_message = "[\x0302{project}\x0f] \x0307{author}\x0f deleted comment from issue \x0303#{id}\x0f: {title} {url}"
- def __init__(self):
- self.global_options = DictConfig()
- self.projects = dict()
- self.show_info = True
- def addDefaultOption(self, name, value):
- if name not in self.global_options:
- self.global_options[name] = value
- setattr(self.global_options, name, value)
- def load_yaml(self, name):
- class OrderedLoader(yaml.SafeLoader):
- pass
- def construct_mapping(loader, node):
- loader.flatten_mapping(node)
- return OrderedDict(loader.construct_pairs(node))
- OrderedLoader.add_constructor(
- yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
- construct_mapping)
- with open(name, "r") as r:
- return yaml.load(r, OrderedLoader)
- def loadDefaultOptions(self):
- self.addDefaultOption("show_commits", True)
- self.addDefaultOption("show_commit_messages", True)
- # number of lines with commit message per commit
- self.addDefaultOption("max_message_lines_per_commit", 3)
- # if build failed, show error message in irc
- self.addDefaultOption("show_build_failures", True)
- # if build success messages for "allowed to fail"
- self.addDefaultOption("show_build_success_for_allowed_to_fail", False)
- # if build failure messages for "allowed to fail"
- self.addDefaultOption("show_build_failures_for_allowed_to_fail", False)
- # if pipeline success, show success message in irc
- self.addDefaultOption("show_pipeline_success", True)
- # if pipeline failed, show error message in irc
- self.addDefaultOption("show_pipeline_failures", True)
- # build stage name what will trigger build success message
- self.addDefaultOption("last_build_stage", "")
- # build stage name what will trigger build failed message
- self.addDefaultOption("last_build_fail_stage", "")
- # custom irc message after build failed message
- self.addDefaultOption("build_fail_custom_message", "")
- # directory where located files with channels created by ii bot
- self.addDefaultOption("ii_server_directory", "irc.freenode.net")
- # listen host / name
- self.addDefaultOption("listen_host", "0.0.0.0")
- # listen port
- self.addDefaultOption("listen_port", 8000)
- # if set to true, return error for any incorrect/not allowed request
- self.addDefaultOption("http_return_error_if_not_supported", True)
- # true, "all", "any" - save all incoming json data into log.
- # false - not save
- # unsupported - only if unsupported
- self.addDefaultOption("http_save_json", "unsupported")
- # if set to True, will follow build_accept_allow_failure attributes
- self.addDefaultOption("build_accept_allow_failure", True)
- # web hook service. Supported values: gitlab, codeship, github
- self.addDefaultOption("service", self.web_hook_default_service)
- # if enabled it reverse commits order in first push due gitlab bug.
- self.addDefaultOption("push_first_push_fix", True)
- # custom irc message after pipeline failed message
- self.addDefaultOption("pipeline_fail_custom_message", "")
- # gitlab api token for access gitlab api
- self.addDefaultOption("gitlab_api_token", "")
- # gitlab api url for access gitlab api
- self.addDefaultOption("gitlab_api_url", "https://gitlab.com/api")
- # gitlab api retry count
- self.addDefaultOption("gitlab_api_retry_count", 3)
- # gitlab build retry count
- self.addDefaultOption("build_retry_count", 3)
- # build retry flag
- self.addDefaultOption("build_retry", "never")
- self.global_options.update_fields()
- def loadProjectConfiguration(self, projectConf, name):
- if self.show_info == True:
- debugChannels = set()
- url = projectConf["url"]
- project = ProjectClass()
- project.name = name
- project.url = url
- actionsDict = dict()
- channelsDict = dict()
- allowBranches = []
- denyBranches = []
- options = copy.copy(self.global_options)
- if "options" in projectConf:
- options.update(projectConf["options"])
- options.update_fields()
- if "channels" in projectConf:
- channels = projectConf["channels"]
- for channelobj in channels:
- channel = channelobj
- channelName = "#" + channel
- channelsDict[channelName] = copy.copy(options)
- if "actions" in channels[channel]:
- objects = channels[channel]["actions"]
- else:
- objects = None
- if "options" in channels[channel]:
- channelsDict[channelName].update(channels[channel]["options"])
- channelsDict[channelName].update_fields()
- if objects is not None:
- for obj in objects:
- if obj not in actionsDict:
- actionsDict[obj] = []
- actionsDict[obj].append(channelName)
- if self.show_info == True:
- debugChannels.add(channelName)
- if self.show_info == True:
- data = ""
- for channel in debugChannels:
- data = data + channel + " "
- print("{0}: {1}".format(name, data))
- if "branches" in projectConf:
- branches = projectConf["branches"]
- if "allow" in branches:
- allowBranches = branches["allow"]
- if "deny" in branches:
- denyBranches = branches["deny"]
- if len(allowBranches) == 0 and "*" not in denyBranches:
- allowBranches.append("*")
- elif len(denyBranches) == 0 and "*" not in allowBranches:
- denyBranches.append("*")
- project.actions = actionsDict
- project.channels = channelsDict
- project.options = options
- project.allow_branches = allowBranches
- project.deny_branches = denyBranches
- self.projects[url] = project
- def loadConfiguration(self, name):
- doc = self.load_yaml(name)
- #print doc
- self.loadDefaultOptions()
- if "options" in doc:
- self.global_options.update(doc["options"])
- self.global_options.update_fields()
- projectsList = doc["projects"]
- for project in projectsList:
- if type(project) is str:
- self.loadProjectConfiguration(projectsList[project], project)
- else:
- name = next(iter(project))
- self.loadProjectConfiguration(project[name], name)
|