diff --git a/container_workflow_tool/constants.py b/container_workflow_tool/constants.py index f2aa518..c1d7945 100644 --- a/container_workflow_tool/constants.py +++ b/container_workflow_tool/constants.py @@ -1,6 +1,6 @@ action_map = {} action_map['git'] = { - 'pullupstream': 'dist_git_changes', + 'pullupstream': 'dist_git_merge_changes', 'clonedownstream': 'pull_downstream', 'cloneupstream': 'pull_upstream', 'rebase': 'dist_git_rebase', diff --git a/container_workflow_tool/distgit.py b/container_workflow_tool/distgit.py index 946e032..66afbe5 100644 --- a/container_workflow_tool/distgit.py +++ b/container_workflow_tool/distgit.py @@ -5,7 +5,7 @@ from git import Repo from git.exc import GitCommandError -import container_workflow_tool.utility as u +from container_workflow_tool import utility from container_workflow_tool.utility import RebuilderError from container_workflow_tool.dockerfile import DockerfileHandler from container_workflow_tool.sync import SyncHandler @@ -49,21 +49,22 @@ def check_script(self, component, script_path, component_path): self.logger.info(template.format(name=component, status="Affected")) err = ret.stderr.decode('utf-8').strip() if err: - self.logger.error(u._2sp(err)) + self.logger.error(utility._2sp(err)) else: self.logger.info(template.format(name=component, status="OK")) - def dist_git_changes(self, images, rebase=False): + def dist_git_merge_changes(self, images, rebase=False): """Method to merge changes from upstream into downstream Pulls both downstream and upstream repositories into a temporary dir. Merge is done by copying tracked files from upstream into downstream. Args: + images (list): List of images to sync rebase (bool, optional): Specify if a rebase should be done instead """ try: - for image in (images): + for image in images: name = image["name"] component = image["component"] branch = image["git_branch"] @@ -92,18 +93,17 @@ def dist_git_changes(self, images, rebase=False): ups_name = name.split('-')[0] # Clone upstream repository ups_path = os.path.join('upstreams/', ups_name) - self._clone_upstream(url, ups_path, commands=commands) + self.clone_upstream(url, ups_path, commands=commands) # Save the upstream commit hash ups_hash = Repo(ups_path).commit().hexsha - self._pull_upstream(component, path, url, repo, ups_name, commands) + self.pull_upstream(component, path, url, repo, ups_name, commands) self.df_handler.update_dockerfile( df_path, from_tag, downstream_from=downstream_from ) repo.git.add("Dockerfile") # It is possible for the git repository to have no changes if repo.is_dirty(): - commit = self.get_commit_msg(rebase, image, ups_hash - ) + commit = self.get_commit_msg(rebase, image, ups_hash) if commit: repo.git.commit("-m", commit) else: @@ -122,8 +122,8 @@ def _clone_downstream(self, component, branch): self.logger.info("Using existing downstream repo: " + component) repo = Repo(component) else: - hostname_url = u._get_hostname_url(self.conf) - packager = u._get_packager(self.conf) + hostname_url = utility._get_hostname_url(self.conf) + packager = utility._get_packager(self.conf) # if packager is fedpkg then namespace is `container` else `containers` namespace = "container" if packager == "fedpkg" else "containers" component_path = f"{namespace}/{component}" @@ -162,7 +162,7 @@ def push_changes(self, tmp, images): # commit_msg is set so it is always returned commit = self.get_commit_msg(None, image) repo.git.commit("-am", commit) - if self._get_unpushed_commits(repo): + if self.are_unpushed_commits_available(repo): self.logger.info("Pushing: " + component) repo.git.push() @@ -176,7 +176,7 @@ def push_changes(self, tmp, images): if failed: self.logger.error("Failed pushing images:") for image in failed: - self.logger.error(u._2sp(image["component"])) + self.logger.error(utility._2sp(image["component"])) self.logger.error("Please check the failures and push the changes manually.") # TODO: Multiple future branches? @@ -204,5 +204,5 @@ def merge_future_branches(self, images): if failed: self.logger.error("Failed merging images:") for image in failed: - self.logger.error(u._2sp(image["component"])) + self.logger.error(utility._2sp(image["component"])) self.logger.error("Please check the failures and push the changes manually.") diff --git a/container_workflow_tool/git_operations.py b/container_workflow_tool/git_operations.py index 7ef94bf..a643c25 100644 --- a/container_workflow_tool/git_operations.py +++ b/container_workflow_tool/git_operations.py @@ -1,6 +1,6 @@ # MIT License # -# Copyright (c) 2020 SCL team at Red Hat +# Copyright (c) 2023 SCL team at Red Hat # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -55,7 +55,7 @@ def set_commit_msg(self, msg): """ self.commit_msg = msg - def _do_git_reset(self, repo): + def do_git_reset(self, repo): file_list = ['--', '.gitignore'] + self.conf.ignore_files repo.git.reset(file_list) # One file at a time to make sure all files get reset even on error @@ -68,7 +68,7 @@ def _do_git_reset(self, repo): repo.git.clean('-xfd', f) self.logger.debug("Removing untracked ignored file: " + f) - def _clone_upstream(self, url, ups_path, commands=None): + def clone_upstream(self, url, ups_path, commands=None): """ :params: url is URL to repofile from upstream. https://github.com/sclorg :param: ups_path is path where URL is cloned locally @@ -113,20 +113,23 @@ def _clone_upstream(self, url, ups_path, commands=None): os.chdir(oldcwd) return repo - def are_unpushed_commits_available(self, repo) -> bool: + def are_unpushed_commits_available(self, repo, branch_name="") -> bool: """ Get unpushed commits :param repo: repo object to check for unpushed commits + :param branch_name: In case of gitlab, branch_name has to be defined. + :param branch_name: In case of gitlab, branch_name has to be defined. + branch_name is e.g. rhel-8.7.0 and 'repo.active_branch.name' is 'rhel-8.7.0-' :return: List of commits or empty array """ branch = repo.active_branch.name # Get a list of commits that have not been pushed to remote select = "origin/" + branch + ".." + branch - if len(list(repo.iter_commits(select))) == 0: - return False - return True + if branch_name != "": + select = "origin/" + branch_name + ".." + branch + return bool(list(repo.iter_commits(select))) - def show_git_changes(self, tmp, components=None, diff=False): + def show_git_changes(self, tmp, components=None, diff=False, branch_name=""): """Shows changes made to tracked files in local downstream repositories Walks through all repositories and calls 'git-show' or 'git-diff' on each of them. @@ -135,6 +138,8 @@ def show_git_changes(self, tmp, components=None, diff=False): tmp (str): Path to the directory that is used to store git repositories components (list of str, optional): List of components to show changes for diff (boolean, optional): Controls whether the method calls git-show or git-diff + branch_name (str, optional): In case of gitlab, branch_name has to be defined. + branch_name is e.g. rhel-8.7.0 and 'repo.active_branch.name' is 'rhel-8.7.0-' """ # Function to check if a path contains a git repository def is_git(x): return os.path.isdir(os.path.join(x, '.git')) @@ -155,7 +160,7 @@ def is_git(x): return os.path.isdir(os.path.join(x, '.git')) repo = Repo(path) # Only show changes if there are unpushed commits to show # or we only want the diff of unstaged changes - if self.are_unpushed_commits_available(repo) or diff: + if self.are_unpushed_commits_available(repo, branch_name=branch_name) or diff: # Clears the screen print(chr(27) + "[2J") # Force pager for short git diffs @@ -229,7 +234,7 @@ def get_commit_msg(self, rebase, image=None, ups_hash=None): commit += "\n created from upstream commit: " + ups_hash return commit - def _pull_upstream(self, component, path, url, repo, ups_name, commands): + def pull_upstream(self, component, path, url, repo, ups_name, commands): """Pulls an upstream repo and copies it into downstream""" ups_path = os.path.join('upstreams/', ups_name) cp_path = os.path.join(ups_path, path) @@ -268,7 +273,7 @@ def _pull_upstream(self, component, path, url, repo, ups_name, commands): self.update_test_openshift_yaml(test_openshift_yaml_file, path, short_name=ups_name) repo.git.add("*") - self._do_git_reset(repo) + self.do_git_reset(repo) # TODO: Configurable? df_ext = self.df_ext df_path = os.path.join(component, "Dockerfile") diff --git a/container_workflow_tool/main.py b/container_workflow_tool/main.py index 07b4564..d691929 100755 --- a/container_workflow_tool/main.py +++ b/container_workflow_tool/main.py @@ -9,7 +9,6 @@ import re import tempfile import pprint -import getpass import logging from git import Repo, GitError @@ -53,6 +52,7 @@ def __init__(self, self.conf_name = config self.rebuild_reason = rebuild_reason + self.gitlab_usage = None self.do_image = None self.exclude_image = None self.do_set = None @@ -119,10 +119,8 @@ def _setup_args(self, args): self.rebuild_reason = args.rebuild_reason if getattr(args, 'check_script', None) is not None and args.check_script: self.check_script = args.check_script - if getattr(args, 'disable_klist', None) is not None and args.disable_klist: - self.disable_klist = args.disable_klist - if getattr(args, 'latest_release', None) is not None and args.latest_release: - self.latest_release = args.latest_release + self.disable_klist = args.disable_klist + self.latest_release = args.latest_release if getattr(args, 'output_file', None) is not None and args.output_file: self.output_file = args.output_file @@ -150,7 +148,7 @@ def git_ops(self): if not self._git_ops: self._git_ops = GitOperations(self.base_image, self.conf, self.rebuild_reason, - self.logger.getChild("-git-ops")) + self.logger.getChild("git-ops")) return self._git_ops @property @@ -449,16 +447,16 @@ def set_repo_url(self, repo_url): def list_images(self): """Prints list of images that we work with""" - for i in self._get_images(): - self.logger.info(i["component"]) + for image in self._get_images(): + self.logger.info(image["component"]) def print_upstream(self): """Prints the upstream name and url for images used in config""" - for i in self._get_images(): + for image in self._get_images(): ups_name = re.search(r".*\/([a-zA-Z0-9-]+).git", - i["git_url"]).group(1) - msg = f"{i.get('component')} {i.get('name')} {ups_name} " \ - f"{i.get('git_url')} {i.get('git_path')} {i.get('git_branch')}" + image["git_url"]).group(1) + msg = f"{image.get('component')} {image.get('name')} {ups_name} " \ + f"{image.get('git_url')} {image.get('git_path')} {image.get('git_branch')}" self.logger.info(msg) def show_config_contents(self): @@ -502,17 +500,14 @@ def pull_downstream(self): Additionally runs a script against each repository if check_script is set, checking its exit value. """ - self._check_kerb_ticket() - tmp = self._get_tmp_workdir() - self._change_workdir(tmp) - images = self._get_images() - for i in images: - self.distgit._clone_downstream(i["component"], i["git_branch"]) + tmp, images = self.preparation() + for image in images: + self.distgit._clone_downstream(image["component"], image["git_branch"]) # If check script is set, run the script provided for each config entry if self.check_script: - for i in images: - self.distgit.check_script(i["component"], self.check_script, - i["git_branch"]) + for image in images: + self.distgit.check_script(image["component"], self.check_script, + image["git_branch"]) def pull_upstream(self): """ @@ -521,24 +516,19 @@ def pull_upstream(self): Additionally runs a script against each repository if check_script is set, checking its exit value. """ - tmp = self._get_tmp_workdir() - self._change_workdir(tmp) - images = self._get_images() - for i in images: + tmp, images = self.preparation() + for image in images: # Use unversioned name as a path for the repository - ups_name = i["name"].split('-')[0] - self.distgit._clone_upstream(i["git_url"], - ups_name, - commands=i["commands"]) + ups_name = image["name"].split('-')[0] + self.git_ops.clone_upstream(image["git_url"], ups_name, commands=image["commands"]) # If check script is set, run the script provided for each config entry if self.check_script: - for i in images: - ups_name = i["name"].split('-')[0] - self.distgit.check_script(i["component"], self.check_script, - os.path.join(ups_name, i["git_path"])) + for image in images: + ups_name = image["name"].split('-')[0] + self.distgit.check_script(image["component"], self.check_script, + os.path.join(ups_name, image["git_path"])) - def push_changes(self): - """Pushes changes for all components into downstream dist-git repository""" + def preparation(self): # Check for kerberos ticket self._check_kerb_ticket() tmp = self._get_tmp_workdir(setup_dir=False) @@ -547,7 +537,12 @@ def push_changes(self): raise RebuilderError(msg) self._change_workdir(tmp) images = self._get_images() + return tmp, images + + def push_changes(self): + """Pushes changes for all components into downstream dist-git repository""" + tmp, images = self.preparation() self.distgit.push_changes(tmp, images) def dist_git_rebase(self): @@ -555,23 +550,9 @@ def dist_git_rebase(self): Do a rebase against a new base/s2i image. Does not pull in upstream changes of layered images. """ - self.dist_git_changes(rebase=True) - - def dist_git_changes(self, rebase: bool = False): - """Method to merge changes from upstream into downstream + self.dist_git_merge_changes(rebase=True) - Pulls both downstream and upstream repositories into a temporary directory. - Merge is done by copying tracked files from upstream into downstream. - - Args: - rebase (bool, optional): Specifies whether a rebase should be done instead. - """ - # Check for kerberos ticket - self._check_kerb_ticket() - tmp = self._get_tmp_workdir() - self._change_workdir(tmp) - images = self._get_images() - self.distgit.dist_git_changes(images, rebase) + def git_changes_report(self, tmp): self.logger.info("\nGit location: " + tmp) if self.args: tmp_str = ' --tmp ' + self.tmp_workdir if self.tmp_workdir else '"' @@ -583,13 +564,23 @@ def dist_git_changes(self, rebase: bool = False): "cwt git push && cwt build" "[base/core/s2i] --repo-url link-to-repo-file") + def dist_git_merge_changes(self, rebase: bool = False): + """Method to merge changes from upstream into downstream + + Pulls both downstream and upstream repositories into a temporary directory. + Merge is done by copying tracked files from upstream into downstream. + + Args: + rebase (bool, optional): Specifies whether a rebase should be done instead. + """ + tmp, images = self.preparation() + self.distgit.dist_git_merge_changes(images, rebase) + self.git_changes_report(tmp=tmp) + def merge_future_branches(self): """Merges current branch with future branches""" # Check for kerberos ticket - self._check_kerb_ticket() - tmp = self._get_tmp_workdir() - self._change_workdir(tmp) - images = self._get_images() + tmp, images = self.preparation() self.distgit.merge_future_branches(images) def show_git_changes(self, components: List = None): @@ -599,9 +590,8 @@ def show_git_changes(self, components: List = None): components (list of str, optional): List of components to show changes for Walks through all downstream repositories and calls 'git-show' on each of them. """ + tmp, _ = self.preparation() if not components: images = self._get_images() - components = [i["component"] for i in images] - tmp = self._get_tmp_workdir() - self._change_workdir(tmp) + components = [image["component"] for image in images] self.distgit.show_git_changes(tmp, components) diff --git a/container_workflow_tool/utility.py b/container_workflow_tool/utility.py index 1512f30..4cb3d35 100644 --- a/container_workflow_tool/utility.py +++ b/container_workflow_tool/utility.py @@ -2,8 +2,9 @@ import argparse import os import logging - +from pathlib import Path import textwrap +import contextlib class RebuilderError(Exception): @@ -73,6 +74,20 @@ def _split_config_path(config: str): return config_path, image_set +@contextlib.contextmanager +def cwd(path): + """ + Changes CWD to the temporary directory. + Yields the temporary directory. + """ + prev_cwd = Path.cwd() + os.chdir(path) + try: + yield + finally: + os.chdir(prev_cwd) + + def setup_logger(logger_id, level=logging.INFO): logger = logging.getLogger(logger_id) logger.setLevel(level) diff --git a/image-requirements/install-requirements.yaml b/image-requirements/install-requirements.yaml index 66b8a9a..bd2946c 100644 --- a/image-requirements/install-requirements.yaml +++ b/image-requirements/install-requirements.yaml @@ -13,4 +13,5 @@ - krb5-devel - krb5-workstation - golang-github-cpuguy83-md2man + - python3-gitlab become: true diff --git a/setup.py b/setup.py index 0bd5ee5..61a3ea2 100755 --- a/setup.py +++ b/setup.py @@ -58,7 +58,7 @@ def get_dir(system_path=None, virtual_path=None): setup( name='container-workflow-tool', - version="1.5.3", + version="1.5.4", description='A python3 tool to make rebuilding images easier by automating several steps of the process.', long_description=long_description, long_description_content_type='text/markdown', diff --git a/tests/data/nodejs-16/Dockerfile b/tests/data/nodejs-16/Dockerfile new file mode 100644 index 0000000..727fac2 --- /dev/null +++ b/tests/data/nodejs-16/Dockerfile @@ -0,0 +1,103 @@ +FROM rhscl/s2i-core-rhel7:1 + +# RHSCL rh-nginx116 image. +# +# Volumes: +# * /var/opt/rh/rh-nginx116/log/nginx/ - Storage for logs + +EXPOSE 8080 +EXPOSE 8443 + +ENV NAME=nginx \ + NGINX_VERSION=1.16 \ + NGINX_SHORT_VER=116 \ + PERL_SCL_SHORT_VER=526 \ + VERSION=0 + +# Set SCL related variables in Dockerfile so that the collection is enabled by default +ENV SUMMARY="Platform for running nginx $NGINX_VERSION or building nginx-based application" \ + DESCRIPTION="Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and IMAP \ +protocols, with a strong focus on high concurrency, performance and low memory usage. The container \ +image provides a containerized packaging of the nginx $NGINX_VERSION daemon. The image can be used \ +as a base image for other applications based on nginx $NGINX_VERSION web server. \ +Nginx server image can be extended using source-to-image tool." \ + X_SCLS="rh-perl$PERL_SCL_SHORT_VER rh-nginx$NGINX_SHORT_VER" \ + PATH=/opt/rh/rh-perl$PERL_SCL_SHORT_VER/root/usr/local/bin:/opt/rh/rh-perl$PERL_SCL_SHORT_VER/root/usr/bin:/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/bin:/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/sbin${PATH:+:${PATH}} \ + MANPATH=/opt/rh/rh-perl$PERL_SCL_SHORT_VER/root/usr/share/man:/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/share/man:${MANPATH} \ + PKG_CONFIG_PATH=/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/lib64/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} \ + LD_LIBRARY_PATH=/opt/rh/rh-perl$PERL_SCL_SHORT_VER/root/usr/lib64 \ + PERL5LIB="/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/lib64/perl5/vendor_perl${PERL5LIB:+:${PERL5LIB}}" + +LABEL summary="${SUMMARY}" \ + description="${DESCRIPTION}" \ + io.k8s.description="${DESCRIPTION}" \ + io.k8s.display-name="Nginx ${NGINX_VERSION}" \ + io.openshift.expose-services="8080:http" \ + io.openshift.expose-services="8443:https" \ + io.openshift.tags="builder,${NAME},rh-${NAME}${NGINX_SHORT_VER}" \ + com.redhat.component="rh-${NAME}${NGINX_SHORT_VER}-container" \ + name="rhscl/${NAME}-${NGINX_SHORT_VER}-rhel7" \ + version="1" \ + com.redhat.license_terms="https://www.redhat.com/en/about/red-hat-end-user-license-agreements#rhel" \ + maintainer="SoftwareCollections.org " \ + help="For more information visit https://github.com/sclorg/${NAME}-container" \ + usage="s2i build rhscl/${NAME}-${NGINX_SHORT_VER}-rhel7:latest " + +ENV NGINX_CONFIGURATION_PATH=${APP_ROOT}/etc/nginx.d \ + NGINX_CONF_PATH=/etc/opt/rh/rh-nginx${NGINX_SHORT_VER}/nginx/nginx.conf \ + NGINX_DEFAULT_CONF_PATH=${APP_ROOT}/etc/nginx.default.d \ + NGINX_CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/nginx \ + NGINX_APP_ROOT=${APP_ROOT} \ + NGINX_LOG_PATH=/var/opt/rh/rh-nginx${NGINX_SHORT_VER}/log/nginx \ + NGINX_PERL_MODULE_PATH=${APP_ROOT}/etc/perl + +RUN yum install -y yum-utils && \ + prepare-yum-repositories rhel-server-rhscl-7-rpms && \ + INSTALL_PKGS="nss_wrapper bind-utils gettext hostname rh-nginx${NGINX_SHORT_VER} rh-nginx${NGINX_SHORT_VER}-nginx \ + rh-nginx${NGINX_SHORT_VER}-nginx-mod-stream rh-nginx${NGINX_SHORT_VER}-nginx-mod-http-perl" && \ + yum install -y --setopt=tsflags=nodocs $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y clean all --enablerepo='*' + +# Copy the S2I scripts from the specific language image to $STI_SCRIPTS_PATH +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# Copy extra files to the image. +COPY ./root/ / + +# In order to drop the root user, we have to make some directories world +# writeable as OpenShift default security model is to run the container under +# random UID. +RUN sed -i -f ${NGINX_APP_ROOT}/nginxconf.sed ${NGINX_CONF_PATH} && \ + chmod a+rwx ${NGINX_CONF_PATH} && \ + mkdir -p ${NGINX_APP_ROOT}/etc/nginx.d/ && \ + mkdir -p ${NGINX_APP_ROOT}/etc/nginx.default.d/ && \ + mkdir -p ${NGINX_APP_ROOT}/src/nginx-start/ && \ + mkdir -p ${NGINX_CONTAINER_SCRIPTS_PATH}/nginx-start && \ + mkdir -p ${NGINX_LOG_PATH} && \ + mkdir -p ${NGINX_PERL_MODULE_PATH} && \ + ln -s ${NGINX_LOG_PATH} /var/log/nginx && \ + ln -s /etc/opt/rh/rh-nginx${NGINX_SHORT_VER}/nginx /etc/nginx && \ + ln -s /opt/rh/rh-nginx${NGINX_SHORT_VER}/root/usr/share/nginx /usr/share/nginx && \ + chmod -R a+rwx ${NGINX_APP_ROOT}/etc && \ + chmod -R a+rwx /var/opt/rh/rh-nginx${NGINX_SHORT_VER} && \ + chmod -R a+rwx ${NGINX_CONTAINER_SCRIPTS_PATH}/nginx-start && \ + chown -R 1001:0 ${NGINX_APP_ROOT} && \ + chown -R 1001:0 /var/opt/rh/rh-nginx${NGINX_SHORT_VER} && \ + chown -R 1001:0 ${NGINX_CONTAINER_SCRIPTS_PATH}/nginx-start && \ + chmod -R a+rwx /var/run && \ + chown -R 1001:0 /var/run && \ + rpm-file-permissions + +USER 1001 + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/opt/rh/rh-nginx116/root/usr/share/nginx/html"] +# VOLUME ["/var/opt/rh/rh-nginx116/log/nginx/"] + +ENV BASH_ENV=${NGINX_APP_ROOT}/etc/scl_enable \ + ENV=${NGINX_APP_ROOT}/etc/scl_enable \ + PROMPT_COMMAND=". ${NGINX_APP_ROOT}/etc/scl_enable" + +CMD $STI_SCRIPTS_PATH/usage diff --git a/tests/data/nodejs-16/Dockerfile.rhel7 b/tests/data/nodejs-16/Dockerfile.rhel7 new file mode 100644 index 0000000..727fac2 --- /dev/null +++ b/tests/data/nodejs-16/Dockerfile.rhel7 @@ -0,0 +1,103 @@ +FROM rhscl/s2i-core-rhel7:1 + +# RHSCL rh-nginx116 image. +# +# Volumes: +# * /var/opt/rh/rh-nginx116/log/nginx/ - Storage for logs + +EXPOSE 8080 +EXPOSE 8443 + +ENV NAME=nginx \ + NGINX_VERSION=1.16 \ + NGINX_SHORT_VER=116 \ + PERL_SCL_SHORT_VER=526 \ + VERSION=0 + +# Set SCL related variables in Dockerfile so that the collection is enabled by default +ENV SUMMARY="Platform for running nginx $NGINX_VERSION or building nginx-based application" \ + DESCRIPTION="Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and IMAP \ +protocols, with a strong focus on high concurrency, performance and low memory usage. The container \ +image provides a containerized packaging of the nginx $NGINX_VERSION daemon. The image can be used \ +as a base image for other applications based on nginx $NGINX_VERSION web server. \ +Nginx server image can be extended using source-to-image tool." \ + X_SCLS="rh-perl$PERL_SCL_SHORT_VER rh-nginx$NGINX_SHORT_VER" \ + PATH=/opt/rh/rh-perl$PERL_SCL_SHORT_VER/root/usr/local/bin:/opt/rh/rh-perl$PERL_SCL_SHORT_VER/root/usr/bin:/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/bin:/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/sbin${PATH:+:${PATH}} \ + MANPATH=/opt/rh/rh-perl$PERL_SCL_SHORT_VER/root/usr/share/man:/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/share/man:${MANPATH} \ + PKG_CONFIG_PATH=/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/lib64/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} \ + LD_LIBRARY_PATH=/opt/rh/rh-perl$PERL_SCL_SHORT_VER/root/usr/lib64 \ + PERL5LIB="/opt/rh/rh-nginx$NGINX_SHORT_VER/root/usr/lib64/perl5/vendor_perl${PERL5LIB:+:${PERL5LIB}}" + +LABEL summary="${SUMMARY}" \ + description="${DESCRIPTION}" \ + io.k8s.description="${DESCRIPTION}" \ + io.k8s.display-name="Nginx ${NGINX_VERSION}" \ + io.openshift.expose-services="8080:http" \ + io.openshift.expose-services="8443:https" \ + io.openshift.tags="builder,${NAME},rh-${NAME}${NGINX_SHORT_VER}" \ + com.redhat.component="rh-${NAME}${NGINX_SHORT_VER}-container" \ + name="rhscl/${NAME}-${NGINX_SHORT_VER}-rhel7" \ + version="1" \ + com.redhat.license_terms="https://www.redhat.com/en/about/red-hat-end-user-license-agreements#rhel" \ + maintainer="SoftwareCollections.org " \ + help="For more information visit https://github.com/sclorg/${NAME}-container" \ + usage="s2i build rhscl/${NAME}-${NGINX_SHORT_VER}-rhel7:latest " + +ENV NGINX_CONFIGURATION_PATH=${APP_ROOT}/etc/nginx.d \ + NGINX_CONF_PATH=/etc/opt/rh/rh-nginx${NGINX_SHORT_VER}/nginx/nginx.conf \ + NGINX_DEFAULT_CONF_PATH=${APP_ROOT}/etc/nginx.default.d \ + NGINX_CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/nginx \ + NGINX_APP_ROOT=${APP_ROOT} \ + NGINX_LOG_PATH=/var/opt/rh/rh-nginx${NGINX_SHORT_VER}/log/nginx \ + NGINX_PERL_MODULE_PATH=${APP_ROOT}/etc/perl + +RUN yum install -y yum-utils && \ + prepare-yum-repositories rhel-server-rhscl-7-rpms && \ + INSTALL_PKGS="nss_wrapper bind-utils gettext hostname rh-nginx${NGINX_SHORT_VER} rh-nginx${NGINX_SHORT_VER}-nginx \ + rh-nginx${NGINX_SHORT_VER}-nginx-mod-stream rh-nginx${NGINX_SHORT_VER}-nginx-mod-http-perl" && \ + yum install -y --setopt=tsflags=nodocs $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y clean all --enablerepo='*' + +# Copy the S2I scripts from the specific language image to $STI_SCRIPTS_PATH +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# Copy extra files to the image. +COPY ./root/ / + +# In order to drop the root user, we have to make some directories world +# writeable as OpenShift default security model is to run the container under +# random UID. +RUN sed -i -f ${NGINX_APP_ROOT}/nginxconf.sed ${NGINX_CONF_PATH} && \ + chmod a+rwx ${NGINX_CONF_PATH} && \ + mkdir -p ${NGINX_APP_ROOT}/etc/nginx.d/ && \ + mkdir -p ${NGINX_APP_ROOT}/etc/nginx.default.d/ && \ + mkdir -p ${NGINX_APP_ROOT}/src/nginx-start/ && \ + mkdir -p ${NGINX_CONTAINER_SCRIPTS_PATH}/nginx-start && \ + mkdir -p ${NGINX_LOG_PATH} && \ + mkdir -p ${NGINX_PERL_MODULE_PATH} && \ + ln -s ${NGINX_LOG_PATH} /var/log/nginx && \ + ln -s /etc/opt/rh/rh-nginx${NGINX_SHORT_VER}/nginx /etc/nginx && \ + ln -s /opt/rh/rh-nginx${NGINX_SHORT_VER}/root/usr/share/nginx /usr/share/nginx && \ + chmod -R a+rwx ${NGINX_APP_ROOT}/etc && \ + chmod -R a+rwx /var/opt/rh/rh-nginx${NGINX_SHORT_VER} && \ + chmod -R a+rwx ${NGINX_CONTAINER_SCRIPTS_PATH}/nginx-start && \ + chown -R 1001:0 ${NGINX_APP_ROOT} && \ + chown -R 1001:0 /var/opt/rh/rh-nginx${NGINX_SHORT_VER} && \ + chown -R 1001:0 ${NGINX_CONTAINER_SCRIPTS_PATH}/nginx-start && \ + chmod -R a+rwx /var/run && \ + chown -R 1001:0 /var/run && \ + rpm-file-permissions + +USER 1001 + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/opt/rh/rh-nginx116/root/usr/share/nginx/html"] +# VOLUME ["/var/opt/rh/rh-nginx116/log/nginx/"] + +ENV BASH_ENV=${NGINX_APP_ROOT}/etc/scl_enable \ + ENV=${NGINX_APP_ROOT}/etc/scl_enable \ + PROMPT_COMMAND=". ${NGINX_APP_ROOT}/etc/scl_enable" + +CMD $STI_SCRIPTS_PATH/usage diff --git a/tests/data/nodejs-16/README.md b/tests/data/nodejs-16/README.md new file mode 100644 index 0000000..a787130 --- /dev/null +++ b/tests/data/nodejs-16/README.md @@ -0,0 +1,207 @@ +Nginx 1.16 server and a reverse proxy server container image +============================================================ +This container image includes Nginx 1.16 server and a reverse server for OpenShift and general usage. +Users can choose between RHEL, CentOS and Fedora based images. +The RHEL images are available in the [Red Hat Container Catalog](https://access.redhat.com/containers/), +the CentOS images are available on [Quay.io](https://quay.io/organization/centos7), +and the Fedora images are available in [Fedora Registry](https://registry.fedoraproject.org/). +The resulting image can be run using [podman](https://github.com/containers/libpod). + +Note: while the examples in this README are calling `podman`, you can replace any such calls by `docker` with the same arguments. + + +Description +----------- + +Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and IMAP +protocols, with a strong focus on high concurrency, performance and low memory usage. The container +image provides a containerized packaging of the nginx 1.16 daemon. The image can be used +as a base image for other applications based on nginx 1.16 web server. +Nginx server image can be extended using Openshift's `Source` build feature. + + +Usage in OpenShift +------------------ +In this example, we assume that you are using the `rhel8/nginx-116` image, available through the `nginx:1.16` imagestream tag in Openshift. +To build a simple [test-app](https://github.com/sclorg/nginx-container/tree/master/examples/1.16/test-app) application in Openshift: + +``` +oc new-app nginx:1.16~https://github.com/sclorg/nginx-container.git --context-dir=1.16/test/test-app/ +``` + +To access the application: +``` +$ oc get pods +$ oc exec -- curl 127.0.0.1:8080 +``` + + +Source-to-Image framework and scripts +------------------------------------- +This image supports the [Source-to-Image](https://docs.openshift.com/container-platform/4.4/builds/build-strategies.html#images-create-s2i_build-strategies) +(S2I) strategy in OpenShift. The Source-to-Image is an OpenShift framework +which makes it easy to write images that take application source code as +an input, use a builder image like this Nginx container image, and produce +a new image that runs the assembled application as an output. + +In case of Nginx container image, the application source code is typically +either static HTML pages or configuration files. + +To support the Source-to-Image framework, important scripts are included in the builder image: + +* The `/usr/libexec/s2i/run` script is set as the default command in the resulting container image (the new image with the application artifacts). + +* The `/usr/libexec/s2i/assemble` script inside the image is run to produce a new image with the application artifacts. The script takes sources of a given application (HTML pages), Nginx configuration files, and places them into appropriate directories inside the image. The structure of nginx-app can look like this: + +**`./nginx.conf`**-- + The main nginx configuration file + +**`./nginx-cfg/*.conf`** + Should contain all nginx configuration we want to include into image + +**`./nginx-default-cfg/*.conf`** + Contains any nginx config snippets to include in the default server block + +**`./nginx-start/*.sh`** + Contains shell scripts that are sourced right before nginx is launched + +**`./nginx-perl/*.pm`** + Contains perl modules to be use by `perl_modules` and `perl_require` directives + +**`./`** + Should contain nginx application source code + + +Build an application using a Dockerfile +--------------------------------------- +Compared to the Source-to-Image strategy, using a Dockerfile is a more +flexible way to build an Nginx container image with an application. +Use a Dockerfile when Source-to-Image is not sufficiently flexible for you or +when you build the image outside of the OpenShift environment. + +To use the Nginx image in a Dockerfile, follow these steps: + +#### 1. Pull a base builder image to build on + +podman pull rhel8/nginx-116 + +#### 2. Pull an application code + +An example application available at https://github.com/sclorg/nginx-container.git is used here. To adjust the example application, clone the repository. + +``` +git clone https://github.com/sclorg/nginx-container.git nginx-container +cd nginx-container/examples/1.16/ +``` + +#### 3. Prepare an application inside a container + +This step usually consists of at least these parts: + +* putting the application source into the container +* moving configuration files to the correct place (if available in the application source code) +* setting the default command in the resulting image + +For all these three parts, you can either set up all manually and use the `nginx` command explicitly in the Dockerfile ([3.1.](#31-to-use-own-setup-create-a-dockerfile-with-this-content)), or you can use the Source-to-Image scripts inside the image ([3.2.](#32-to-use-the-source-to-image-scripts-and-build-an-image-using-a-dockerfile-create-a-dockerfile-with-this-content). For more information about these scripts, which enable you to set-up and run the nginx daemon, see the "Source-to-Image framework and scripts" section above. + +##### 3.1. To use your own setup, create a Dockerfile with this content: + +``` +FROM registry.access.redhat.com/ubi8/nginx-116 + +# Add application sources +ADD test-app/nginx.conf "${NGINX_CONF_PATH}" +ADD test-app/nginx-default-cfg/*.conf "${NGINX_DEFAULT_CONF_PATH}" +ADD test-app/nginx-cfg/*.conf "${NGINX_CONFIGURATION_PATH}" +ADD test-app/*.html . + +# Run script uses standard ways to run the application +CMD nginx -g "daemon off;" +``` + +##### 3.2. To use the Source-to-Image scripts and build an image using a Dockerfile, create a Dockerfile with this content: + +``` +FROM registry.access.redhat.com/ubi8/nginx-116 + +# Add application sources to a directory that the assemble script expects them +# and set permissions so that the container runs without root access +# With older docker that does not support --chown option for ADD statement, +# use these statements instead: +# USER 0 +# ADD app-src /tmp/src +# RUN chown -R 1001:0 /tmp/src +# USER 1001 +ADD --chown 1001:0 app-src /tmp/src + +# Let the assemble script to install the dependencies +RUN /usr/libexec/s2i/assemble + +# Run script uses standard ways to run the application +CMD /usr/libexec/s2i/run +``` + +#### 4. Build a new image from a Dockerfile prepared in the previous step +``` +podman build -t nginx-app . +``` + +#### 5. Run the resulting image with the final application +``` +podman run -d nginx-app +``` + + +Direct usage with a mounted directory +------------------------------------- +An example of the data on the host for the following example: +``` +$ ls -lZ /wwwdata/html +-rw-r--r--. 1 1001 1001 54321 Jan 01 12:34 index.html +-rw-r--r--. 1 1001 1001 5678 Jan 01 12:34 page.html +``` + +If you want to run the image directly and mount the static pages available in the `/wwwdata/` directory on the host +as a container volume, execute the following command: + +``` +$ podman run -d --name nginx -p 8080:8080 -v /wwwdata:/opt/app-root/src:Z rhel8/nginx-116 nginx -g "daemon off;" +``` + +This creates a container named `nginx` running the Nginx server, serving data from +the `/wwwdata/` directory. Port 8080 is exposed and mapped to the host. +You can pull the data from the nginx container using this command: + +``` +$ curl -Lk 127.0.0.1:8080 +``` + +You can replace `/wwwdata/` with location of your web root. Please note that this has to be an **absolute** path, due to podman requirements. + + +Environment variables and volumes +--------------------------------- +The nginx container image supports the following configuration variable, which can be set by using the `-e` option with the podman run command: + + +**`NGINX_LOG_TO_VOLUME`** + When `NGINX_LOG_TO_VOLUME` is set, nginx logs into `/var/log/nginx/`. In case of RHEL-7 and CentOS-7 images, this is a symlink to `/var/opt/rh/rh-nginx116/log/nginx/`. + + +Troubleshooting +--------------- +By default, nginx access logs are written to standard output and error logs are written to standard error, so both are available in the container log. The log can be examined by running: + + podman logs + +**If `NGINX_LOG_TO_VOLUME` variable is set, nginx logs into `/var/log/nginx/`. In case of RHEL-7 and CentOS-7 images, this is a symlink to `/var/opt/rh/rh-nginx116/log/nginx/`, which can be mounted to host system using the container volumes.** + + +See also +-------- +Dockerfile and other sources for this container image are available on +https://github.com/sclorg/nginx-container. +In that repository you also can find another versions of Python environment Dockerfiles. +Dockerfile for CentOS is called `Dockerfile`, Dockerfile for RHEL7 is called `Dockerfile.rhel7`, +for RHEL8 it's `Dockerfile.rhel8` and the Fedora Dockerfile is called Dockerfile.fedora. + diff --git a/tests/data/nodejs-16/help.md b/tests/data/nodejs-16/help.md new file mode 100644 index 0000000..a787130 --- /dev/null +++ b/tests/data/nodejs-16/help.md @@ -0,0 +1,207 @@ +Nginx 1.16 server and a reverse proxy server container image +============================================================ +This container image includes Nginx 1.16 server and a reverse server for OpenShift and general usage. +Users can choose between RHEL, CentOS and Fedora based images. +The RHEL images are available in the [Red Hat Container Catalog](https://access.redhat.com/containers/), +the CentOS images are available on [Quay.io](https://quay.io/organization/centos7), +and the Fedora images are available in [Fedora Registry](https://registry.fedoraproject.org/). +The resulting image can be run using [podman](https://github.com/containers/libpod). + +Note: while the examples in this README are calling `podman`, you can replace any such calls by `docker` with the same arguments. + + +Description +----------- + +Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and IMAP +protocols, with a strong focus on high concurrency, performance and low memory usage. The container +image provides a containerized packaging of the nginx 1.16 daemon. The image can be used +as a base image for other applications based on nginx 1.16 web server. +Nginx server image can be extended using Openshift's `Source` build feature. + + +Usage in OpenShift +------------------ +In this example, we assume that you are using the `rhel8/nginx-116` image, available through the `nginx:1.16` imagestream tag in Openshift. +To build a simple [test-app](https://github.com/sclorg/nginx-container/tree/master/examples/1.16/test-app) application in Openshift: + +``` +oc new-app nginx:1.16~https://github.com/sclorg/nginx-container.git --context-dir=1.16/test/test-app/ +``` + +To access the application: +``` +$ oc get pods +$ oc exec -- curl 127.0.0.1:8080 +``` + + +Source-to-Image framework and scripts +------------------------------------- +This image supports the [Source-to-Image](https://docs.openshift.com/container-platform/4.4/builds/build-strategies.html#images-create-s2i_build-strategies) +(S2I) strategy in OpenShift. The Source-to-Image is an OpenShift framework +which makes it easy to write images that take application source code as +an input, use a builder image like this Nginx container image, and produce +a new image that runs the assembled application as an output. + +In case of Nginx container image, the application source code is typically +either static HTML pages or configuration files. + +To support the Source-to-Image framework, important scripts are included in the builder image: + +* The `/usr/libexec/s2i/run` script is set as the default command in the resulting container image (the new image with the application artifacts). + +* The `/usr/libexec/s2i/assemble` script inside the image is run to produce a new image with the application artifacts. The script takes sources of a given application (HTML pages), Nginx configuration files, and places them into appropriate directories inside the image. The structure of nginx-app can look like this: + +**`./nginx.conf`**-- + The main nginx configuration file + +**`./nginx-cfg/*.conf`** + Should contain all nginx configuration we want to include into image + +**`./nginx-default-cfg/*.conf`** + Contains any nginx config snippets to include in the default server block + +**`./nginx-start/*.sh`** + Contains shell scripts that are sourced right before nginx is launched + +**`./nginx-perl/*.pm`** + Contains perl modules to be use by `perl_modules` and `perl_require` directives + +**`./`** + Should contain nginx application source code + + +Build an application using a Dockerfile +--------------------------------------- +Compared to the Source-to-Image strategy, using a Dockerfile is a more +flexible way to build an Nginx container image with an application. +Use a Dockerfile when Source-to-Image is not sufficiently flexible for you or +when you build the image outside of the OpenShift environment. + +To use the Nginx image in a Dockerfile, follow these steps: + +#### 1. Pull a base builder image to build on + +podman pull rhel8/nginx-116 + +#### 2. Pull an application code + +An example application available at https://github.com/sclorg/nginx-container.git is used here. To adjust the example application, clone the repository. + +``` +git clone https://github.com/sclorg/nginx-container.git nginx-container +cd nginx-container/examples/1.16/ +``` + +#### 3. Prepare an application inside a container + +This step usually consists of at least these parts: + +* putting the application source into the container +* moving configuration files to the correct place (if available in the application source code) +* setting the default command in the resulting image + +For all these three parts, you can either set up all manually and use the `nginx` command explicitly in the Dockerfile ([3.1.](#31-to-use-own-setup-create-a-dockerfile-with-this-content)), or you can use the Source-to-Image scripts inside the image ([3.2.](#32-to-use-the-source-to-image-scripts-and-build-an-image-using-a-dockerfile-create-a-dockerfile-with-this-content). For more information about these scripts, which enable you to set-up and run the nginx daemon, see the "Source-to-Image framework and scripts" section above. + +##### 3.1. To use your own setup, create a Dockerfile with this content: + +``` +FROM registry.access.redhat.com/ubi8/nginx-116 + +# Add application sources +ADD test-app/nginx.conf "${NGINX_CONF_PATH}" +ADD test-app/nginx-default-cfg/*.conf "${NGINX_DEFAULT_CONF_PATH}" +ADD test-app/nginx-cfg/*.conf "${NGINX_CONFIGURATION_PATH}" +ADD test-app/*.html . + +# Run script uses standard ways to run the application +CMD nginx -g "daemon off;" +``` + +##### 3.2. To use the Source-to-Image scripts and build an image using a Dockerfile, create a Dockerfile with this content: + +``` +FROM registry.access.redhat.com/ubi8/nginx-116 + +# Add application sources to a directory that the assemble script expects them +# and set permissions so that the container runs without root access +# With older docker that does not support --chown option for ADD statement, +# use these statements instead: +# USER 0 +# ADD app-src /tmp/src +# RUN chown -R 1001:0 /tmp/src +# USER 1001 +ADD --chown 1001:0 app-src /tmp/src + +# Let the assemble script to install the dependencies +RUN /usr/libexec/s2i/assemble + +# Run script uses standard ways to run the application +CMD /usr/libexec/s2i/run +``` + +#### 4. Build a new image from a Dockerfile prepared in the previous step +``` +podman build -t nginx-app . +``` + +#### 5. Run the resulting image with the final application +``` +podman run -d nginx-app +``` + + +Direct usage with a mounted directory +------------------------------------- +An example of the data on the host for the following example: +``` +$ ls -lZ /wwwdata/html +-rw-r--r--. 1 1001 1001 54321 Jan 01 12:34 index.html +-rw-r--r--. 1 1001 1001 5678 Jan 01 12:34 page.html +``` + +If you want to run the image directly and mount the static pages available in the `/wwwdata/` directory on the host +as a container volume, execute the following command: + +``` +$ podman run -d --name nginx -p 8080:8080 -v /wwwdata:/opt/app-root/src:Z rhel8/nginx-116 nginx -g "daemon off;" +``` + +This creates a container named `nginx` running the Nginx server, serving data from +the `/wwwdata/` directory. Port 8080 is exposed and mapped to the host. +You can pull the data from the nginx container using this command: + +``` +$ curl -Lk 127.0.0.1:8080 +``` + +You can replace `/wwwdata/` with location of your web root. Please note that this has to be an **absolute** path, due to podman requirements. + + +Environment variables and volumes +--------------------------------- +The nginx container image supports the following configuration variable, which can be set by using the `-e` option with the podman run command: + + +**`NGINX_LOG_TO_VOLUME`** + When `NGINX_LOG_TO_VOLUME` is set, nginx logs into `/var/log/nginx/`. In case of RHEL-7 and CentOS-7 images, this is a symlink to `/var/opt/rh/rh-nginx116/log/nginx/`. + + +Troubleshooting +--------------- +By default, nginx access logs are written to standard output and error logs are written to standard error, so both are available in the container log. The log can be examined by running: + + podman logs + +**If `NGINX_LOG_TO_VOLUME` variable is set, nginx logs into `/var/log/nginx/`. In case of RHEL-7 and CentOS-7 images, this is a symlink to `/var/opt/rh/rh-nginx116/log/nginx/`, which can be mounted to host system using the container volumes.** + + +See also +-------- +Dockerfile and other sources for this container image are available on +https://github.com/sclorg/nginx-container. +In that repository you also can find another versions of Python environment Dockerfiles. +Dockerfile for CentOS is called `Dockerfile`, Dockerfile for RHEL7 is called `Dockerfile.rhel7`, +for RHEL8 it's `Dockerfile.rhel8` and the Fedora Dockerfile is called Dockerfile.fedora. + diff --git a/tests/test_distgit.py b/tests/test_distgit.py index f12bdf2..38e548e 100644 --- a/tests/test_distgit.py +++ b/tests/test_distgit.py @@ -62,10 +62,10 @@ def test_pull_upstream(self): assert os.path.isfile(dpath) @pytest.mark.distgit - def test_distgit_changes(self): + def test_distgit_merge_changes(self): self.ir.conf["from_tag"] = "test" tmp = Path(self.ir._get_tmp_workdir()) - self.ir.dist_git_changes() + self.ir.dist_git_merge_changes() dpath = tmp / self.component / 'Dockerfile' assert os.path.isfile(dpath) assert not (tmp / self.component / "test" / "test-openshift.yaml").exists() @@ -77,7 +77,7 @@ def test_distgit_changes(self): shutil.rmtree(tmp / self.component) @pytest.mark.distgit - def test_distgit_changes_openshift_yaml(self): + def test_distgit_merge_changes_openshift_yaml(self): # TODO # As soon as s2i-base-container will contain file 'test/test-openshift.yaml' # Then change it to once @@ -85,7 +85,7 @@ def test_distgit_changes_openshift_yaml(self): self.ir.conf["from_tag"] = "test" tmp = Path(self.ir._get_tmp_workdir()) self.ir.distgit._clone_downstream(self.component, "main") - self.ir.dist_git_changes() + self.ir.dist_git_merge_changes() dpath = tmp / self.component / 'Dockerfile' assert os.path.isfile(dpath) tag_found = False @@ -99,7 +99,7 @@ def test_distgit_changes_openshift_yaml(self): def test_tag_dockerfile(self): tmp = Path(self.ir._get_tmp_workdir()) self.ir.conf["from_tag"] = "test" - self.ir.dist_git_changes() + self.ir.dist_git_merge_changes() cpath = tmp / self.component dpath = cpath / 'Dockerfile' found_tag = False