From 082e375c299b91220b44a817538d0136ed874627 Mon Sep 17 00:00:00 2001 From: Zuul CI Bot (Fabien Boucher) Date: Nov 22 2019 15:26:17 +0000 Subject: Merge #33 `Add helper to ease project config settings` --- diff --git a/tools/project-settings-helper/README.md b/tools/project-settings-helper/README.md new file mode 100644 index 0000000..31ee57c --- /dev/null +++ b/tools/project-settings-helper/README.md @@ -0,0 +1,17 @@ +# Project Settings Helper + +This tool is a helper to configure a Project hosted on a Pagure +instance to integrate with Zuul. + +Indeed some specific settings are needed. See: +https://fedoraproject.org/wiki/Zuul-based-ci#Configure_the_repository_for_Zuul + +## Usage: + +``` +./helper.py --host src.fedoraproject.org --projects test-zuul,readerlib-installer --apikey XYZ +./helper.py --host src.fedoraproject.org --from-yaml projects.yaml --apikey XYZ +cat projects.yaml +- test-zuul +- readerlib-installer +``` diff --git a/tools/project-settings-helper/helper.py b/tools/project-settings-helper/helper.py new file mode 100755 index 0000000..b615898 --- /dev/null +++ b/tools/project-settings-helper/helper.py @@ -0,0 +1,165 @@ +#!/bin/env python3 + +import os +import sys +import logging +import argparse +import requests +import yaml + + +BASE_WH_URL = "https://softwarefactory-project.io/zuul/api/connection/%s/payload" +ZUUL_WH_SRC_F_O = BASE_WH_URL % "src.fedoraproject.io" +ZUUL_WH_PAGURE_IO = BASE_WH_URL % "pagure.io" + + +class PagureAPIClientException(Exception): + pass + + +class PagureAPIClient(): + log = logging.getLogger("zuul.PagureAPIClient") + + def __init__( + self, baseurl, api_token): + self.session = requests.Session() + self.base_url = '%s/api/0/' % baseurl + self.api_token = api_token + self.headers = {'Authorization': 'token %s' % self.api_token} + + def _manage_error(self, data, code, url, verb): + if code < 400: + return + else: + raise PagureAPIClientException( + "Unable to %s on %s (code: %s) due to: %s" % ( + verb, url, code, data + )) + + def get(self, url): + self.log.debug("Getting resource %s ..." % url) + ret = self.session.get(url, headers=self.headers) + self.log.debug("GET returned (code: %s): %s" % ( + ret.status_code, ret.text)) + return ret.json(), ret.status_code, ret.url, 'GET' + + def post(self, url, params=None): + self.log.debug( + "Posting on resource %s, params (%s) ..." % (url, params)) + ret = self.session.post(url, data=params, headers=self.headers) + self.log.debug("POST returned (code: %s): %s" % ( + ret.status_code, ret.text)) + return ret.json(), ret.status_code, ret.url, 'POST' + + def get_config(self, project): + path = '%s/options' % project + resp = self.get(self.base_url + path) + self._manage_error(*resp) + return resp[0] + + def set_config(self, project, params): + path = '%s/options/update' % project + resp = self.post(self.base_url + path, params) + self._manage_error(*resp) + return resp[0] + + def set_acl(self, project, params): + path = '%s/git/modifyacls' % project + resp = self.post(self.base_url + path, params) + self._manage_error(*resp) + return resp[0] + + def set_tags(self, project, params): + # This endpoint does not exists yet + # https://pagure.io/pagure/issue/4663 + pass + # path = '%s/tags/update' % project + # resp = self.post(self.base_url + path, params) + # self._manage_error(*resp) + # return resp[0] + + +def set_zuul_settings(client, project, gating): + logging.debug("Get settings config on %s" % project) + config = client.get_config(project) + config['Web-hooks'] = ZUUL_WH_SRC_F_O + config['pull_requests'] = True + config['notify_on_pull-request_flag'] = True + if gating: + config['open_metadata_access_to_all'] = False + # Cannot set 0 by the API so let's force it to -1 + # Then https://review.opendev.org/#/c/691254/ is needed asap. + config['Minimum_score_to_merge_pull-request'] = -1 + client.set_tags(project, ['gateit']) + client.set_config(project, config) + logging.debug("Applying new setting set on %s" % project) + acls = { + 'user_type': 'user', + 'name': 'zuul', + 'acl': 'admin' + } + client.set_acl(project, acls) + logging.debug("Adding zuul user as admin on %s" % project) + + +def process(client, projects, gating): + count = 1 + for project in projects: + logging.info('[%s/%s] Applying setting for %s' % ( + count, len(projects), project)) + try: + set_zuul_settings(client, project, gating) + count += 1 + except Exception: + logging.exception("Unable to set settings for %s" % project) + + +def load_projects_from_yaml(path): + path = os.path.expanduser(path) + if not os.path.isfile(path): + logging.error("Unable to access %s" % path) + sys.exit(1) + with open(path) as fd: + projects = yaml.load(fd, Loader=yaml.FullLoader) + return projects + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + '--host', help='Pagure instance', + default='pagure.io') + parser.add_argument( + '--projects', + help='Projects to set settings on (comma separated)') + parser.add_argument( + '--from-yaml', + help='Projects to set settings on (from a yaml file)') + parser.add_argument( + '--apikey', help='API key with modify project ACL', + required=True) + parser.add_argument( + '--gating', help='Set settings for gating', + action="store_true") + parser.add_argument( + '--loglevel', help='Log level', + default="INFO") + args = parser.parse_args() + + logging.basicConfig( + level=getattr(logging, args.loglevel.upper())) + + client = PagureAPIClient( + 'https://%s' % args.host, + args.apikey) + if not(args.projects or args.from_yaml): + logging.info("Missing argument --projects or --from-yaml") + parser.print_help() + sys.exit(1) + + if args.projects: + projects = args.projects.split(',') + if args.from_yaml: + projects = load_projects_from_yaml( + args.from_yaml) + process(client, projects, args.gating)