diff --git a/obal/data/module_utils/copr_wrapper.py b/obal/data/module_utils/copr_wrapper.py new file mode 100644 index 00000000..6a9038b4 --- /dev/null +++ b/obal/data/module_utils/copr_wrapper.py @@ -0,0 +1,23 @@ +""" +A copr-cli wrapper +""" +from subprocess import check_output, CalledProcessError + +class CoprCliCommandError(Exception): + """Raised when copr-cli command fails""" + def __init__(self, message, command): + self.message = message + self.command = command + super(CoprCliCommandError, self).__init__(message) #pylint: disable-all + +def copr_cli(command, executable=None): + """ + Run a copr-cli command + """ + if executable is None: + executable = 'copr-cli' + + try: + return check_output([executable] + command, universal_newlines=True) + except CalledProcessError as error: + raise CoprCliCommandError(error.output, error.cmd) diff --git a/obal/data/modules/copr_build.py b/obal/data/modules/copr_build.py new file mode 100644 index 00000000..e42e6bfd --- /dev/null +++ b/obal/data/modules/copr_build.py @@ -0,0 +1,44 @@ +""" +Release a package to Copr +""" + +import re + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.copr_wrapper import copr_cli, CoprCliCommandError # pylint:disable=import-error,no-name-in-module + + +def main(): + """ + Build a package in koji + """ + module = AnsibleModule( + argument_spec=dict( + srpm=dict(type='path', required=True), + repo_name=dict(type='str', required=True), + wait=dict(type='bool', required=False, default=True) + ) + ) + + srpm = module.params['srpm'] + repo_name = module.params['repo_name'] + wait = module.params['wait'] + + command = ['build', repo_name, srpm] + + if not wait: + command.append('--nowait') + + try: + output = copr_cli(command) + except CoprCliCommandError as error: + module.fail_json(msg='Copr build failed', command=error.command, output=error.message, + repo_name=repo_name, srpm=srpm) + + builds = re.findall(r'^Build was added to.+:\n^\s(.+)', output, re.MULTILINE) + + module.exit_json(changed=True, output=output, builds=builds) + + +if __name__ == '__main__': + main() diff --git a/obal/data/modules/copr_chroot.py b/obal/data/modules/copr_chroot.py new file mode 100644 index 00000000..2a7980fc --- /dev/null +++ b/obal/data/modules/copr_chroot.py @@ -0,0 +1,52 @@ +""" +Manage a chroot in a Copr repository +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.copr_wrapper import copr_cli, CoprCliCommandError # pylint:disable=import-error,no-name-in-module + + +def main(): + """ + Manage a chroot in a Copr repository + """ + module = AnsibleModule( + argument_spec=dict( + repo_name=dict(type='str', required=True), + chroot=dict(type='str', required=True), + external_repos=dict(type='list', required=False, default=[]), + buildroot_packages=dict(type='list', required=False, default=[]), + modules=dict(type='list', required=False, default=[]), + ) + ) + + repo_name = module.params['repo_name'] + chroot = module.params['chroot'] + external_repos = module.params['external_repos'] + buildroot_packages = module.params['buildroot_packages'] + modules = module.params['modules'] + + command = [ + 'edit-chroot', + "%s/%s" % (repo_name, chroot) + ] + + if external_repos: + command.extend(['--repos', ' '.join(external_repos)]) + + if buildroot_packages: + command.extend(['--packages', ' '.join(buildroot_packages)]) + + if modules: + command.extend(['--modules', ','.join(modules)]) + + try: + output = copr_cli(command) + except CoprCliCommandError as error: + module.fail_json(msg='Copr chroot edit failed', command=' '.join(error.command), output=error.message) + + module.exit_json(changed=True, output=output) + + +if __name__ == '__main__': + main() diff --git a/obal/data/modules/copr_repo.py b/obal/data/modules/copr_repo.py new file mode 100644 index 00000000..b3977b9e --- /dev/null +++ b/obal/data/modules/copr_repo.py @@ -0,0 +1,57 @@ +""" +Create a repository in Copr +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.copr_wrapper import copr_cli, CoprCliCommandError # pylint:disable=import-error,no-name-in-module + + +def main(): + """ + Create a repository in Copr + """ + module = AnsibleModule( + argument_spec=dict( + repo_name=dict(type='str', required=True), + chroots=dict(type='list', required=True), + description=dict(type='str', required=False), + unlisted_on_homepage=dict(type='bool', required=False, default=True), + delete_after_days=dict(type='str', required=False, default=None), + ) + ) + + repo_name = module.params['repo_name'] + chroots = module.params['chroots'] + description = module.params['description'] + unlisted_on_homepage = module.params['unlisted_on_homepage'] + delete_after_days = module.params['delete_after_days'] + + if not description: + description = repo_name + + command = [ + 'create', + repo_name, + '--description', + "%s" % description + ] + + for chroot in chroots: + command.extend(['--chroot', chroot]) + + if unlisted_on_homepage: + command.extend(['--unlisted-on-hp', 'on']) + + if delete_after_days: + command.extend(['--delete-after-days', delete_after_days]) + + try: + output = copr_cli(command) + except CoprCliCommandError as error: + module.fail_json(msg='Copr repository creation failed', command=' '.join(error.command), output=error.message) + + module.exit_json(changed=True, output=output) + + +if __name__ == '__main__': + main() diff --git a/obal/data/roles/build_package/tasks/copr.yml b/obal/data/roles/build_package/tasks/copr.yml index 41487cc1..a054e011 100644 --- a/obal/data/roles/build_package/tasks/copr.yml +++ b/obal/data/roles/build_package/tasks/copr.yml @@ -1,20 +1,4 @@ --- -- when: not build_package_scratch - block: - - name: 'Release to copr' - tito_release: - directory: "{{ inventory_dir }}/{{ package_base_dir }}/{{ inventory_hostname }}" - arguments: "{{ build_package_tito_args }}" - test: "{{ build_package_test }}" - scratch: "{{ build_package_scratch }}" - releasers: "{{ releasers }}" - releaser_arguments: "{{ build_package_tito_releaser_args }}" - register: build_package_tito_release - - - name: 'Wait for tasks to finish' - include_tasks: wait.yml - when: build_package_wait|bool - - when: build_package_scratch block: - name: Define copr repo name @@ -33,21 +17,30 @@ - include_role: name: copr_repo run_once: true + vars: + copr_repo_delete_after_days: 2 + +- name: Create temporary build directory + tempfile: + state: directory + suffix: srpms + register: srpm_directory + when: srpm_directory is not defined - - name: 'Build SRPM' - tito_build: - directory: "{{ inventory_dir }}/{{ package_base_dir }}/{{ inventory_hostname }}" - srpm: true - scl: "{{ scl }}" - register: srpm_build +- name: 'Build SRPM' + srpm: + package: "{{ inventory_dir }}/{{ package_base_dir }}/{{ inventory_hostname }}" + output: "{{ srpm_directory.path if 'path' in srpm_directory else srpm_directory }}" + source_location: "{{ source_location | default(omit) }}" + source_system: "{{ source_system | default(omit) }}" + register: srpm_build - - name: 'Run build' - command: >- - copr-cli build - {% if not build_package_wait | bool %}--nowait{% endif %} - {{ copr_repo_name }} - {{ srpm_build.path }} - register: build_status +- name: 'Run build' + copr_build: + repo_name: "{{ copr_repo_name }}" + srpm: "{{ srpm_build.path }}" + wait: "{{ build_package_wait }}" + register: copr_builds - - debug: - msg: "{{ build_status.stdout_lines | join('\n') }}" +- debug: + msg: "{{ copr_builds.output }}" diff --git a/obal/data/roles/copr_repo/tasks/main.yml b/obal/data/roles/copr_repo/tasks/main.yml index d52bab75..8b129f55 100644 --- a/obal/data/roles/copr_repo/tasks/main.yml +++ b/obal/data/roles/copr_repo/tasks/main.yml @@ -1,19 +1,20 @@ --- -- name: 'Create copr scratch build repo' - command: > - copr-cli - create - {{ copr_repo_name }} - --chroot {{ copr_repo_chroot }} - --description '{{ copr_repo_description }}' - --unlisted-on-hp on - --repo '{{ copr_repo_external_repos | join(' ') }}' - changed_when: false +- name: 'Create Copr repo' + copr_repo: + repo_name: "{{ copr_repo_name }}" + chroots: "{{ copr_repo_chroots | map(attribute='name') }}" + description: "{{ copr_repo_description | default(omit) }}" + delete_after_days: "{{ copr_repo_delete_after_days | default(omit) }}" + unlisted_on_homepage: "{{ copr_repo_unlisted_on_homepage | default(omit) }}" + register: create_output -- name: 'Add build packages to chroot' - command: > - copr-cli - edit-chroot - {{ copr_repo_name }}/{{ copr_repo_chroot }} - --packages '{{ copr_repo_packages | join(' ') }}' - changed_when: false +- name: Configure chroots + copr_chroot: + repo_name: "{{ copr_repo_name }}" + chroot: "{{ chroot.name }}" + external_repos: "{{ chroot.external_repos | default(omit) }}" + buildroot_packages: "{{ chroot.buildroot_packages | default(omit) }}" + modules: "{{ chroot.modules | default(omit) }}" + loop: "{{ copr_repo_chroots }}" + loop_control: + loop_var: chroot diff --git a/tests/fixtures/testrepo/copr/package_manifest.yaml b/tests/fixtures/testrepo/copr/package_manifest.yaml index d75072d9..1b17f101 100644 --- a/tests/fixtures/testrepo/copr/package_manifest.yaml +++ b/tests/fixtures/testrepo/copr/package_manifest.yaml @@ -6,16 +6,17 @@ packages: scl: copr-scl copr_user: "@fake-user" copr_repo_name: copr-repo-scratch + copr_repo_chroots: + - name: epel-7-x86_64 + external_repos: + - http://mirror.centos.org/centos/7/sclo/x86_64/rh/ + buildroot_packages: + - scl-utils-build + - rh-ruby24-build diff_package_copr_repo: copr-repo-staging diff_package_type: copr build_package_build_system: copr build_package_scratch_repo: copr-repo-scratch - copr_repo_chroot: epel-7-x86_64 - copr_repo_external_repos: - - http://mirror.centos.org/centos/7/sclo/x86_64/rh/ - copr_repo_packages: - - scl-utils-build - - rh-ruby24-build hosts: hello: {} diff --git a/tests/test_functional.py b/tests/test_functional.py index 554604c5..00dea9ba 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -662,10 +662,9 @@ def test_obal_scratch_copr_hello_nowait(): assert os.path.exists('packages/hello/hello-2.10.tar.gz') expected_log = [ - "copr-cli create copr-repo-scratch --chroot epel-7-x86_64 --description 'Scratch Builds' --unlisted-on-hp on --repo http://mirror.centos.org/centos/7/sclo/x86_64/rh/", # noqa: E501 - "copr-cli edit-chroot copr-repo-scratch/epel-7-x86_64 --packages 'scl-utils-build rh-ruby24-build'", # noqa: E501 - "tito build --srpm --scl copr-scl", - "copr-cli build --nowait copr-repo-scratch hello-2.10-1.src.rpm" + "copr-cli create copr-repo-scratch --description 'Scratch Builds' --chroot epel-7-x86_64 --unlisted-on-hp on --delete-after-days 2", # noqa: E501 + "copr-cli edit-chroot copr-repo-scratch/epel-7-x86_64 --repos http://mirror.centos.org/centos/7/sclo/x86_64/rh/ --packages 'scl-utils-build rh-ruby24-build'", # noqa: E501 + "copr-cli build copr-repo-scratch /tmp/SRPMs/hello-2.10-1.src.rpm --nowait" ] assert_mockbin_log(expected_log) @@ -677,10 +676,9 @@ def test_obal_scratch_copr_hello(): assert os.path.exists('packages/hello/hello-2.10.tar.gz') expected_log = [ - "copr-cli create copr-repo-scratch --chroot epel-7-x86_64 --description 'Scratch Builds' --unlisted-on-hp on --repo http://mirror.centos.org/centos/7/sclo/x86_64/rh/", # noqa: E501 - "copr-cli edit-chroot copr-repo-scratch/epel-7-x86_64 --packages 'scl-utils-build rh-ruby24-build'", # noqa: E501 - "tito build --srpm --scl copr-scl", - "copr-cli build copr-repo-scratch hello-2.10-1.src.rpm", + "copr-cli create copr-repo-scratch --description 'Scratch Builds' --chroot epel-7-x86_64 --unlisted-on-hp on --delete-after-days 2", # noqa: E501 + "copr-cli edit-chroot copr-repo-scratch/epel-7-x86_64 --repos http://mirror.centos.org/centos/7/sclo/x86_64/rh/ --packages 'scl-utils-build rh-ruby24-build'", # noqa: E501 + "copr-cli build copr-repo-scratch /tmp/SRPMs/hello-2.10-1.src.rpm", # copr-cli build waits by default, so there is no "watch-build" step here ] assert_mockbin_log(expected_log) @@ -694,7 +692,7 @@ def test_obal_release_copr_hello_nowait(): expected_log = [ "copr-cli get-package @fake-user/copr-repo-staging --name hello --with-latest-build", - "tito release --yes copr", + "copr-cli build copr-repo-scratch /tmp/SRPMs/hello-2.10-1.src.rpm --nowait" ] assert_mockbin_log(expected_log) @@ -707,8 +705,7 @@ def test_obal_release_copr_hello(): expected_log = [ "copr-cli get-package @fake-user/copr-repo-staging --name hello --with-latest-build", - "tito release --yes copr", - "copr-cli watch-build" + "copr-cli build copr-repo-scratch /tmp/SRPMs/hello-2.10-1.src.rpm" ] assert_mockbin_log(expected_log)