commit b12f70e9782aef0bc80c921f4a17bc46c46432c07b777346860b66fcedd78688 Author: Martin Pluskal Date: Mon Oct 1 11:28:15 2018 +0000 Accepting request 639243 from home:Pharaoh_Atem:SUSE_Pagure Initial packaging of Pagure for openSUSE OBS-URL: https://build.opensuse.org/request/show/639243 OBS-URL: https://build.opensuse.org/package/show/devel:tools:scm/pagure?expand=0&rev=1 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +## Default LFS +*.7z filter=lfs diff=lfs merge=lfs -text +*.bsp filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.gem filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.lz filter=lfs diff=lfs merge=lfs -text +*.lzma filter=lfs diff=lfs merge=lfs -text +*.obscpio filter=lfs diff=lfs merge=lfs -text +*.oxt filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.rpm filter=lfs diff=lfs merge=lfs -text +*.tbz filter=lfs diff=lfs merge=lfs -text +*.tbz2 filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.txz filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/flask_fas_openid.py b/flask_fas_openid.py new file mode 100644 index 0000000..9334f06 --- /dev/null +++ b/flask_fas_openid.py @@ -0,0 +1,349 @@ +# -*- coding: utf-8 -*- +# Flask-FAS-OpenID - A Flask extension for authorizing users with FAS-OpenID +# +# Primary maintainer: Patrick Uiterwijk +# +# Copyright (c) 2013, Patrick Uiterwijk +# This file is part of python-fedora +# +# python-fedora is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# python-fedora 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with python-fedora; if not, see + +''' +FAS-OpenID authentication plugin for the flask web framework + +.. moduleauthor:: Patrick Uiterwijk + +..versionadded:: 0.3.33 +''' +from functools import wraps + +import logging +import time +from munch import Munch +import flask +try: + from flask import _app_ctx_stack as stack +except ImportError: + from flask import _request_ctx_stack as stack + +from openid.consumer import consumer +from openid.fetchers import setDefaultFetcher, Urllib2Fetcher +from openid.extensions import pape, sreg, ax +from openid_cla import cla +from openid_teams import teams + +import six +log = logging.getLogger(__name__) + + +# http://flask.pocoo.org/snippets/45/ +def request_wants_json(): + ''' Return wether the user requested the data in JSON or not. ''' + best = flask.request.accept_mimetypes \ + .best_match(['application/json', 'text/html']) + return best == 'application/json' and \ + flask.request.accept_mimetypes[best] > \ + flask.request.accept_mimetypes['text/html'] + + +class FASJSONEncoder(flask.json.JSONEncoder): + """ Dedicated JSON encoder for the FAS openid information. """ + + def default(self, o): + """Implement this method in a subclass such that it returns a + serializable object for ``o``, or calls the base implementation (to + raise a ``TypeError``). + + For example, to support arbitrary iterators, you could implement + default like this:: + + def default(self, o): + try: + iterable = iter(o) + except TypeError: + pass + else: + return list(iterable) + return JSONEncoder.default(self, o) + """ + if isinstance(o, (set, frozenset)): + return list(o) + return flask.json.JSONEncoder.default(self, o) + + +class FAS(object): + """ The Flask plugin. """ + + def __init__(self, app=None): + self.postlogin_func = None + self.app = app + if self.app is not None: + self.init_app(app) + + def init_app(self, app): + """ Constructor for the Flask application. """ + self.app = app + app.config.setdefault('FAS_OPENID_ENDPOINT', + 'https://id.fedoraproject.org/openid/') + app.config.setdefault('FAS_OPENID_CHECK_CERT', True) + + if not self.app.config['FAS_OPENID_CHECK_CERT']: + setDefaultFetcher(Urllib2Fetcher()) + + # json_encoder is only available from flask 0.10 + version = flask.__version__.split('.') + assume_recent = False + try: + major = int(version[0]) + minor = int(version[1]) + except ValueError: + # We'll assume we're using a recent enough flask as the packages + # of old versions used sane version numbers. + assume_recent = True + + if assume_recent or (major > 0 or minor >= 10): + self.app.json_encoder = FASJSONEncoder + + @app.route('/_flask_fas_openid_handler/', methods=['GET', 'POST']) + def flask_fas_openid_handler(): + """ Endpoint for OpenID results. """ + return self._handle_openid_request() + + app.before_request(self._check_session) + + def postlogin(self, f): + """Marks a function as post login handler. This decorator calls your + function after the login has been performed. + """ + self.postlogin_func = f + return f + + def _handle_openid_request(self): + return_url = flask.session.get('FLASK_FAS_OPENID_RETURN_URL', None) + cancel_url = flask.session.get('FLASK_FAS_OPENID_CANCEL_URL', None) + base_url = self.normalize_url(flask.request.base_url) + oidconsumer = consumer.Consumer(flask.session, None) + info = oidconsumer.complete(flask.request.values, base_url) + display_identifier = info.getDisplayIdentifier() + + if info.status == consumer.FAILURE and display_identifier: + return 'FAILURE. display_identifier: %s' % display_identifier + elif info.status == consumer.CANCEL: + if cancel_url: + return flask.redirect(cancel_url) + return 'OpenID request was cancelled' + elif info.status == consumer.SUCCESS: + if info.endpoint.server_url != \ + self.app.config['FAS_OPENID_ENDPOINT']: + log.warn('Claim received from invalid issuer: %s', + info.endpoint.server_url) + return 'Invalid provider issued claim!' + + sreg_resp = sreg.SRegResponse.fromSuccessResponse(info) + teams_resp = teams.TeamsResponse.fromSuccessResponse(info) + cla_resp = cla.CLAResponse.fromSuccessResponse(info) + ax_resp = ax.FetchResponse.fromSuccessResponse(info) + user = {'fullname': '', 'username': '', 'email': '', + 'timezone': '', 'cla_done': False, 'groups': []} + if not sreg_resp: + # If we have no basic info, be gone with them! + return flask.redirect(cancel_url) + user['username'] = sreg_resp.get('nickname') + user['fullname'] = sreg_resp.get('fullname') + user['email'] = sreg_resp.get('email') + user['timezone'] = sreg_resp.get('timezone') + user['login_time'] = time.time() + if cla_resp: + user['cla_done'] = cla.CLA_URI_FEDORA_DONE in cla_resp.clas + if teams_resp: + # The groups do not contain the cla_ groups + user['groups'] = frozenset(teams_resp.teams) + if ax_resp: + ssh_keys = ax_resp.get( + 'http://fedoauth.org/openid/schema/SSH/key') + if isinstance(ssh_keys, (list, tuple)): + ssh_keys = '\n'.join( + ssh_key + for ssh_key in ssh_keys + if ssh_key.strip() + ) + if ssh_keys: + user['ssh_key'] = ssh_keys + user['gpg_keyid'] = ax_resp.get( + 'http://fedoauth.org/openid/schema/GPG/keyid') + flask.session['FLASK_FAS_OPENID_USER'] = user + flask.session.modified = True + if self.postlogin_func is not None: + self._check_session() + return self.postlogin_func(return_url) + else: + return flask.redirect(return_url) + else: + return 'Strange state: %s' % info.status + + def _check_session(self): + if 'FLASK_FAS_OPENID_USER' not in flask.session \ + or flask.session['FLASK_FAS_OPENID_USER'] is None: + flask.g.fas_user = None + else: + user = flask.session['FLASK_FAS_OPENID_USER'] + # Add approved_memberships to provide backwards compatibility + # New applications should only use g.fas_user.groups + user['approved_memberships'] = [] + for group in user['groups']: + membership = dict() + membership['name'] = group + user['approved_memberships'].append(Munch.fromDict(membership)) + flask.g.fas_user = Munch.fromDict(user) + flask.g.fas_user.groups = frozenset(flask.g.fas_user.groups) + flask.g.fas_session_id = 0 + + def _check_safe_root(self, url): + if url is None: + return None + if url.startswith(flask.request.url_root) or url.startswith('/'): + # A URL inside the same app is deemed to always be safe + return url + return None + + def login(self, username=None, password=None, return_url=None, + cancel_url=None, groups=['_FAS_ALL_GROUPS_']): + """Tries to log in a user. + + Sets the user information on :attr:`flask.g.fas_user`. + Will set 0 to :attr:`flask.g.fas_session_id, for compatibility + with flask_fas. + + :kwarg username: Not used, but accepted for compatibility with the + flask_fas module + :kwarg password: Not used, but accepted for compatibility with the + flask_fas module + :kwarg return_url: The URL to forward the user to after login + :kwarg groups: A string or a list of group the user should belong + to to be authentified. + :returns: True if the user was succesfully authenticated. + :raises: Might raise an redirect to the OpenID endpoint + """ + if return_url is None: + if 'next' in flask.request.args.values(): + return_url = flask.request.args.values['next'] + else: + return_url = flask.request.url_root + # This makes sure that we only allow stuff where + # ?next= value is in a safe root (the application + # root) + return_url = (self._check_safe_root(return_url) or + flask.request.url_root) + session = {} + oidconsumer = consumer.Consumer(session, None) + try: + request = oidconsumer.begin(self.app.config['FAS_OPENID_ENDPOINT']) + except consumer.DiscoveryFailure as exc: + # VERY strange, as this means it could not discover an OpenID + # endpoint at FAS_OPENID_ENDPOINT + log.warn(exc) + return 'discoveryfailure' + if request is None: + # Also very strange, as this means the discovered OpenID + # endpoint is no OpenID endpoint + return 'no-request' + + if isinstance(groups, six.string_types): + groups = [groups] + + request.addExtension(sreg.SRegRequest( + required=['nickname', 'fullname', 'email', 'timezone'])) + request.addExtension(pape.Request([])) + request.addExtension(teams.TeamsRequest(requested=groups)) + request.addExtension(cla.CLARequest( + requested=[cla.CLA_URI_FEDORA_DONE])) + + ax_req = ax.FetchRequest() + ax_req.add(ax.AttrInfo( + type_uri='http://fedoauth.org/openid/schema/GPG/keyid')) + ax_req.add(ax.AttrInfo( + type_uri='http://fedoauth.org/openid/schema/SSH/key', + count='unlimited')) + request.addExtension(ax_req) + + trust_root = self.normalize_url(flask.request.url_root) + return_to = trust_root + '_flask_fas_openid_handler/' + + flask.session['FLASK_FAS_OPENID_RETURN_URL'] = return_url + flask.session['FLASK_FAS_OPENID_CANCEL_URL'] = cancel_url + + if request_wants_json(): + output = request.getMessage(trust_root, + return_to=return_to).toPostArgs() + output['server_url'] = request.endpoint.server_url + return flask.jsonify(output) + elif request.shouldSendRedirect(): + redirect_url = request.redirectURL(trust_root, return_to, False) + return flask.redirect(redirect_url) + else: + return request.htmlMarkup( + trust_root, return_to, + form_tag_attrs={'id': 'openid_message'}, immediate=False) + + def logout(self): + '''Logout the user associated with this session + ''' + flask.session['FLASK_FAS_OPENID_USER'] = None + flask.g.fas_session_id = None + flask.g.fas_user = None + flask.session.modified = True + + def normalize_url(self, url): + ''' Replace the scheme prefix of a url with our preferred scheme. + ''' + scheme = self.app.config['PREFERRED_URL_SCHEME'] + scheme_index = url.index('://') + return scheme + url[scheme_index:] + + +# This is a decorator we can use with any HTTP method (except login, obviously) +# to require a login. +# If the user is not logged in, it will redirect them to the login form. +# http://flask.pocoo.org/docs/patterns/viewdecorators/#login-required-decorator +def fas_login_required(function): + """ Flask decorator to ensure that the user is logged in against FAS. + To use this decorator you need to have a function named 'auth_login'. + Without that function the redirect if the user is not logged in will not + work. + """ + @wraps(function) + def decorated_function(*args, **kwargs): + if flask.g.fas_user is None: + return flask.redirect(flask.url_for('auth_login', + next=flask.request.url)) + return function(*args, **kwargs) + return decorated_function + + +def cla_plus_one_required(function): + """ Flask decorator to retrict access to CLA+1. + To use this decorator you need to have a function named 'auth_login'. + Without that function the redirect if the user is not logged in will not + work. + """ + @wraps(function) + def decorated_function(*args, **kwargs): + if flask.g.fas_user is None or not flask.g.fas_user.cla_done \ + or len(flask.g.fas_user.groups) < 1: + # FAS-OpenID does not return cla_ groups + return flask.redirect(flask.url_for('auth_login', + next=flask.request.url)) + else: + return function(*args, **kwargs) + return decorated_function diff --git a/pagure-5.0-default-example-cfg.patch b/pagure-5.0-default-example-cfg.patch new file mode 100644 index 0000000..2b07765 --- /dev/null +++ b/pagure-5.0-default-example-cfg.patch @@ -0,0 +1,130 @@ +diff -rup pagure-5.0/files/gitolite3.rc pagure-5.0.cfg-defs/files/gitolite3.rc +--- pagure-5.0/files/gitolite3.rc 2018-08-20 05:28:38.000000000 -0400 ++++ pagure-5.0.cfg-defs/files/gitolite3.rc 2018-09-24 17:29:01.927780974 -0400 +@@ -16,7 +16,7 @@ + + # ------------------------------------------------------------------ + +- GL_REPO_BASE => '/path/to/git/repositories', ++ GL_REPO_BASE => '/srv/gitolite/repositories', + + # default umask gives you perms of '0700'; see the rc file docs for + # how/why you might change this +diff -rup pagure-5.0/files/pagure.cfg.sample pagure-5.0.cfg-defs/files/pagure.cfg.sample +--- pagure-5.0/files/pagure.cfg.sample 2018-09-24 15:57:50.000000000 -0400 ++++ pagure-5.0.cfg-defs/files/pagure.cfg.sample 2018-09-24 17:29:01.928780964 -0400 +@@ -68,21 +68,21 @@ GIT_URL_GIT = 'git://localhost.localdoma + + ### Folder containing to the git repos + GIT_FOLDER = os.path.join( +- os.path.abspath(os.path.dirname(__file__)), +- '..', +- 'repos' ++ '/srv', ++ 'gitolite', ++ 'repositories' + ) + + REPOSPANNER_PSEUDO_FOLDER = os.path.join( +- os.path.abspath(os.path.dirname(__file__)), +- '..', ++ '/srv', ++ 'gitolite', + 'pseudo' + ) + + ### Folder containing the clones for the remote pull-requests + REMOTE_GIT_FOLDER = os.path.join( +- os.path.abspath(os.path.dirname(__file__)), +- '..', ++ '/srv', ++ 'gitolite', + 'remotes' + ) + +@@ -92,21 +92,23 @@ VIRUS_SCAN_ATTACHMENTS = False + + ### Configuration file for gitolite + GITOLITE_CONFIG = os.path.join( +- os.path.abspath(os.path.dirname(__file__)), +- '..', ++ '/srv', ++ 'gitolite', ++ '.gitolite', ++ 'conf', + 'gitolite.conf' + ) + + + ### Home folder of the gitolite user + ### Folder where to run gl-compile-conf from +-GITOLITE_HOME = None ++GITOLITE_HOME = '/srv/gitolite' + + ### Version of gitolite used: 2 or 3? + GITOLITE_VERSION = 3 + + ### Folder containing all the public ssh keys for gitolite +-GITOLITE_KEYDIR = None ++GITOLITE_KEYDIR = os.path.join(GITOLITE_HOME, '.gitolite', 'keydir') + + ### Path to the gitolite.rc file + GL_RC = None +diff -rup pagure-5.0/files/pagure.conf pagure-5.0.cfg-defs/files/pagure.conf +--- pagure-5.0/files/pagure.conf 2018-08-23 15:08:03.000000000 -0400 ++++ pagure-5.0.cfg-defs/files/pagure.conf 2018-09-24 17:29:01.928780964 -0400 +@@ -29,9 +29,9 @@ + ## Use secure TLSv1.1 and TLSv1.2 ciphers + #Header always add Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" + +- #SSLCertificateFile /etc/pki/tls/....crt +- #SSLCertificateChainFile /etc/pki/tls/....intermediate.crt +- #SSLCertificateKeyFile /etc/pki/tls/....key ++ #SSLCertificateFile /etc/ssl/....crt ++ #SSLCertificateChainFile /etc/ssl/....intermediate.crt ++ #SSLCertificateKeyFile /etc/ssl/....key + + #Alias /static /usr/lib/pythonX.Y/site-packages/pagure/static/ + +@@ -60,24 +60,24 @@ + ## Use secure TLSv1.1 and TLSv1.2 ciphers + #Header always add Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" + +- #SSLCertificateFile /etc/pki/tls/....crt +- #SSLCertificateChainFile /etc/pki/tls/....intermediate.crt +- #SSLCertificateKeyFile /etc/pki/tls/....key ++ #SSLCertificateFile /etc/ssl/....crt ++ #SSLCertificateChainFile /etc/ssl/....intermediate.crt ++ #SSLCertificateKeyFile /etc/ssl/....key + + #Alias /static /usr/lib/pythonX.Y/site-packages/pagure/static/ +- #Alias /releases /var/www/releases ++ #Alias /releases /srv/www/pagure-releases + + ## Section used to support cloning git repo over http (https in this case) +- #SetEnv GIT_PROJECT_ROOT /path/to/git/repositories ++ #SetEnv GIT_PROJECT_ROOT /srv/gitolite/repositories + +- #AliasMatch ^/(.*/objects/[0-9a-f]{2}/[0-9a-f]{38})$ /path/to/git/repositories/$1 +- #AliasMatch ^/(.*/objects/pack/pack-[0-9a-f]{40}.(pack|idx))$ /path/to/git/repositories/$1 ++ #AliasMatch ^/(.*/objects/[0-9a-f]{2}/[0-9a-f]{38})$ /srv/gitolite/repositories/$1 ++ #AliasMatch ^/(.*/objects/pack/pack-[0-9a-f]{40}.(pack|idx))$ /srv/gitolite/repositories/$1 + #ScriptAliasMatch \ + #"(?x)^/(.*/(HEAD | \ + #info/refs | \ + #objects/info/[^/]+ | \ + #git-(upload|receive)-pack))$" \ +- #/usr/libexec/git-core/git-http-backend/$1 ++ #/usr/lib/git/git-http-backend/$1 + + # + #WSGIProcessGroup pagure +@@ -106,7 +106,7 @@ + # + # + +- # ++ # + #Options +Indexes + # + diff --git a/pagure-5.0.1.tar.gz b/pagure-5.0.1.tar.gz new file mode 100644 index 0000000..2df5d6d --- /dev/null +++ b/pagure-5.0.1.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f80add9dd706e5b59f0b1f9cf44fe2820b5b2573aea390602c17cbd3a742da58 +size 21696775 diff --git a/pagure-README.SUSE b/pagure-README.SUSE new file mode 100644 index 0000000..9859d18 --- /dev/null +++ b/pagure-README.SUSE @@ -0,0 +1,107 @@ +# Setting up pagure + +0. Prepare the filesystem (this step is usually performed on package install) + +mkdir -p /srv/www/pagure-releases +mkdir -p /srv/gitolite/repositories/{,docs,forks,requests,tickets} +mkdir -p /srv/gitolite/pseudo +mkdir -p /srv/gitolite/remotes +mkdir -p /srv/gitolite/.gitolite/{conf,keydir,logs} + +touch /srv/gitolite/.gitolite/conf/gitolite.conf + +cp /usr/share/doc/packages/pagure/gitolite3.rc /srv/gitolite/.gitolite.rc + +chown git:git -R /srv/gitolite +chown git:git /srv/www/pagure-releases + +mkdir -p /srv/www/run + +setfacl -m user:wwwrun:rx --default /srv/gitolite +setfacl -Rdm user:wwwrun:rx /srv/gitolite +setfacl -Rm user:wwwrun:rx /srv/gitolite + +1. Install and set up a database + +Option A: PostgreSQL + +Note: If your PostgreSQL server is not on the same machine, just install 'python3-psycopg2' +on the pagure host machine and follow the installation and database creation steps below +on the designated database server. This also requires the database port opened on the +database server's firewall. + +zypper install postgresql-server +systemctl start postgresql + +A1. Edit /var/lib/pgsql/data/pg_hba.conf and change auth method from `ident` to `md5` for localhost + +A2. Create the pagure database + +sudo -u postgres psql + +CREATE DATABASE pagure; +CREATE USER pagure; +ALTER USER pagure WITH ENCRYPTED PASSWORD '--PagureDBUserPW--'; +GRANT ALL PRIVILEGES ON DATABASE pagure to pagure; +GRANT ALL PRIVILEGES ON ALL tables IN SCHEMA public TO pagure; +GRANT ALL PRIVILEGES ON ALL sequences IN SCHEMA public TO pagure; +\q + +A3. Enable and restart PostgreSQL + +systemctl stop postgresql +systemctl enable --now postgresql + +Option B: MariaDB + +Note: If your MariaDB server is not on the same machine, just install 'python3-PyMySQL' +on the pagure host machine and follow the installation and database creation steps below +on the designated database server. This also requires the database port opened on the +database server's firewall. + +zypper install mariadb mariadb-client +systemctl enable --now mariadb +mysql_secure_installation + +B1. Create the pagure database + +mysql -u root -p + +mysql> create database pagure; +mysql> grant all privileges on pagure.* to pagure identified by '--PagureDBUserPW--'; +mysql> flush privileges; +mysql> exit + +2. Install Redis + +zypper install redis + +3. Configure redis + +cp /etc/redis/default.conf.example /etc/redis/default.conf +chown root:redis /etc/redis/default.conf +systemctl enable --now redis@default.service + +4. Edit /etc/pagure/pagure.cfg to set up pagure settings as appropriate. + +For details on all the options in pagure.cfg, see https://docs.pagure.org/pagure/configuration.html + +5. Populate the database + +python3 /usr/share/pagure/pagure_createdb.py -c /etc/pagure/pagure.cfg -i /etc/pagure/alembic.ini + +6. Edit /etc/apache2/vhosts.d/pagure.conf to set up web settings as appropriate. + +7. Open ports in the firewall as appropriate + +firewall-cmd --add-service=ssh +firewall-cmd --add-service=http +firewall-cmd --add-service=https +firewall-cmd --add-service=redis +firewall-cmd --runtime-to-permanent + +8. Enable and start pagure_worker and pagure_gitolite_worker + +9. Enable and start apache2, or restart if it's already running + +For more details on setup, take a look at the official Pagure documentation: https://docs.pagure.org/pagure/ diff --git a/pagure.changes b/pagure.changes new file mode 100644 index 0000000..c16a6b3 --- /dev/null +++ b/pagure.changes @@ -0,0 +1,109 @@ +------------------------------------------------------------------- +Sun Sep 30 15:06:24 UTC 2018 - Neal Gompa + +- Add missing directory to directory structure + +------------------------------------------------------------------- +Sat Sep 29 22:28:26 UTC 2018 - Neal Gompa + +- Drop unnecessary systemd build dependency + +------------------------------------------------------------------- +Sat Sep 29 21:15:49 UTC 2018 - Neal Gompa + +- Add missing rcFOO symlinks to systemd services + +------------------------------------------------------------------- +Sat Sep 29 20:29:04 UTC 2018 - Neal Gompa + +- Update to 5.0.1 + + Multiple adjustments to the scripts keyhelper and aclchecker + + Only enforce Signed-Off-By on the code repo of a project + + Sign-off the merge commits when the project enforces it + + Switch from GIT_SORT_TIME to GIT_SORT_NONE to preserve + 'git log'-like commit ordering + + Add reporter and assignee to notification emails headers + + Fix various visual glitches +- Restore symlinks clobbered by setuptools' creation of archive + +------------------------------------------------------------------- +Mon Sep 24 21:35:35 UTC 2018 - Neal Gompa + +- Rebase to 5.0 + + Pagure now runs on Python 3 + + The UI has been completely redesigned + + Theming has been redesigned, and new themes are included as subpackages + + Many new API endpoints have been added + + Rework how git hooks work to rely on a single file for efficiency + + Expanded functionality included in the pagure-admin command +- Pagure defaults to the chameleon theme for openSUSE +- Drop all upstreamed patches +- Refresh example configuration patch + +------------------------------------------------------------------- +Sun Jul 22 00:48:43 UTC 2018 - Neal Gompa + +- Update to 4.0.4 +- Refresh config fix patch for pagure-milters + +------------------------------------------------------------------- +Wed Jul 11 04:05:20 UTC 2018 - Neal Gompa + +- Add missing requirement on python-Pillow + +------------------------------------------------------------------- +Wed Jul 11 01:21:18 UTC 2018 - Neal Gompa + +- Drop python2-trollius-redis requirement since it's not actually used + +------------------------------------------------------------------- +Sun Jun 10 00:04:18 UTC 2018 - Neal Gompa + +- Backport patch to make syntax highlighting threshold configurable + +------------------------------------------------------------------- +Sat Jun 9 21:56:34 UTC 2018 - Neal Gompa + +- Bundle an internal pagure-celery binary to use stock celery + with Python 2 +- Switch to a sed call instead of a patch to fix systemd units + to use correct libexecdir + +------------------------------------------------------------------- +Sat Jun 9 13:20:33 UTC 2018 - Neal Gompa + +- Fix syntax error in gitolite3.rc file + +------------------------------------------------------------------- +Fri Jun 8 11:13:43 UTC 2018 - Neal Gompa + +- Switch from /srv/pagure to /srv/gitolite to use the already + setup gitolite directory structure + +------------------------------------------------------------------- +Mon Jun 4 04:45:53 UTC 2018 - Neal Gompa + +- Fix pagure-ev to use correct libexecdir +- Fix pagure-milters to call correct function to load config + +------------------------------------------------------------------- +Mon Jun 4 03:36:38 UTC 2018 - Neal Gompa + +- Install gitolite configuration + +------------------------------------------------------------------- +Mon Jun 4 01:15:19 UTC 2018 - Neal Gompa + +- Prepare more of the filesystem tree as part of the packaging +- Refine README.SUSE to more closely match the required steps + +------------------------------------------------------------------- +Sat Jun 2 17:44:49 UTC 2018 - Neal Gompa + +- Refresh configuration patch to match SUSE sematics +- Add README.SUSE file for basic setup quick start guide + +------------------------------------------------------------------- +Mon May 28 22:00:06 UTC 2018 - Neal Gompa + +- Initial packaging based on Mageia packaging diff --git a/pagure.spec b/pagure.spec new file mode 100644 index 0000000..d684b22 --- /dev/null +++ b/pagure.spec @@ -0,0 +1,635 @@ +# +# spec file for package pagure +# +# Copyright (c) 2018 Neal Gompa . +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + + +# Prevent dep generators from trying to process static stuff and stall out +# We only need to read the python metadata anyway +%global __provides_exclude_from ^%{python3_sitelib}/pagure/.*$ +%global __requires_exclude_from ^%{python3_sitelib}/pagure/.*$ + + +Name: pagure +Version: 5.0.1 +Release: 0 +Summary: A git-centered forge +Group: Development/Tools/Version Control +# Pagure itself is GPL-2.0-or-later; flask_fas_openid.py is LGPL-2.1-or-later +License: GPL-2.0-or-later AND LGPL-2.1-or-later +URL: https://pagure.io/pagure +Source0: https://pagure.io/releases/pagure/%{name}-%{version}.tar.gz + +# Vendor in the single file from python-fedora that's needed +# This way, we avoid having to pull in all of python-fedora +# This file is licensed LGPL-2.1-or-later, per https://github.com/fedora-infra/python-fedora/blob/develop/README.rst#license +Source1: https://raw.githubusercontent.com/fedora-infra/python-fedora/4719f10b3af1cf068e969387eab7df7e935003cd/flask_fas_openid.py + +# SUSE-specific README providing a quickstart guide +Source10: pagure-README.SUSE + + +# SUSE-specific fixes +# Change the defaults in the example config to match packaging +Patch1000: pagure-5.0-default-example-cfg.patch + +BuildArch: noarch + + +BuildRequires: apache2 +BuildRequires: fdupes +BuildRequires: systemd-rpm-macros +BuildRequires: python3-devel +BuildRequires: python3-setuptools + +BuildRequires: python3-alembic +BuildRequires: python3-arrow +BuildRequires: python3-bcrypt +BuildRequires: python3-binaryornot +BuildRequires: python3-bleach +BuildRequires: python3-blinker +BuildRequires: python3-chardet +BuildRequires: python3-cryptography +BuildRequires: python3-docutils +BuildRequires: python3-Flask +BuildRequires: python3-Flask-WTF +# Pagure is currently not compatible with Markdown v3 +BuildRequires: python3-Markdown < 3 +BuildRequires: python3-nose +BuildRequires: python3-Pillow +BuildRequires: python3-psutil +BuildRequires: python3-pygit2 >= 0.24.0 +BuildRequires: python3-Pygments +#BuildRequires: python3-fedora-flask +BuildRequires: python3-python3-openid +BuildRequires: python3-python-openid-cla +BuildRequires: python3-python-openid-teams +BuildRequires: python3-SQLAlchemy > 0.8 +BuildRequires: python3-straight-plugin +BuildRequires: python3-WTForms +BuildRequires: python3-munch +BuildRequires: python3-redis + + +Requires: python3-alembic +Requires: python3-arrow +Requires: python3-bcrypt +Requires: python3-binaryornot +Requires: python3-bleach +Requires: python3-blinker +Requires: python3-celery +Requires: python3-chardet +Requires: python3-cryptography +Requires: python3-docutils +Requires: python3-Flask +Requires: python3-Flask-WTF +# Pagure is currently not compatible with Markdown v3 +Requires: python3-Markdown < 3 +Requires: python3-Pillow +Requires: python3-psutil +Requires: python3-pygit2 >= 0.24.0 +Requires: python3-Pygments +#Requires: python3-fedora-flask +Requires: python3-python3-openid +Requires: python3-python-openid-cla +Requires: python3-python-openid-teams +Requires: python3-SQLAlchemy > 0.8 +Requires: python3-straight-plugin +Requires: python3-WTForms +Requires: python3-munch +Requires: python3-redis + +Requires: apache2-mod_wsgi-python3 + +# Required for celery +Requires: python3-pytz + +# Required for database setup/migrations +Requires: python3-dbm +Requires: python3-kitchen +Requires: python3-requests + +# If using PostgreSQL, the correct driver should be installed +Recommends: (python3-psycopg2 if postgresql-server) + +# If using MariaDB/MySQL, the correct driver should be installed +Recommends: (python3-PyMySQL if mysql-server) + + +# The default theme is required +Requires: %{name}-theme-default + +%{?systemd_requires} + +# No dependency of the app per se, but required to make it working. +OrderWithRequires: gitolite >= 3.0 +Requires(pre): gitolite >= 3.0 +Requires: gitolite >= 3.0 +Requires(post): user(wwwrun) + +%description +Pagure is a light-weight git-centered forge based on pygit2. + +Currently, Pagure offers a web-interface for git repositories, a ticket +system and possibilities to create new projects, fork existing ones and +create/merge pull-requests across or within projects. + +For steps on how to set up the system after installing this package, +please read %{_docdir}/%{name}/README.SUSE. + + +%package theme-upstream +Summary: Base web interface theme +Requires: %{name} = %{version}-%{release} +%description theme-upstream +This package provides the web interface assets for styling +a Pagure server with the base upstream look and feel. + + +%package theme-pagureio +Summary: Web interface theme used for Pagure.io +Requires: %{name} = %{version}-%{release} +%description theme-pagureio +This package provides the web interface assets for styling +a Pagure server with the same look and feel as Pagure.io. + + +%package theme-srcfpo +Summary: Web interface theme used for src.fedoraproject.org +Requires: %{name} = %{version}-%{release} +%description theme-srcfpo +This package provides the web interface assets for styling +a Pagure server with the same look and feel as src.fedoraproject.org. + + +%package theme-chameleon +Summary: Web interface based on openSUSE's chameleon theme +Requires: %{name} = %{version}-%{release} +%description theme-chameleon +This package provides the web interface assets for styling +a Pagure server with the same look and feel as openSUSE Infrastructure. + + +%package theme-default-upstream +Summary: Default web interface theme from upstream +Conflicts: %{name}-theme-default +Provides: %{name}-theme-default +Requires: %{name}-theme-upstream = %{version}-%{release} +%description theme-default-upstream +This package sets the default web interface assets used for +a Pagure server running as shipped by upstream. + + +%package theme-default-openSUSE +Summary: Default web interface theme for openSUSE +Conflicts: %{name}-theme-default +Provides: %{name}-theme-default +Requires: %{name}-theme-chameleon = %{version}-%{release} +Enhances: (%{name} and branding-openSUSE) +RemovePathPostfixes: .openSUSE +%description theme-default-openSUSE +This package sets the default web interface assets used for +a Pagure server running on openSUSE. + + +%package milters +Summary: Milter to integrate pagure with emails +BuildRequires: systemd-rpm-macros +Requires: %{name} = %{version}-%{release} +Requires: python3-pymilter +%{?systemd_requires} +# It would work with sendmail but we configure things (like the tempfile) +# to work with postfix +Requires: postfix +%description milters +Milters (Mail filters) allowing the integration of pagure and emails. +This is useful for example to allow commenting on a ticket by email. + + +%package ev +Summary: EventSource server for pagure +BuildRequires: systemd-rpm-macros +Requires: %{name} = %{version}-%{release} +Requires: python3-Trololio +%{?systemd_requires} +%description ev +Pagure comes with an eventsource server allowing live update of the pages +supporting it. This package provides it. + + +%package webhook +Summary: Web-Hook server for pagure +BuildRequires: systemd-rpm-macros +Requires: %{name} = %{version}-%{release} +%{?systemd_requires} +%description webhook +Pagure comes with an webhook server allowing http callbacks for any action +done on a project. This package provides it. + + +%package ci +Summary: A CI service for pagure +BuildRequires: systemd-rpm-macros +Requires: %{name} = %{version}-%{release} +Requires: python3-python-jenkins +%{?systemd_requires} +%description ci +Pagure comes with a continuous integration service, currently supporting +only jenkins but extendable to others. +With this service, your CI server will be able to report the results of the +build on the pull-requests opened to your project. + + +%package logcom +Summary: The logcom service for pagure +BuildRequires: systemd-rpm-macros +Requires: %{name} = %{version}-%{release} +%{?systemd_requires} +%description logcom +pagure-logcom contains the service that logs commits into the database so that +the activity calendar heatmap is filled. + + +%package loadjson +Summary: The loadjson service for pagure +BuildRequires: systemd-rpm-macros +Requires: %{name} = %{version}-%{release} +%{?systemd_requires} +%description loadjson +pagure-loadjson is the service allowing to update the database with the +information provided in the JSON blobs that are stored in the tickets (and +in the future pull-requests) git repo. + + +%package mirror +Summary: The mirroring service for pagure +BuildRequires: systemd-rpm-macros +Requires: %{name} = %{version}-%{release} +%{?systemd_requires} +%description mirror +pagure-mirror is the service mirroring projects that asked for it outside +of this pagure instance. + + +%prep +%autosetup -p1 + +# Vendor in the file needed from python-fedora +install -pm 0644 %{SOURCE1} pagure/ui +sed -e "s/import flask_fas_openid/from pagure.ui import flask_fas_openid as flask_fas_openid/" -i pagure/ui/fas_login.py + +# Install README.SUSE file +install -pm 0644 %{SOURCE10} README.SUSE + + +%build +%py3_build + + +%install +%py3_install + +# Install apache configuration file +mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/apache2/vhosts.d +install -p -m 644 files/pagure.conf $RPM_BUILD_ROOT/%{_sysconfdir}/apache2/vhosts.d/pagure.conf + +# Install configuration file +mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/pagure +install -p -m 644 files/pagure.cfg.sample $RPM_BUILD_ROOT/%{_sysconfdir}/pagure/pagure.cfg + +# Install WSGI file +mkdir -p $RPM_BUILD_ROOT/%{_datadir}/pagure +install -p -m 644 files/pagure.wsgi $RPM_BUILD_ROOT/%{_datadir}/pagure/pagure.wsgi +install -p -m 644 files/doc_pagure.wsgi $RPM_BUILD_ROOT/%{_datadir}/pagure/doc_pagure.wsgi + +# Install the createdb script +install -p -m 644 createdb.py $RPM_BUILD_ROOT/%{_datadir}/pagure/pagure_createdb.py + +# Install the api_key_expire_mail.py script +install -p -m 644 files/api_key_expire_mail.py $RPM_BUILD_ROOT/%{_datadir}/pagure/api_key_expire_mail.py + +# Install the keyhelper and aclcheck scripts +mkdir -p $RPM_BUILD_ROOT/%{_libexecdir}/pagure +install -p -m 755 files/aclchecker.py $RPM_BUILD_ROOT/%{_libexecdir}/pagure/aclchecker.py +install -p -m 755 files/keyhelper.py $RPM_BUILD_ROOT/%{_libexecdir}/pagure/keyhelper.py + +# Install the alembic configuration file +install -p -m 644 files/alembic.ini $RPM_BUILD_ROOT/%{_sysconfdir}/pagure/alembic.ini + +# Install the alembic revisions +cp -r alembic $RPM_BUILD_ROOT/%{_datadir}/pagure + +# Install the systemd file for the worker +mkdir -p $RPM_BUILD_ROOT/%{_unitdir} +install -p -m 644 files/pagure_worker.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_worker.service + +# Install the systemd file for the gitolite worker +install -p -m 644 files/pagure_gitolite_worker.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_gitolite_worker.service + +# Install the systemd file for the web-hook +install -p -m 644 files/pagure_webhook.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_webhook.service + +# Install the systemd file for the ci service +install -p -m 644 files/pagure_ci.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_ci.service + +# Install the systemd file for the logcom service +install -p -m 644 files/pagure_logcom.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_logcom.service + +# Install the systemd file for the loadjson service +install -p -m 644 files/pagure_loadjson.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_loadjson.service + +# Install the systemd file for the mirror service +install -p -m 644 files/pagure_mirror.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_mirror.service + +# Install the systemd file for the script sending reminder about API key +# expiration +install -p -m 644 files/pagure_api_key_expire_mail.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_api_key_expire_mail.service +install -p -m 644 files/pagure_api_key_expire_mail.timer \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_api_key_expire_mail.timer + +# Install the milter files +mkdir -p $RPM_BUILD_ROOT/%{_tmpfilesdir} +install -p -m 0644 pagure-milters/milter_tempfile.conf \ + $RPM_BUILD_ROOT/%{_tmpfilesdir}/%{name}-milter.conf +install -p -m 644 pagure-milters/pagure_milter.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_milter.service +install -p -m 644 pagure-milters/comment_email_milter.py \ + $RPM_BUILD_ROOT/%{_datadir}/pagure/comment_email_milter.py + +# Install the eventsource +mkdir -p $RPM_BUILD_ROOT/%{_libexecdir}/pagure-ev +install -p -m 755 pagure-ev/pagure_stream_server.py \ + $RPM_BUILD_ROOT/%{_libexecdir}/pagure-ev/pagure_stream_server.py +install -p -m 644 pagure-ev/pagure_ev.service \ + $RPM_BUILD_ROOT/%{_unitdir}/pagure_ev.service + +# Switch all systemd units to use the correct libexecdir +sed -e "s|/usr/libexec|%{_libexecdir}|g" -i $RPM_BUILD_ROOT/%{_unitdir}/*.service + +# Change default_config.py to use the correct libexecdir +sed -e "s|/usr/libexec|%{_libexecdir}|g" -i $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/default_config.py + +# Fix the shebang for various scripts +sed -e "s|#!/usr/bin/env python|#!%{__python3}|" -i \ + $RPM_BUILD_ROOT/%{_libexecdir}/pagure-ev/pagure_stream_server.py \ + $RPM_BUILD_ROOT/%{_libexecdir}/pagure/aclchecker.py \ + $RPM_BUILD_ROOT/%{_libexecdir}/pagure/keyhelper.py \ + $RPM_BUILD_ROOT/%{_datadir}/pagure/comment_email_milter.py \ + $RPM_BUILD_ROOT/%{_datadir}/pagure/pagure_createdb.py \ + $RPM_BUILD_ROOT/%{_datadir}/pagure/api_key_expire_mail.py \ + $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/hooks/files/*.py \ + $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/hooks/files/hookrunner \ + $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/hooks/files/post-receive \ + $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/hooks/files/pre-receive \ + $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/hooks/files/repospannerhook + +# Switch interpreter for systemd units to correct Python interpreter +sed -e "s|/usr/bin/python|%{__python3}|g" -i $RPM_BUILD_ROOT/%{_unitdir}/*.service + +# Change to correct static file path for apache httpd +sed -e "s/pythonX.Y/python%{python3_version}/g" -i $RPM_BUILD_ROOT/%{_sysconfdir}/apache2/vhosts.d/pagure.conf + +# Make symlinks for default theme packages +mv $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/themes/default $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/themes/upstream +ln -sr $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/themes/upstream $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/themes/default +ln -sr $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/themes/chameleon $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/themes/default.openSUSE + +# Run fdupes +%fdupes $RPM_BUILD_ROOT/%{python3_sitelib} +%fdupes doc/ + +# Regenerate clobbered symlinks (Cf. https://pagure.io/pagure/issue/3782) +runnerhooks="post-receive pre-receive" + +for runnerhook in $runnerhooks; do + rm -rf $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/hooks/files/$runnerhook + ln -sf hookrunner $RPM_BUILD_ROOT/%{python3_sitelib}/pagure/hooks/files/$runnerhook +done + +# Make the rcFOO symlinks for systemd services +mkdir -p $RPM_BUILD_ROOT/%{_sbindir} +paguresvcs="api_key_expire_mail ci ev gitolite_worker loadjson logcom milter mirror webhook worker" +for paguresvc in $paguresvcs; do + ln -sf %{_sbindir}/service $RPM_BUILD_ROOT/%{_sbindir}/rcpagure_$paguresvc +done + +# Install the basic directory structure +mkdir -p $RPM_BUILD_ROOT/srv/www/pagure-releases +mkdir -p $RPM_BUILD_ROOT/srv/gitolite/pseudo +mkdir -p $RPM_BUILD_ROOT/srv/gitolite/repositories/{,docs,forks,requests,tickets} +mkdir -p $RPM_BUILD_ROOT/srv/gitolite/remotes +mkdir -p $RPM_BUILD_ROOT/srv/gitolite/.gitolite/{conf,keydir,logs} + +# Add empty gitolite config file +touch $RPM_BUILD_ROOT/srv/gitolite/.gitolite/conf/gitolite.conf + +# Install gitolite rc file +install -p -m 644 files/gitolite3.rc $RPM_BUILD_ROOT/srv/gitolite/.gitolite.rc + +%pre +# Do nothing, but ensure dependency is evaluated... + +%post +echo "Create wsgi rundir if it doesn't exist..." +mkdir -p /srv/www/run || : + +echo "Setting up facls..." +setfacl -m user:wwwrun:rx --default /srv/gitolite || : +setfacl -Rdm user:wwwrun:rx /srv/gitolite || : +setfacl -Rm user:wwwrun:rx /srv/gitolite || : + +echo "See %{_docdir}/%{name}/README.SUSE to continue" +%systemd_post pagure_worker.service +%systemd_post pagure_gitolite_worker.service +%systemd_post pagure_api_key_expire_mail.timer +%post milters +%tmpfiles_create %{_tmpfilesdir}/%{name}-milter.conf +%systemd_post pagure_milter.service +%post ev +%systemd_post pagure_ev.service +%post webhook +%systemd_post pagure_webhook.service +%post ci +%systemd_post pagure_ci.service +%post logcom +%systemd_post pagure_logcom.service +%post loadjson +%systemd_post pagure_loadjson.service +%post mirror +%systemd_post pagure_mirror.service + +%preun +%systemd_preun pagure_worker.service +%systemd_preun pagure_api_key_expire_mail.timer +%preun milters +%systemd_preun pagure_milter.service +%preun ev +%systemd_preun pagure_ev.service +%preun webhook +%systemd_preun pagure_webhook.service +%preun ci +%systemd_preun pagure_ci.service +%preun logcom +%systemd_preun pagure_logcom.service +%preun loadjson +%systemd_preun pagure_loadjson.service +%preun mirror +%systemd_preun pagure_mirror.service + +%postun +%systemd_postun_with_restart pagure_worker.service +%systemd_postun_with_restart pagure_gitolite_worker.service +%systemd_postun pagure_api_key_expire_mail.timer +%postun milters +%systemd_postun_with_restart pagure_milter.service +%postun ev +%systemd_postun_with_restart pagure_ev.service +%postun webhook +%systemd_postun_with_restart pagure_webhook.service +%postun ci +%systemd_postun_with_restart pagure_ci.service +%postun logcom +%systemd_postun_with_restart pagure_logcom.service +%postun loadjson +%systemd_postun_with_restart pagure_loadjson.service +%postun mirror +%systemd_postun_with_restart pagure_mirror.service + + +%files +%doc README.SUSE README.rst UPGRADING.rst doc/ files/gitolite3.rc files/pagure.conf files/pagure.cfg.sample +%license LICENSE +%config(noreplace) %{_sysconfdir}/apache2/vhosts.d/pagure.conf +%config(noreplace) %{_sysconfdir}/pagure/pagure.cfg +%config(noreplace) %{_sysconfdir}/pagure/alembic.ini +%dir %{_sysconfdir}/pagure/ +%dir %{_datadir}/pagure/ +%config(noreplace) %{_datadir}/pagure/*.wsgi +%{_datadir}/pagure/*.py* +%exclude %{_datadir}/pagure/comment_email_milter.py* +%{_datadir}/pagure/alembic/ +%{_libexecdir}/pagure/ +%{python3_sitelib}/pagure/ +%exclude %{python3_sitelib}/pagure/themes/default +%exclude %{python3_sitelib}/pagure/themes/default.openSUSE +%exclude %{python3_sitelib}/pagure/themes/upstream +%exclude %{python3_sitelib}/pagure/themes/pagureio +%exclude %{python3_sitelib}/pagure/themes/srcfpo +%exclude %{python3_sitelib}/pagure/themes/chameleon +%{python3_sitelib}/pagure*.egg-info +%{_bindir}/pagure-admin +%{_unitdir}/pagure_worker.service +%{_unitdir}/pagure_gitolite_worker.service +%{_unitdir}/pagure_api_key_expire_mail.service +%{_unitdir}/pagure_api_key_expire_mail.timer +%{_sbindir}/rcpagure_api_key_expire_mail +%{_sbindir}/rcpagure_worker +%{_sbindir}/rcpagure_gitolite_worker +# Pagure data content +%attr(-,git,git) %dir /srv/gitolite/pseudo +%attr(-,git,git) %dir /srv/gitolite/remotes +%attr(-,git,git) %dir /srv/gitolite/repositories/{,docs,forks,requests,tickets} +%attr(-,git,git) %dir /srv/gitolite/.gitolite/{,conf,keydir,logs} +%attr(-,git,git) %config(noreplace) /srv/gitolite/.gitolite/conf/gitolite.conf +%attr(-,git,git) %config(noreplace) /srv/gitolite/.gitolite.rc +%attr(-,git,git) %dir /srv/www/pagure-releases + + +%files theme-upstream +%license LICENSE +%{python3_sitelib}/pagure/themes/upstream/ + + +%files theme-pagureio +%license LICENSE +%{python3_sitelib}/pagure/themes/pagureio/ + + +%files theme-srcfpo +%license LICENSE +%{python3_sitelib}/pagure/themes/srcfpo/ + + +%files theme-chameleon +%license LICENSE +%{python3_sitelib}/pagure/themes/chameleon/ + + +%files theme-default-upstream +%license LICENSE +%{python3_sitelib}/pagure/themes/default + + +%files theme-default-openSUSE +%license LICENSE +%{python3_sitelib}/pagure/themes/default.openSUSE + + +%files milters +%license LICENSE +%dir %{_datadir}/pagure/ +%{_tmpfilesdir}/%{name}-milter.conf +%{_unitdir}/pagure_milter.service +%{_datadir}/pagure/comment_email_milter.py* +%{_sbindir}/rcpagure_milter + + +%files ev +%license LICENSE +%{_libexecdir}/pagure-ev/ +%{_unitdir}/pagure_ev.service +%{_sbindir}/rcpagure_ev + + +%files webhook +%license LICENSE +%{_unitdir}/pagure_webhook.service +%{_sbindir}/rcpagure_webhook + + +%files ci +%license LICENSE +%{_unitdir}/pagure_ci.service +%{_sbindir}/rcpagure_ci + + +%files logcom +%license LICENSE +%{_unitdir}/pagure_logcom.service +%{_sbindir}/rcpagure_logcom + + +%files loadjson +%license LICENSE +%{_unitdir}/pagure_loadjson.service +%{_sbindir}/rcpagure_loadjson + + +%files mirror +%license LICENSE +%{_unitdir}/pagure_mirror.service +%{_sbindir}/rcpagure_mirror + + +%changelog +