From ec4f6cf05a1f4f34235d81c828a572da3f00e38b Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Mon, 5 Apr 2021 14:46:48 +0300 Subject: [PATCH 01/16] feat(docs): make guide/tutorial more specific --- doc/guide.rst | 600 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 590 insertions(+), 10 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index a40606f4..e9d2e141 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -1,17 +1,597 @@ Getting started =============== -1. Step one: :doc:`install Universum `. Use ``{python} -m universum --help`` to make sure the installation - was successful, and also to get the list of available :doc:`parameters `. +This guide will provide an example step-by-step tutorial on setting up CI for a GitHub project, using Jenkins server, +GitHub application and Pylint analyzer. These are the steps to take: -2. Step two: :ref:`initialize Universum ` by creating a default :doc:`configuration - file ` and modifying it according to the project needs. +1. :ref:`Install Universum ` +2. :ref:`Load project to VCS ` +3. :ref:`Initialize Unviersum ` +4. :ref:`Configure project ` +5. :ref:`Add static analyzer ` +6. :ref:`Configuration filtering ` +7. :ref:`Upload changes to VCS ` +8. :ref:`Run Universum in default mode ` +9. :ref:`Set up Jenkins server ` +10. :ref:`Create a Jenkins job ` -3. Step three: use ``{python} -m universum run`` to :ref:`check the provided configuration - locally `. -4. Step four: submit a working configuration file to a VCS and pass required :doc:`parameters ` to `Universum` - to work with it. +.. _guide#install: -5. Configure CI, using `Universum`, on a CI server. See the following guides for :doc:`TeamCity ` or - :ref:`GitHub `. +Install Universum +----------------- + +First, before setting up Continious Integration, let's implement and test Universum support locally. + +1. Make sure your system meets Universum :doc:`prerequisites ` +2. Install Univesrum using ``{pip} install -U universum`` command from command line +3. Run ``{python} -m universum --help`` to make sure the installation was successful + +If nothing went wrong, you should get a list of available :doc:`command line parameters `. + + +.. _guide#create: + +Create project in VCS +--------------------- + +For demonstration purposes let's create a project on GitHub. To do so, we'll need to do the following: + +1. Register a user on GitHub, if not already (press the `Sign up` button and follow the instructions) +2. Get to `Create a new repository` interactive dialog by doing any of these: + + * press `New` button in `Repositories` block on main page (https://github.com/) + * press ``+`` button in upper right corner and select `New repository` + * press `New` button on `Repositories` tab on personal page (https://github.com/*YOUR-USERNAME*?tab=repositories) + * simply proceed to https://github.com/new + +3. Enter requested parameters: + + * a name (we will use ``universum-test-project``) + * `Public/Private` (we will use `Public`) + * `Initialize this repository with` (we will use `Add a README file`) + + +Read more about creating repositories in `a detailed GitHub guide +`__ + +After creating a repo online, clone it locally:: + + git clone https://github.com/YOUR-USERNAME/universum-test-project.git + cd universum-test-project + ls -a + +The output of such command should be:: + + . .. .git README.md + +From now on we will refer to this directory as a project root. + + +.. _guide#init: + +Initialize Universum +-------------------- + +After previous step, we should still be in project root directory. +Let's :ref:`initialize Universum ` in that directory:: + + {python} -m universum init + +That will create a new file ``.universum.py`` and print a command to use it:: + + {python} -m universum run + +The default :doc:`configuration file `, created by this command, looks like this:: + + #!/usr/bin/env python3.7 + + from universum.configuration_support import Configuration + + configs = Configuration([Step(name='Show directory contents', command=['ls', '-la']), + Step(name='Print a line', command=['bash', '-c', 'echo Hello world'])]) + + if __name__ == '__main__': + print(configs.dump()) + +Running suggested command ``{python} -m universum run`` should result in launching Universum and +getting an output like this:: + + ==> Universum 1.0.0 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 2. Preprocessing artifact lists + └ [Success] + + 3. Executing build steps + | 3.1. [ 1/2 ] Show directory contents + | | $ /usr/bin/ls -a + | | . .. artifacts .git README.md .universum.py + | └ [Success] + | + | 3.2. [ 2/2 ] Print a line + | | $ /usr/bin/bash -c 'echo Hello world' + | | Hello world + | └ [Success] + | + └ [Success] + + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/2 ] Show directory contents - Success + | ==> 3.2. [ 2/2 ] Print a line - Success + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Collecting artifacts + └ [Success] + + ==> Universum 1.0.0 finished execution + +Running this command will also produce a directory ``artifacts``, containing single file: ``CONFIGS_DUMP.txt``. +The reason for this file existance will be explained in the next paragraph. + + +.. _guide#configure: + +Configure project +----------------- + +Let's add some actual sources to project directory. For example, a simple script ``run.sh``:: + + #!/usr/bin/env bash + + if [ "$1" = "pass" ] + then + echo "Script succeeded" + exit 0 + elif [ "$1" = "fail" ] + then + echo "Script failed" + exit 1 + else + echo "Unknown outcome" + exit 2 + fi + +Then, in configuration file we can refer to this script:: + + configs = Configuration([Step(name='Run script', command=['run.sh', 'pass'])]) + +After this change, running ``{python} -m universum run`` should result in the following output:: + + ==> Universum 1.0.0 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file/home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 2. Preprocessing artifact lists + └ [Success] + + 3. Executing build steps + | 3.1. [ 1/1 ] Run script + | | $ /home/user/work/run.sh pass + | | Script succeeded + | └ [Success] + | + └ [Success] + + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/1 ] Run script - Success + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Collecting artifacts + └ [Success] + + ==> Universum 1.0.0 finished execution + +More info on project configuration file can be found on :doc:`project configuration ` page. +Final configuration may be a result of :class:`~universum.configuration_support.Step` objects multiplication +and filtering, but the explicit list of steps to be executed can be found in ``CONFIGS_DUMP.txt`` file in +``artifacts`` directory. + + +.. _guide#analyzer: + +Add static analyzer +------------------- + +Say, instead of writing a script in `bash` we used `python`, and have the following script ``run.py``:: + + import sys + + if len(sys.argv) < 2: + print("Unknown outcome") + sys.exit(2) + if sys.argv[1] == "pass": + print("Script succeeded") + sys.exit(0) + print("Script failed") + sys.exit(1) + +To use this script, we'd have to modify ``configs`` to this:: + + configs = Configuration([Step(name='Run script', command=['python', 'run.py', 'pass'])]) + +which will get the same result as the previous one. + +But, let's presume we want to make sure our Python code style +corresponds to PEP-8 from the very beginning. We might install `Pylint `__ via +``{pip} install -U pylint``, and then add the code style check:: + + configs = Configuration([ + Step(name='Run script', command=['{python}', 'run.py', 'pass']), + Step(name='Pylint check', code_report=True, command=[ + '{python}', '-m', 'universum.analyzers.pylint', '--python-version', '3.7', + '--result-file', '${CODE_REPORT_FILE}', '--files', '*.py' + ]) + ]) + +Running Universum with this config will produce the following output:: + + ==> Universum 1.0.0 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 2. Preprocessing artifact lists + └ [Success] + + 3. Executing build steps + | 3.1. [ 1/2 ] Run script + | | $ /usr/bin/{python} run.py pass + | └ [Success] + | + | 3.2. [ 2/2 ] Pylint check + | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file /home/user/universum-test-project/code_report_results/Pylint_check.json --files '*.py' + | | Error: Module sh got exit code 1 + | └ [Failed] + | + └ [Success] + + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/2 ] Run script - Success + | ==> 3.2. [ 2/2 ] Pylint check - Failed + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Collecting artifacts + └ [Success] + + ==> Universum 1.0.0 finished execution + +Which means we already have some code style issues in the project sources. Open the ``Pylint_check.json`` file +with code style check results:: + + [ + { + "type": "convention", + "module": "run", + "obj": "", + "line": 1, + "column": 0, + "path": "run.py", + "symbol": "missing-module-docstring", + "message": "Missing module docstring", + "message-id": "C0114" + } + ] + +Let's presume we do not indend to add docstrings to every module. Then this check failure can be fixed by simply +putting a ``pylintrc`` file in project root with following content:: + + [MESSAGES CONTROL] + disable = missing-docstring + +Leading to `Universum` successful execution. + + +.. _guide#filter: + +Configuration filtering +----------------------- + +Let's presume, we want to only run one of the two steps currently listed in ``confis``. For example, to double check +the code style we only want to run a ``Pylint check`` step. This can be easily achieved by simply using +the ``--filter`` `command-line parameter `__. When running +a ``{python} -m universum run -f Pylint`` command, we will get the following output:: + + ==> Universum 1.0.0 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 2. Preprocessing artifact lists + └ [Success] + + 3. Executing build steps + | 3.1. [ 1/1 ] Pylint check + | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file '${CODE_REPORT_FILE}' --files '*.py' + | └ [Success] + | + └ [Success] + + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/1 ] Pylint check - Success + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Collecting artifacts + └ [Success] + + ==> Universum 1.0.0 finished execution + +This is quite useful for local checks. + + +.. _guide#upload: + +Upload changes to VCS +--------------------- + +Now that the project has some sources, we can upload them to VCS. But not all of the files, that are now present +in project root directory, are required in VCS. Here are some directories, that might be present locally, but +not to be committed: + + * ``__pycache__`` + * ``artifacts`` + * ``code_report_results`` + +To prevent them from being committed to GitHub, create a file named ``.gitignore`` with these directories listed in it:: + + __pycache__ + artifacts + code_report_results + +After this, use these common `Git` commands:: + + git add --all + git commit -m "Add project sources" + git push + +Executing these commands may require your GitHub user name, password and/or e-mail address. If so, +required info will be prompted to input via command line during command execution. + +Successful repository update will lead to all the files described above arriving on GitHub, along with the new +commit ``Add project sources``. + + +.. _guide#launch: + +Run Universum in default mode +----------------------------- + +Now that project sources can be accessed online, we may launch `Universum` in default CI mode, including +downloading sources from server. + +.. note:: + + As we are now planing to work with Git repository, `Universum` will :doc:`require ` + Git CLI installed in the system, and some additional Python packages specific for Git. + +We can install all these by:: + + sudo apt install git + {pip} install -U universum[git] + +Now let's leave the project root directory, as we no longer need local sources, create a new one, +``universum-ci-checks``, and launch `Universum` there:: + + cd .. + mkdir universum-ci-checks + python -m universum --no-diff --vcs-type git --git-repo https://github.com/YOUR-USERNAME/universum-test-project.git + +We will now get a log, very similar to previous one, but with some additional sections: + +.. code-block:: + :linenos: + :emphasize-lines: 2-17, 26-28, 45-48, 62-66 + + ==> Universum 1.0.0 started execution + 1. Preparing repository + | ==> Adding file /home/user/universum-ci-checks/artifacts/REPOSITORY_STATE.txt to artifacts... + | 1.1. Cloning repository + | | ==> Cloning 'https://github.com/YOUR-USERNAME/universum-test-project.git'... + | | ==> Cloning into '/home/user/universum-ci-checks/temp'... + | | ==> POST git-upload-pack (165 bytes) + | | ==> remote: Enumerating objects: 9, done. + | | ==> remote: Total 9 (delta 0), reused 6 (delta 0), pack-reused 0 + | | ==> Please note that default remote name is 'origin' + | └ [Success] + | + | 1.2. Checking out + | | ==> Checking out 'HEAD'... + | └ [Success] + | + └ [Success] + + 2. Processing project configs + | ==> Adding file /home/user/universum-ci-checks/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 3. Preprocessing artifact lists + └ [Success] + + 4. Reporting build start + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Executing build steps + | 5.1. [ 1/2 ] Run script + | | ==> Adding file /home/user/universum-ci-checks/artifacts/Run_script_log.txt to artifacts... + | | ==> Execution log is redirected to file + | | $ /usr/bin/{python} run.py pass + | └ [Success] + | + | 5.2. [ 2/2 ] Pylint check + | | ==> Adding file /home/user/universum-ci-checks/artifacts/Pylint_check_log.txt to artifacts... + | | ==> Execution log is redirected to file + | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file /home/user/universum-ci-checks/temp/code_report_results/Pylint_check.json --files '*.py' + | └ [Success] + | + └ [Success] + + 6. Processing code report results + | ==> Adding file /home/user/universum-ci-checks/artifacts/Static_analysis_report.json to artifacts... + | ==> Issues not found. + └ [Success] + + 7. Collecting artifacts + └ [Success] + + 8. Reporting build result + | ==> Here is the summarized build result: + | ==> 5. Executing build steps + | ==> 5.1. [ 1/2 ] Run script - Success + | ==> 5.2. [ 2/2 ] Pylint check - Success + | ==> 7. Collecting artifacts - Success + | ==> Nowhere to report. Skipping... + └ [Success] + + 9. Finalizing + | 9.1. Cleaning copied sources + | └ [Success] + | + └ [Success] + + ==> Universum 1.0.0 finished execution + +We will look at `reporting` closer a little later, and for now pay attention to ``Preparing repository``/``Finalizing`` +blocks. As a CI system, `Univesrum` downloads sources from server, runs checks on them and then clears up. +Pay attention to the directory ``artifacts``. Until now it contained only the ``CONFIGS_DUMP.txt`` file with +full step list; but now it contains a lot of new files: + + * REPOSITORY_STATE.txt + * Run_script_log.txt + * Pylint_check_log.txt + * Static_analysis_report.json + +First one describes what sources were used for this exact build: repo, fetch target (e.g. `HEAD` or commit hash), +list of downloaded files. In case of other VCS types (such as Perforce or local folder) the contents of this file +will vary; the purpose of this file is repeatability of the builds. + +Next two files are step execution logs. When project configuration includes many different steps, each containing +a long execution log, reading the whole `Universum` log in console may be not that user-friendly. That's why when +executing in console, by default the logs are written to files. This befaviour may be changed via ``--out`` +`command-line parameter `__. + +And, finally, the last file, ``Static_analysis_report.json``, contains all issues found by ``code_report=True`` +steps. As we already fixed all Pylint issues, it should now contain an empty list ``[]``. + + +.. _guide#jenkins: + +Set up Jenkins server +--------------------- + +Now that CI builds are working locally, let's set up a real automated CI. + +Create a ``Dockerfile`` with following content:: + + FROM jenkins/jenkins:2.263.1-lts-slim + USER root + RUN apt-get update && apt-get install -y apt-transport-https \ + ca-certificates curl gnupg2 \ + software-properties-common + RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - + RUN apt-key fingerprint 0EBFCD88 + RUN add-apt-repository \ + "deb [arch=amd64] https://download.docker.com/linux/debian \ + $(lsb_release -cs) stable" + RUN apt-get update && apt-get install -y docker-ce-cli + RUN apt-get update && apt-get install -y git {python} python3-pip + RUN {python} -m pip install -U pip + USER jenkins + RUN jenkins-plugin-cli --plugins blueocean:1.24.3 + +Execute the following commands:: + + docker network create jenkins + docker run --name jenkins-docker --rm --detach \ + --privileged --network jenkins --network-alias docker \ + --env DOCKER_TLS_CERTDIR=/certs \ + --volume jenkins-docker-certs:/certs/client \ + --volume jenkins-data:/var/jenkins_home \ + --publish 2376:2376 docker:dind + docker build -t myjenkins-blueocean:1.1 . + docker run --name jenkins-blueocean --rm --detach \ + --network jenkins --env DOCKER_HOST=tcp://docker:2376 \ + --env DOCKER_CERT_PATH=/certs/client --env DOCKER_TLS_VERIFY=1 \ + --publish 8080:8080 --publish 50000:50000 \ + --volume jenkins-data:/var/jenkins_home \ + --volume jenkins-docker-certs:/certs/client:ro \ + myjenkins-blueocean:1.1 + +Go to http://localhost:8080 and unlock Jenkins, follow the instruction on a title page: + + 1. execute ``docker exec jenkins-blueocean cat /var/jenkins_home/secrets/initialAdminPassword`` + 2. input the required key and follow further wizard instructions + +Detailed instruction with explanation of the steps can be found `in official Jenkins installation guide +`__. + + +.. _guide#job: + +Create a Jenkins job +-------------------- + +First let's create a simple post-commit check. On Jenkins main page click ``Create a job``, or simply go to +http://localhost:8080/newJob. There enter a job name (for example we will use ``universum_postcommit``), select +a job type (for example we will use ``Pipeline``) and proceed to project configuration. + +On configuration page find ``Build Triggers`` and check the ``GitHub hook trigger for GITScm polling`` checkbox. +After that, go to ``Pipeline``, select ``Pipeline script`` and enter the following script:: + + pipeline { + agent any + stages { + stage ('Universum check') { + steps { + git 'https://github.com/YOUR-USERNAME/universum-test-project.git' + ansiColor('xterm') { + sh("{python} -m universum --no-diff --vcs-type none --file-source-dir universum-test-project") + } + } + } + } + } + +But, actually running this job will fail for now with the following error:: + + /usr/bin/{python}: No module named universum + +Which is expected, because we have not installed neither Universum, nor Git to the Jenkins node. +For now, let's do the following changes to pipeline:: + + pipeline { + agent any + stages { + stage ('Universum check') { + steps { + sh("{pip} install -U universum") + git 'https://github.com/YOUR-USERNAME/universum-test-project.git' + ansiColor('xterm') { + sh("{python} -m universum --no-diff --vcs-type none --file-source-dir universum-test-project") + } + } + } + } + } + + +.. TBD From d8e85a1aca0919dc7b5b5d64a25faa7eb852cd53 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Wed, 7 Apr 2021 16:52:10 +0300 Subject: [PATCH 02/16] wip(docs): make long code/output blocks collapsible --- doc/guide.rst | 400 ++++++++++++++++++++++++++------------------------ 1 file changed, 209 insertions(+), 191 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index e9d2e141..e873dffa 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -74,7 +74,7 @@ Initialize Universum -------------------- After previous step, we should still be in project root directory. -Let's :ref:`initialize Universum ` in that directory:: +Let's :ref:`initialize Universum ` in that directory:: {python} -m universum init @@ -95,42 +95,46 @@ The default :doc:`configuration file `, created by this command, lo print(configs.dump()) Running suggested command ``{python} -m universum run`` should result in launching Universum and -getting an output like this:: - - ==> Universum 1.0.0 started execution - ==> Cleaning artifacts... - 1. Processing project configs - | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... - └ [Success] - - 2. Preprocessing artifact lists - └ [Success] - - 3. Executing build steps - | 3.1. [ 1/2 ] Show directory contents - | | $ /usr/bin/ls -a - | | . .. artifacts .git README.md .universum.py - | └ [Success] - | - | 3.2. [ 2/2 ] Print a line - | | $ /usr/bin/bash -c 'echo Hello world' - | | Hello world - | └ [Success] - | - └ [Success] - - 4. Reporting build result - | ==> Here is the summarized build result: - | ==> 3. Executing build steps - | ==> 3.1. [ 1/2 ] Show directory contents - Success - | ==> 3.2. [ 2/2 ] Print a line - Success - | ==> Nowhere to report. Skipping... - └ [Success] - - 5. Collecting artifacts - └ [Success] - - ==> Universum 1.0.0 finished execution +getting an output like this: + +.. collapsible:: + + ..code-block:: + + ==> Universum 1.0.0 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 2. Preprocessing artifact lists + └ [Success] + + 3. Executing build steps + | 3.1. [ 1/2 ] Show directory contents + | | $ /usr/bin/ls -a + | | . .. artifacts .git README.md .universum.py + | └ [Success] + | + | 3.2. [ 2/2 ] Print a line + | | $ /usr/bin/bash -c 'echo Hello world' + | | Hello world + | └ [Success] + | + └ [Success] + + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/2 ] Show directory contents - Success + | ==> 3.2. [ 2/2 ] Print a line - Success + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Collecting artifacts + └ [Success] + + ==> Universum 1.0.0 finished execution Running this command will also produce a directory ``artifacts``, containing single file: ``CONFIGS_DUMP.txt``. The reason for this file existance will be explained in the next paragraph. @@ -162,36 +166,40 @@ Then, in configuration file we can refer to this script:: configs = Configuration([Step(name='Run script', command=['run.sh', 'pass'])]) -After this change, running ``{python} -m universum run`` should result in the following output:: +After this change, running ``{python} -m universum run`` should result in the following output: - ==> Universum 1.0.0 started execution - ==> Cleaning artifacts... - 1. Processing project configs - | ==> Adding file/home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... - └ [Success] +.. collapsible:: - 2. Preprocessing artifact lists - └ [Success] + ..code-block:: - 3. Executing build steps - | 3.1. [ 1/1 ] Run script - | | $ /home/user/work/run.sh pass - | | Script succeeded - | └ [Success] - | - └ [Success] + ==> Universum 1.0.0 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file/home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] - 4. Reporting build result - | ==> Here is the summarized build result: - | ==> 3. Executing build steps - | ==> 3.1. [ 1/1 ] Run script - Success - | ==> Nowhere to report. Skipping... - └ [Success] + 2. Preprocessing artifact lists + └ [Success] - 5. Collecting artifacts - └ [Success] + 3. Executing build steps + | 3.1. [ 1/1 ] Run script + | | $ /home/user/work/run.sh pass + | | Script succeeded + | └ [Success] + | + └ [Success] - ==> Universum 1.0.0 finished execution + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/1 ] Run script - Success + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Collecting artifacts + └ [Success] + + ==> Universum 1.0.0 finished execution More info on project configuration file can be found on :doc:`project configuration ` page. Final configuration may be a result of :class:`~universum.configuration_support.Step` objects multiplication @@ -235,41 +243,45 @@ corresponds to PEP-8 from the very beginning. We might install `Pylint Universum 1.0.0 started execution - ==> Cleaning artifacts... - 1. Processing project configs - | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... - └ [Success] - - 2. Preprocessing artifact lists - └ [Success] - - 3. Executing build steps - | 3.1. [ 1/2 ] Run script - | | $ /usr/bin/{python} run.py pass - | └ [Success] - | - | 3.2. [ 2/2 ] Pylint check - | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file /home/user/universum-test-project/code_report_results/Pylint_check.json --files '*.py' - | | Error: Module sh got exit code 1 - | └ [Failed] - | - └ [Success] - - 4. Reporting build result - | ==> Here is the summarized build result: - | ==> 3. Executing build steps - | ==> 3.1. [ 1/2 ] Run script - Success - | ==> 3.2. [ 2/2 ] Pylint check - Failed - | ==> Nowhere to report. Skipping... - └ [Success] - - 5. Collecting artifacts - └ [Success] - - ==> Universum 1.0.0 finished execution +Running Universum with this config will produce the following output: + +.. collapsible:: + + ..code-block:: + + ==> Universum 1.0.0 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 2. Preprocessing artifact lists + └ [Success] + + 3. Executing build steps + | 3.1. [ 1/2 ] Run script + | | $ /usr/bin/{python} run.py pass + | └ [Success] + | + | 3.2. [ 2/2 ] Pylint check + | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file /home/user/universum-test-project/code_report_results/Pylint_check.json --files '*.py' + | | Error: Module sh got exit code 1 + | └ [Failed] + | + └ [Success] + + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/2 ] Run script - Success + | ==> 3.2. [ 2/2 ] Pylint check - Failed + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Collecting artifacts + └ [Success] + + ==> Universum 1.0.0 finished execution Which means we already have some code style issues in the project sources. Open the ``Pylint_check.json`` file with code style check results:: @@ -305,35 +317,39 @@ Configuration filtering Let's presume, we want to only run one of the two steps currently listed in ``confis``. For example, to double check the code style we only want to run a ``Pylint check`` step. This can be easily achieved by simply using the ``--filter`` `command-line parameter `__. When running -a ``{python} -m universum run -f Pylint`` command, we will get the following output:: +a ``{python} -m universum run -f Pylint`` command, we will get the following output: + +.. collapsible:: + + ..code-block:: - ==> Universum 1.0.0 started execution - ==> Cleaning artifacts... - 1. Processing project configs - | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... - └ [Success] + ==> Universum 1.0.0 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] - 2. Preprocessing artifact lists - └ [Success] + 2. Preprocessing artifact lists + └ [Success] - 3. Executing build steps - | 3.1. [ 1/1 ] Pylint check - | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file '${CODE_REPORT_FILE}' --files '*.py' - | └ [Success] - | - └ [Success] + 3. Executing build steps + | 3.1. [ 1/1 ] Pylint check + | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file '${CODE_REPORT_FILE}' --files '*.py' + | └ [Success] + | + └ [Success] - 4. Reporting build result - | ==> Here is the summarized build result: - | ==> 3. Executing build steps - | ==> 3.1. [ 1/1 ] Pylint check - Success - | ==> Nowhere to report. Skipping... - └ [Success] + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/1 ] Pylint check - Success + | ==> Nowhere to report. Skipping... + └ [Success] - 5. Collecting artifacts - └ [Success] + 5. Collecting artifacts + └ [Success] - ==> Universum 1.0.0 finished execution + ==> Universum 1.0.0 finished execution This is quite useful for local checks. @@ -397,78 +413,80 @@ Now let's leave the project root directory, as we no longer need local sources, We will now get a log, very similar to previous one, but with some additional sections: -.. code-block:: - :linenos: - :emphasize-lines: 2-17, 26-28, 45-48, 62-66 - - ==> Universum 1.0.0 started execution - 1. Preparing repository - | ==> Adding file /home/user/universum-ci-checks/artifacts/REPOSITORY_STATE.txt to artifacts... - | 1.1. Cloning repository - | | ==> Cloning 'https://github.com/YOUR-USERNAME/universum-test-project.git'... - | | ==> Cloning into '/home/user/universum-ci-checks/temp'... - | | ==> POST git-upload-pack (165 bytes) - | | ==> remote: Enumerating objects: 9, done. - | | ==> remote: Total 9 (delta 0), reused 6 (delta 0), pack-reused 0 - | | ==> Please note that default remote name is 'origin' - | └ [Success] - | - | 1.2. Checking out - | | ==> Checking out 'HEAD'... - | └ [Success] - | - └ [Success] - - 2. Processing project configs - | ==> Adding file /home/user/universum-ci-checks/artifacts/CONFIGS_DUMP.txt to artifacts... - └ [Success] - - 3. Preprocessing artifact lists - └ [Success] - - 4. Reporting build start - | ==> Nowhere to report. Skipping... - └ [Success] - - 5. Executing build steps - | 5.1. [ 1/2 ] Run script - | | ==> Adding file /home/user/universum-ci-checks/artifacts/Run_script_log.txt to artifacts... - | | ==> Execution log is redirected to file - | | $ /usr/bin/{python} run.py pass - | └ [Success] - | - | 5.2. [ 2/2 ] Pylint check - | | ==> Adding file /home/user/universum-ci-checks/artifacts/Pylint_check_log.txt to artifacts... - | | ==> Execution log is redirected to file - | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file /home/user/universum-ci-checks/temp/code_report_results/Pylint_check.json --files '*.py' - | └ [Success] - | - └ [Success] - - 6. Processing code report results - | ==> Adding file /home/user/universum-ci-checks/artifacts/Static_analysis_report.json to artifacts... - | ==> Issues not found. - └ [Success] - - 7. Collecting artifacts - └ [Success] - - 8. Reporting build result - | ==> Here is the summarized build result: - | ==> 5. Executing build steps - | ==> 5.1. [ 1/2 ] Run script - Success - | ==> 5.2. [ 2/2 ] Pylint check - Success - | ==> 7. Collecting artifacts - Success - | ==> Nowhere to report. Skipping... - └ [Success] - - 9. Finalizing - | 9.1. Cleaning copied sources - | └ [Success] - | - └ [Success] - - ==> Universum 1.0.0 finished execution +.. collapsible:: + + .. code-block:: + :linenos: + :emphasize-lines: 2-17, 26-28, 45-48, 62-66 + + ==> Universum 1.0.0 started execution + 1. Preparing repository + | ==> Adding file /home/user/universum-ci-checks/artifacts/REPOSITORY_STATE.txt to artifacts... + | 1.1. Cloning repository + | | ==> Cloning 'https://github.com/YOUR-USERNAME/universum-test-project.git'... + | | ==> Cloning into '/home/user/universum-ci-checks/temp'... + | | ==> POST git-upload-pack (165 bytes) + | | ==> remote: Enumerating objects: 9, done. + | | ==> remote: Total 9 (delta 0), reused 6 (delta 0), pack-reused 0 + | | ==> Please note that default remote name is 'origin' + | └ [Success] + | + | 1.2. Checking out + | | ==> Checking out 'HEAD'... + | └ [Success] + | + └ [Success] + + 2. Processing project configs + | ==> Adding file /home/user/universum-ci-checks/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 3. Preprocessing artifact lists + └ [Success] + + 4. Reporting build start + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Executing build steps + | 5.1. [ 1/2 ] Run script + | | ==> Adding file /home/user/universum-ci-checks/artifacts/Run_script_log.txt to artifacts... + | | ==> Execution log is redirected to file + | | $ /usr/bin/{python} run.py pass + | └ [Success] + | + | 5.2. [ 2/2 ] Pylint check + | | ==> Adding file /home/user/universum-ci-checks/artifacts/Pylint_check_log.txt to artifacts... + | | ==> Execution log is redirected to file + | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file /home/user/universum-ci-checks/temp/code_report_results/Pylint_check.json --files '*.py' + | └ [Success] + | + └ [Success] + + 6. Processing code report results + | ==> Adding file /home/user/universum-ci-checks/artifacts/Static_analysis_report.json to artifacts... + | ==> Issues not found. + └ [Success] + + 7. Collecting artifacts + └ [Success] + + 8. Reporting build result + | ==> Here is the summarized build result: + | ==> 5. Executing build steps + | ==> 5.1. [ 1/2 ] Run script - Success + | ==> 5.2. [ 2/2 ] Pylint check - Success + | ==> 7. Collecting artifacts - Success + | ==> Nowhere to report. Skipping... + └ [Success] + + 9. Finalizing + | 9.1. Cleaning copied sources + | └ [Success] + | + └ [Success] + + ==> Universum 1.0.0 finished execution We will look at `reporting` closer a little later, and for now pay attention to ``Preparing repository``/``Finalizing`` blocks. As a CI system, `Univesrum` downloads sources from server, runs checks on them and then clears up. From 21c8d09ea99d2dc2568fd2f3ab61f1ae2d3e86a8 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Wed, 7 Apr 2021 16:57:55 +0300 Subject: [PATCH 03/16] wip(docs): typos --- doc/guide.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index e873dffa..bfc3f9f2 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -99,7 +99,7 @@ getting an output like this: .. collapsible:: - ..code-block:: + .. code-block:: ==> Universum 1.0.0 started execution ==> Cleaning artifacts... @@ -170,7 +170,7 @@ After this change, running ``{python} -m universum run`` should result in the fo .. collapsible:: - ..code-block:: + .. code-block:: ==> Universum 1.0.0 started execution ==> Cleaning artifacts... @@ -247,7 +247,7 @@ Running Universum with this config will produce the following output: .. collapsible:: - ..code-block:: + .. code-block:: ==> Universum 1.0.0 started execution ==> Cleaning artifacts... @@ -321,7 +321,7 @@ a ``{python} -m universum run -f Pylint`` command, we will get the following out .. collapsible:: - ..code-block:: + .. code-block:: ==> Universum 1.0.0 started execution ==> Cleaning artifacts... From 8f3d970cd26366aca56e2fa6628e291dd4f8e1ac Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Thu, 8 Apr 2021 17:46:53 +0300 Subject: [PATCH 04/16] wip(docs): finish the 'simple Jenkins job' section --- doc/guide.rst | 115 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 101 insertions(+), 14 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index bfc3f9f2..a751408d 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -14,6 +14,7 @@ GitHub application and Pylint analyzer. These are the steps to take: 8. :ref:`Run Universum in default mode ` 9. :ref:`Set up Jenkins server ` 10. :ref:`Create a Jenkins job ` +11. :ref:`Set up CI using Universum ` .. _guide#install: @@ -565,25 +566,30 @@ Detailed instruction with explanation of the steps can be found `in official Jen .. _guide#job: -Create a Jenkins job --------------------- +Create a simple Jenkins job +--------------------------- First let's create a simple post-commit check. On Jenkins main page click ``Create a job``, or simply go to http://localhost:8080/newJob. There enter a job name (for example we will use ``universum_postcommit``), select a job type (for example we will use ``Pipeline``) and proceed to project configuration. On configuration page find ``Build Triggers`` and check the ``GitHub hook trigger for GITScm polling`` checkbox. + +.. note:: + + For Git SCM to work automatically, PUSH notifications should be set up in your repository settings. + Please refer to the following `official guide `__ + on managing such triggers. + After that, go to ``Pipeline``, select ``Pipeline script`` and enter the following script:: - pipeline { + pipeline { agent any stages { stage ('Universum check') { steps { - git 'https://github.com/YOUR-USERNAME/universum-test-project.git' - ansiColor('xterm') { - sh("{python} -m universum --no-diff --vcs-type none --file-source-dir universum-test-project") - } + git branch: 'main', 'https://github.com/YOUR-USERNAME/universum-test-project.git' + sh("{python} -m universum run") } } } @@ -594,22 +600,103 @@ But, actually running this job will fail for now with the following error:: /usr/bin/{python}: No module named universum Which is expected, because we have not installed neither Universum, nor Git to the Jenkins node. -For now, let's do the following changes to pipeline:: +Also, our config uses Pylint, so let's do the following changes to pipeline:: - pipeline { + pipeline { agent any stages { stage ('Universum check') { steps { - sh("{pip} install -U universum") - git 'https://github.com/YOUR-USERNAME/universum-test-project.git' - ansiColor('xterm') { - sh("{python} -m universum --no-diff --vcs-type none --file-source-dir universum-test-project") - } + sh("{pip} install -U universum pylint") + git branch: 'main', 'https://github.com/YOUR-USERNAME/universum-test-project.git' + sh("{python} -m universum run") } } } } +Keeping Universum updated is generally a good idea, as critical bugs may be fixed in new releases. + +Though, now Univesrum does not look very pretty due to color codes. We recommend installing +`AnsiColor `__ Jenkins plugin for prettier output. +See `Jenkins official guide on plugin installation `__. +After installing the plugin and rebooting change pipeline to this:: + + pipeline { + agent any + options { + ansiColor('xterm') + } + stages { + stage ('Universum check') { + steps { + sh("{pip} install -U universum pylint") + git branch: 'main', 'https://github.com/YOUR-USERNAME/universum-test-project.git' + sh("{python} -m universum run") + } + } + } + } + +.. collapsible:: + :header: And the stage output should look like this + + .. code-block:: + + [Pipeline] { (Universum check) + [Pipeline] sh + + pip3.7 install -U universum + + Defaulting to user installation because normal site-packages is not writeable + Requirement already satisfied: universum + [Pipeline] git + The recommended git tool is: NONE + No credentials specified + > /usr/bin/git rev-parse --is-inside-work-tree # timeout=10 + + Fetching changes from the remote Git repository + + [Pipeline] sh + + python3.7 -m universum run + + ==> Universum 0.19.4 started execution + ==> Cleaning artifacts... + 1. Processing project configs + | ==> Adding file http://localhost:8080/job/universum_postcommit/3/artifact/artifacts/CONFIGS_DUMP.txt to artifacts... + └ [Success] + + 2. Preprocessing artifact lists + └ [Success] + + 3. Executing build steps + | 3.1. [ 1/2 ] Run script + | | $ /usr/bin/python3.7 run.py pass + | └ [Success] + | + | 3.2. [ 2/2 ] Pylint check + | | $ /usr/bin/python3.7 -m universum.analyzers.pylint --python-version 3.7 --result-file /var/jenkins_home/workspace/universum_postcommit/code_report_results/Pylint_check.json --files '*.py' + | └ [Success] + | + └ [Success] + + 4. Reporting build result + | ==> Here is the summarized build result: + | ==> 3. Executing build steps + | ==> 3.1. [ 1/2 ] Run script - Success + | ==> 3.2. [ 2/2 ] Pylint check - Success + | ==> Nowhere to report. Skipping... + └ [Success] + + 5. Collecting artifacts + └ [Success] + + ==> Universum 0.19.4 finished execution + [Pipeline] } + + +.. _guide#set-up-ci: + +Set up CI using Universum +------------------------- .. TBD From 1ff1e4e8bdb8472485d8f7e2a7801bb8ce254822 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Mon, 26 Apr 2021 15:35:53 +0300 Subject: [PATCH 05/16] wip --- doc/guide.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/guide.rst b/doc/guide.rst index a751408d..fd41485c 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -699,4 +699,16 @@ After installing the plugin and rebooting change pipeline to this:: Set up CI using Universum ------------------------- +Universum offers a lot of additional functionality, but to use it, we first have to let it know +about VCS we're using. First, let's change Jenkins GitHub plugin to +`Generic Webhook Trigger `__, so that it doesn't +download sources automatically before Universum even started. + +.. note:: + + This also can be, for example, used later, to cherry-pick some files, including Universum config itself, + from a different commit (e.g. in another branch). + + + .. TBD From 7e9bb1353341e3cca17928925ee33941bf8fa5bc Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Wed, 23 Jun 2021 18:13:49 +0300 Subject: [PATCH 06/16] fix(docs): various fixes --- doc/guide.rst | 64 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index fd41485c..7fe2d35c 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -54,7 +54,7 @@ For demonstration purposes let's create a project on GitHub. To do so, we'll nee Read more about creating repositories in `a detailed GitHub guide -`__ +`__. After creating a repo online, clone it locally:: @@ -62,7 +62,7 @@ After creating a repo online, clone it locally:: cd universum-test-project ls -a -The output of such command should be:: +The output of the last command should be:: . .. .git README.md @@ -85,11 +85,11 @@ That will create a new file ``.universum.py`` and print a command to use it:: The default :doc:`configuration file `, created by this command, looks like this:: - #!/usr/bin/env python3.7 + #!/usr/bin/env {python} from universum.configuration_support import Configuration - configs = Configuration([Step(name='Show directory contents', command=['ls', '-la']), + configs = Configuration([Step(name='Show directory contents', command=['ls', '-a']), Step(name='Print a line', command=['bash', '-c', 'echo Hello world'])]) if __name__ == '__main__': @@ -137,7 +137,7 @@ getting an output like this: ==> Universum 1.0.0 finished execution -Running this command will also produce a directory ``artifacts``, containing single file: ``CONFIGS_DUMP.txt``. +Running this command will also produce a directory ``artifacts``, containing a single file: ``CONFIGS_DUMP.txt``. The reason for this file existance will be explained in the next paragraph. @@ -176,7 +176,7 @@ After this change, running ``{python} -m universum run`` should result in the fo ==> Universum 1.0.0 started execution ==> Cleaning artifacts... 1. Processing project configs - | ==> Adding file/home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... + | ==> Adding file /home/user/universum-test-project/artifacts/CONFIGS_DUMP.txt to artifacts... └ [Success] 2. Preprocessing artifact lists @@ -184,7 +184,7 @@ After this change, running ``{python} -m universum run`` should result in the fo 3. Executing build steps | 3.1. [ 1/1 ] Run script - | | $ /home/user/work/run.sh pass + | | $ /home/user/universum-test-project/run.sh pass | | Script succeeded | └ [Success] | @@ -215,6 +215,8 @@ Add static analyzer Say, instead of writing a script in `bash` we used `python`, and have the following script ``run.py``:: + #!/usr/bin/env {python} + import sys if len(sys.argv) < 2: @@ -228,7 +230,7 @@ Say, instead of writing a script in `bash` we used `python`, and have the follow To use this script, we'd have to modify ``configs`` to this:: - configs = Configuration([Step(name='Run script', command=['python', 'run.py', 'pass'])]) + configs = Configuration([Step(name='Run script', command=['{python}', 'run.py', 'pass'])]) which will get the same result as the previous one. @@ -239,8 +241,7 @@ corresponds to PEP-8 from the very beginning. We might install `Pylint Universum 1.0.0 finished execution Which means we already have some code style issues in the project sources. Open the ``Pylint_check.json`` file -with code style check results:: +in ``code_report_results`` directory to see the code style check results:: [ { @@ -301,13 +303,18 @@ with code style check results:: } ] -Let's presume we do not indend to add docstrings to every module. Then this check failure can be fixed by simply +Let's presume we do not intend to add docstrings to every module. Then this check failure can be fixed by simply putting a ``pylintrc`` file in project root with following content:: [MESSAGES CONTROL] disable = missing-docstring -Leading to `Universum` successful execution. +That should lead to `Universum` successful execution. + +.. note:: + + Current Pylint docs do not have a separate guide on ``rcfile``, but a sample one can be generated using + ``pylint --generate-rcfile`` command. .. _guide#filter: @@ -335,7 +342,7 @@ a ``{python} -m universum run -f Pylint`` command, we will get the following out 3. Executing build steps | 3.1. [ 1/1 ] Pylint check - | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file '${CODE_REPORT_FILE}' --files '*.py' + | | $ /usr/bin/{python} -m universum.analyzers.pylint --result-file /home/user/universum-test-project/code_report_results/Pylint_check.json --files '*.py' | └ [Success] | └ [Success] @@ -410,7 +417,7 @@ Now let's leave the project root directory, as we no longer need local sources, cd .. mkdir universum-ci-checks - python -m universum --no-diff --vcs-type git --git-repo https://github.com/YOUR-USERNAME/universum-test-project.git + {python} -m universum --no-diff --vcs-type git --git-repo https://github.com/YOUR-USERNAME/universum-test-project.git We will now get a log, very similar to previous one, but with some additional sections: @@ -459,7 +466,7 @@ We will now get a log, very similar to previous one, but with some additional se | 5.2. [ 2/2 ] Pylint check | | ==> Adding file /home/user/universum-ci-checks/artifacts/Pylint_check_log.txt to artifacts... | | ==> Execution log is redirected to file - | | $ /usr/bin/{python} -m universum.analyzers.pylint --python-version 3.7 --result-file /home/user/universum-ci-checks/temp/code_report_results/Pylint_check.json --files '*.py' + | | $ /usr/bin/{python} -m universum.analyzers.pylint --result-file /home/user/universum-ci-checks/temp/code_report_results/Pylint_check.json --files '*.py' | └ [Success] | └ [Success] @@ -499,11 +506,11 @@ full step list; but now it contains a lot of new files: * Pylint_check_log.txt * Static_analysis_report.json -First one describes what sources were used for this exact build: repo, fetch target (e.g. `HEAD` or commit hash), +The first one describes what sources were used for this exact build: repo, fetch target (e.g. `HEAD` or commit hash), list of downloaded files. In case of other VCS types (such as Perforce or local folder) the contents of this file will vary; the purpose of this file is repeatability of the builds. -Next two files are step execution logs. When project configuration includes many different steps, each containing +The next two files are step execution logs. When the project configuration includes many different steps, each containing a long execution log, reading the whole `Universum` log in console may be not that user-friendly. That's why when executing in console, by default the logs are written to files. This befaviour may be changed via ``--out`` `command-line parameter `__. @@ -563,6 +570,11 @@ Go to http://localhost:8080 and unlock Jenkins, follow the instruction on a titl Detailed instruction with explanation of the steps can be found `in official Jenkins installation guide `__. +.. note:: + + Please pay attention, that to let you server to be visible to GitHub (for webhook triggers), its port + should be exposed to the Internet. Please use router settings or any other suitable means for this. + .. _guide#job: @@ -645,7 +657,7 @@ After installing the plugin and rebooting change pipeline to this:: [Pipeline] { (Universum check) [Pipeline] sh - + pip3.7 install -U universum + + {pip} install -U universum Defaulting to user installation because normal site-packages is not writeable Requirement already satisfied: universum @@ -657,12 +669,12 @@ After installing the plugin and rebooting change pipeline to this:: Fetching changes from the remote Git repository [Pipeline] sh - + python3.7 -m universum run + + {python} -m universum run - ==> Universum 0.19.4 started execution + ==> Universum 1.0.0 started execution ==> Cleaning artifacts... 1. Processing project configs - | ==> Adding file http://localhost:8080/job/universum_postcommit/3/artifact/artifacts/CONFIGS_DUMP.txt to artifacts... + | ==> Adding file http://localhost:8080/job/universum_postcommit/1/artifact/artifacts/CONFIGS_DUMP.txt to artifacts... └ [Success] 2. Preprocessing artifact lists @@ -670,11 +682,11 @@ After installing the plugin and rebooting change pipeline to this:: 3. Executing build steps | 3.1. [ 1/2 ] Run script - | | $ /usr/bin/python3.7 run.py pass + | | $ /usr/bin/{python} run.py pass | └ [Success] | | 3.2. [ 2/2 ] Pylint check - | | $ /usr/bin/python3.7 -m universum.analyzers.pylint --python-version 3.7 --result-file /var/jenkins_home/workspace/universum_postcommit/code_report_results/Pylint_check.json --files '*.py' + | | $ /usr/bin/{python} -m universum.analyzers.pylint --result-file /var/jenkins_home/workspace/universum_postcommit/code_report_results/Pylint_check.json --files '*.py' | └ [Success] | └ [Success] @@ -690,7 +702,7 @@ After installing the plugin and rebooting change pipeline to this:: 5. Collecting artifacts └ [Success] - ==> Universum 0.19.4 finished execution + ==> Universum 1.0.0 finished execution [Pipeline] } From 400c8c4b6ed64ef9ddc551c8d310c00afb955523 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Fri, 25 Jun 2021 14:43:44 +0300 Subject: [PATCH 07/16] update(docs): add paragraph on universum on jenkins --- doc/guide.rst | 82 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index 7fe2d35c..ade62404 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -14,7 +14,8 @@ GitHub application and Pylint analyzer. These are the steps to take: 8. :ref:`Run Universum in default mode ` 9. :ref:`Set up Jenkins server ` 10. :ref:`Create a Jenkins job ` -11. :ref:`Set up CI using Universum ` +11. :ref:`Set up the simplest CI using Universum ` +12. :ref:`Make repo state more precise ` .. _guide#install: @@ -575,6 +576,10 @@ Detailed instruction with explanation of the steps can be found `in official Jen Please pay attention, that to let you server to be visible to GitHub (for webhook triggers), its port should be exposed to the Internet. Please use router settings or any other suitable means for this. +Now that we have server URL and an exposed port, we can set up `a simple PUSH notification webhook +`__ to know about sources +updates. + .. _guide#job: @@ -589,7 +594,7 @@ On configuration page find ``Build Triggers`` and check the ``GitHub hook trigge .. note:: - For Git SCM to work automatically, PUSH notifications should be set up in your repository settings. + For Git SCM to work automatically, PUSH notifications should be set up right in your repository settings. Please refer to the following `official guide `__ on managing such triggers. @@ -708,8 +713,8 @@ After installing the plugin and rebooting change pipeline to this:: .. _guide#set-up-ci: -Set up CI using Universum -------------------------- +Set up the simplest CI using Universum +-------------------------------------- Universum offers a lot of additional functionality, but to use it, we first have to let it know about VCS we're using. First, let's change Jenkins GitHub plugin to @@ -721,6 +726,75 @@ download sources automatically before Universum even started. This also can be, for example, used later, to cherry-pick some files, including Universum config itself, from a different commit (e.g. in another branch). +In job configuration go to ``Build Triggers``, uncheck the ``GitHub hook trigger for GITScm polling`` +and instead check the ``Generic Webhook Trigger``. + +Running `Universum` in default mode will require all parameters we already `tried locally `. +So first, let's change job pipeline accordingly:: + + pipeline { + agent any + options { + ansiColor('xterm') + } + stages { + stage ('Universum check') { + steps { + sh("{pip} install -U universum[git] pylint") + sh("{python} -m universum --no-diff --vcs-type git --git-repo https://github.com/YOUR-USERNAME/universum-test-project.git") + } + } + } + } + +Even though first launch might be successful, further job reruns will fail with the following error:: + + ==> Universum 1.0.0 started execution + 1. Preparing repository + | Error: File 'REPOSITORY_STATE.txt' already exists in artifact directory. + | Possible reason of this error: previous build artifacts are not cleaned + └ [Failed] + + 2. Finalizing + └ [Success] + + ==> Universum 1.0.0 finished execution + +The reason for such error is that CI build is meant to be run in an empty clean directory to make sure +no leftovers from previous builds could affect the result. An example of such contamination can be some build +artifacts, created with previous sources and not created in most current run at all: in this scenario the outdated +files might be considered created successfully. + +So, to avoid this problem, we can install `Workspace Cleanup plugin ` to +Jenkins, and modify pipeline to clean working directory before execution:: + + pipeline { + agent any + options { + ansiColor('xterm') + } + stages { + stage ('Clean workspace') { + steps { + cleanWs() + } + } + stage ('Universum check') { + steps { + sh("{pip} install -U universum[git] pylint") + sh("{python} -m universum --no-diff --vcs-type git --git-repo https://github.com/YOUR-USERNAME/universum-test-project.git") + } + } + } + } + +So, for now this job will start every time we push a new commit to the Git repository and check the latest +repository state. Let's apply to this job some useful features. + + +.. _guide#set-repo-state: +Make repo state more precise +---------------------------- .. TBD From cf8e131cc955ff13c33af93096fe9230df0653d5 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Fri, 25 Jun 2021 17:32:46 +0300 Subject: [PATCH 08/16] update(docs): add paragraph on vcs params --- doc/guide.rst | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/doc/guide.rst b/doc/guide.rst index ade62404..43dabb22 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -16,6 +16,7 @@ GitHub application and Pylint analyzer. These are the steps to take: 10. :ref:`Create a Jenkins job ` 11. :ref:`Set up the simplest CI using Universum ` 12. :ref:`Make repo state more precise ` +13. :ref:`Add artifacts to the build ` .. _guide#install: @@ -727,7 +728,8 @@ download sources automatically before Universum even started. from a different commit (e.g. in another branch). In job configuration go to ``Build Triggers``, uncheck the ``GitHub hook trigger for GITScm polling`` -and instead check the ``Generic Webhook Trigger``. +and instead check the ``Generic Webhook Trigger``. In revealed settings for Generic webhook we need to find +``Token`` parameter and add a triggering token; otherwise we'd have to pass user and password to webhook. Running `Universum` in default mode will require all parameters we already `tried locally `. So first, let's change job pipeline accordingly:: @@ -797,4 +799,85 @@ repository state. Let's apply to this job some useful features. Make repo state more precise ---------------------------- +Let's presume we want to check not the *latest* repository state, but every pushed commit separately. +Every webhook notification includes a payload with a lot of useful information. Let's investigate its contents +and decide what of them we might use. + +To see a payload, sent to Jenkins by GitHub, first push a commit to the repo. Then open the project settings, +``Webhooks`` page. There find a webhook you created earlier and click the ``Edit`` button. Go to the end of the +page to find ``Recent Deliveries`` and click on the latest one. There you will find the headers and request body, +sent and received by GitHub. + +To check the exact commit, we will need its hash, that is referenced in payload as ``after``. We might also pay +attention to ``repository.url`` to take the value from payload instead of hardcoding it into pipeline. +But, to use this parameters, we need to extract them from payload. + +So, on Jenkins go to job configuration, ``Build Triggers``, ``Generic Webhook Trigger`` and click on ``Add`` button +in ``Post content parameters`` (actually, click it twice, for we will add two parameters). Parameter usage is +described in `plugin description `__. + +1. First, we will add parameter named ``GIT_REPO``, with value ``$.repository.url``, where ``$`` refers to payload, + and ``.repository.url`` is a 'JSONPath' +2. Then, add parameter named ``GIT_CHECKOUT_ID`` with value ``$.after`` to refer to new commit hash + +These parameters will become environment variables for the upcoming builds and without further effort will be +`recognized `__ by Universum. Therefore, there's no need to pass ``--git-repo`` directly:: + + pipeline { + agent any + options { + ansiColor('xterm') + } + stages { + stage ('Clean workspace') { + steps { + cleanWs() + } + } + stage ('Universum check') { + steps { + sh("{pip} install -U universum[git] pylint") + sh("{python} -m universum --no-diff --vcs-type git") + } + } + } + } + +This will produce a build log, very similar to those received in previous configuration; main difference will be +``Preparing repository`` part: + +.. collapsible:: + + .. code-block:: + :emphasize-lines: 12-14 + + 1. Preparing repository + | ==> Adding file http://localhost:8080/job/universum_postcommit/58/artifact/artifacts/REPOSITORY_STATE.txt to artifacts... + | 1.1. Cloning repository + | | ==> Cloning 'https://github.com/YOUR-USERNAME/universum-test-project'... + | | ==> Cloning into '/var/jenkins_home/workspace/universum_postcommit/temp'... + | | ==> POST git-upload-pack (165 bytes) + | | ==> remote: Enumerating objects: 34, done. + | | ==> remote: Total 34 (delta 10), reused 7 (delta 0), pack-reused 0 + | | ==> Please note that default remote name is 'origin' + | └ [Success] + | + | 1.2. Checking out + | | ==> Checking out '4411f3378a3c82cfb9b95487afd77fe6a7a5d472'... + | └ [Success] + | + | 1.3. Registering file diff for API + | └ [Success] + | + └ [Success] + +Also, the contents of ``REPOSITORY_STATE.txt`` file will vary, but for now we won't be able to see that. + + +.. _guide#add-artifacts: + +Add artifacts to the build +-------------------------- + + .. TBD From 91cbb208e042cb04f2bf862aecbc0bb1dfa67ce9 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Thu, 8 Jul 2021 19:55:51 +0300 Subject: [PATCH 09/16] update(docs): add a paragragh on artifacts to the guide --- doc/guide.rst | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/doc/guide.rst b/doc/guide.rst index 43dabb22..57d43fa8 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -17,6 +17,7 @@ GitHub application and Pylint analyzer. These are the steps to take: 11. :ref:`Set up the simplest CI using Universum ` 12. :ref:`Make repo state more precise ` 13. :ref:`Add artifacts to the build ` +14. :ref:`Create a pre-commit job ` .. _guide#install: @@ -879,5 +880,94 @@ Also, the contents of ``REPOSITORY_STATE.txt`` file will vary, but for now we wo Add artifacts to the build -------------------------- +So, now we have this directory, defined with ``--artifact-dir`` +`command line parameter `__, that already contains some useful data about the +recent build. To be able to see it on Jenkins, we will mention it in Jenkins pipeline like this:: + + pipeline { + agent any + options { + ansiColor('xterm') + } + stages { + stage ('Clean workspace') { + steps { + cleanWs() + } + } + stage ('Universum check') { + steps { + sh("{pip} install -U universum[git] pylint") + sh("{python} -m universum --no-diff --vcs-type git") + archiveArtifacts artifacts: 'artifacts/', followSymlinks: false + } + } + } + } + +After this, all links in log (like that one leading to ``REPOSITORY_STATE.txt``) will start to work; +and all the artifacts will be accessible from a build page on Jenkins. Later on, when we will turn on the +``--report-to-review`` `command line option `__, we will be able to use ``report_artifacts`` +key of :class:`~universum.configuration_support.Step`, that will result in link to a chosen file to be posted in +a comment to checked review. + +There two kinds of artifacts, expected by `Universum` from a build: + +1. Usual artifacts, that are results of step execution. Absence of such artifacts is a symptom of unsuccessful + execution, and therefore is considered a failure +2. Special artifacts to be reported to a code review, such as static analysis reports. Absence of + such artifacts may mean that there simply is nothing to report, and therefore is not considered a failure + +If an artifact is to be reported to code review, but is also a mandatory outcome of a build, it should be noted +in configurations file in both ``artifacts`` and ``report_artifacts`` key. + +So, let's presume we want our build checks to generate a mandatory build artifacts. As an example, let's generate +a log file in our build script ``run.py``:: + + #!/usr/bin/env python + + import sys + + with open("execution.log", "w+") as new_file: + new_file.write("Here's what a script accepted from command line:\n" + str(sys.argv)) + + if len(sys.argv) < 2: + print("Unknown outcome") + sys.exit(2) + if sys.argv[1] == "pass": + print("Script succeeded") + sys.exit(0) + print("Script failed") + sys.exit(1) + +After that, let's inform `Universum` we expect this file to be generated as an outcome of a build check:: + + #!/usr/bin/env python + + from universum.configuration_support import Configuration, Step + + configs = Configuration([ + Step(name='Run script', command=['python3.7', 'run.py', 'pass'], artifacts="execution.log"), + dict(name="Pylint check", code_report=True, command=[ + "python3.7", "-m", "universum.analyzers.pylint", "--result-file", "${CODE_REPORT_FILE}", "--files", "*.py" + ]) + ]) + + if __name__ == '__main__': + print(configs.dump()) + +Actually, if we expect more than one log file to be generated, we can pass ``artifacts="*.log"`` to collect +all of them. But, be aware: if any of this log files are committed to the repo, the build will fail, as the file, +expected to be created by step execution, is already present in project directory. If, however, such file is to be +generated anew instead of the already committed one (this is a common case for builds, utilizing +:ref:`submit ` `Universum` mode), there's another helpful +:class:`~universum.configuration_support.Step` key: ``artifact_prebuild_clean=True``. + + +.. _guide#pre-commit: + +Create a pre-commit job +----------------------- + .. TBD From 31cf484aa36e86e960282d25cd4847243bb8a705 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Thu, 5 Aug 2021 14:11:15 +0300 Subject: [PATCH 10/16] update(docs): update Jenkins Dockerfile according to official guide --- doc/guide.rst | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index 57d43fa8..3133c8ab 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -18,6 +18,7 @@ GitHub application and Pylint analyzer. These are the steps to take: 12. :ref:`Make repo state more precise ` 13. :ref:`Add artifacts to the build ` 14. :ref:`Create a pre-commit job ` +15. :ref:`Register a GitHub Application ` .. _guide#install: @@ -531,7 +532,7 @@ Now that CI builds are working locally, let's set up a real automated CI. Create a ``Dockerfile`` with following content:: - FROM jenkins/jenkins:2.263.1-lts-slim + FROM jenkins/jenkins:2.289.3-lts-jdk11 USER root RUN apt-get update && apt-get install -y apt-transport-https \ ca-certificates curl gnupg2 \ @@ -542,10 +543,8 @@ Create a ``Dockerfile`` with following content:: "deb [arch=amd64] https://download.docker.com/linux/debian \ $(lsb_release -cs) stable" RUN apt-get update && apt-get install -y docker-ce-cli - RUN apt-get update && apt-get install -y git {python} python3-pip - RUN {python} -m pip install -U pip USER jenkins - RUN jenkins-plugin-cli --plugins blueocean:1.24.3 + RUN jenkins-plugin-cli --plugins "blueocean:1.24.7 docker-workflow:1.26" Execute the following commands:: @@ -969,5 +968,27 @@ generated anew instead of the already committed one (this is a common case for b Create a pre-commit job ----------------------- +So, let's presume we want to check commit before merging it into `main` branch (or any other). To do so, +we need almost the same information as for the post-commit: commit hash to checkout and a webhook notification +to know the commit was pushed to server and requires to be checked. + +Let's say we don't want to check any commit, pushed to the repo; for the pre-commit we're only interested in +those pushed in scope of `pull requests` (PRs). To only react to those, go to project `Settings`, `Webhooks`, +find the webhook created earlier and click 'Edit'. There find the 'Which events would you like to trigger this webhook?' +radio-button and switch to 'Let me select individual events'. + +A large list of possible event should appear beneath. Find and uncheck the 'Push' event, and instead check the +'Pull requests'. + + +.. _guide#github-app: + +Register a GitHub Application +----------------------------- + +For the next step (creating pre-commit and reporting results to GitHub) we will need an active `GitHub Application +`__. + + .. TBD From 1de5ad7f3b965d1ea67c8f64080be2d81357a92e Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Thu, 5 Aug 2021 15:04:08 +0300 Subject: [PATCH 11/16] update(docs): update notes on Jenkins Dockerfile and preinstalled Python --- doc/guide.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index 3133c8ab..f6ddf327 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -546,6 +546,9 @@ Create a ``Dockerfile`` with following content:: USER jenkins RUN jenkins-plugin-cli --plugins "blueocean:1.24.7 docker-workflow:1.26" +If this results in outdated Jenkins server later, please consult `official Jenkins installation guide +`__. + Execute the following commands:: docker network create jenkins @@ -564,14 +567,18 @@ Execute the following commands:: --volume jenkins-docker-certs:/certs/client:ro \ myjenkins-blueocean:1.1 +Please note that depending on exact ``Dockerfile`` contents resulting server may or may not contain Python and Pip. +If not, ether add installation to ``Dockerfile`` or execute the following after starting the container:: + + docker exec -u root jenkins-blueocean apt install -y {python} + docker exec -u root jenkins-blueocean apt install -y python3-pip + docker exec -u root jenkins-blueocean {python} -m pip install -U pip + Go to http://localhost:8080 and unlock Jenkins, follow the instruction on a title page: 1. execute ``docker exec jenkins-blueocean cat /var/jenkins_home/secrets/initialAdminPassword`` 2. input the required key and follow further wizard instructions -Detailed instruction with explanation of the steps can be found `in official Jenkins installation guide -`__. - .. note:: Please pay attention, that to let you server to be visible to GitHub (for webhook triggers), its port @@ -986,7 +993,7 @@ A large list of possible event should appear beneath. Find and uncheck the 'Push Register a GitHub Application ----------------------------- -For the next step (creating pre-commit and reporting results to GitHub) we will need an active `GitHub Application +For the next step (reporting results to GitHub) we will need an active `GitHub Application `__. From 50de3912dfa5830157939e1b5014bf0d07e211c6 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Thu, 5 Aug 2021 15:31:00 +0300 Subject: [PATCH 12/16] update(docs): add a simple pre-commit paragraph --- doc/guide.rst | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/doc/guide.rst b/doc/guide.rst index f6ddf327..a6592c26 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -980,12 +980,22 @@ we need almost the same information as for the post-commit: commit hash to check to know the commit was pushed to server and requires to be checked. Let's say we don't want to check any commit, pushed to the repo; for the pre-commit we're only interested in -those pushed in scope of `pull requests` (PRs). To only react to those, go to project `Settings`, `Webhooks`, -find the webhook created earlier and click 'Edit'. There find the 'Which events would you like to trigger this webhook?' -radio-button and switch to 'Let me select individual events'. - -A large list of possible event should appear beneath. Find and uncheck the 'Push' event, and instead check the -'Pull requests'. +those pushed in scope of `pull requests` (PRs). To only react to those, go to project ``Settings``, ``Webhooks``, +find the webhook created earlier and click ``Edit``. There find the ``Which events would you like to trigger this +webhook?`` radio-button and switch to ``Let me select individual events``. + +A large list of possible events should appear beneath. Find and uncheck the ``Push`` event, and instead check the +``Pull requests``. After that create a new PR (requires additional branch, can be performed by GitHub automatically +when redacting single file). This should trigger the created post-commit configuration (as pass the new info to the +old `Generic Webhook Trigger`), but the build will most likely fail due to payload content differences. + +So, to see the new payload, once again in webhook settings go to ``Recent Deliveries`` and find the latest payload. +As you can see, now ``repository.url`` contains ``https://api.github.com/repos/YOUR-USERNAME/universum-test-project``, +which might not be available to anonymous cloning. For now we can replace it with ``repository.html_url``, that +still contains old familiar ``https://github.com/YOUR-USERNAME/universum-test-project``. + +But why ``https://api.github.com/``, and how to use this API to report the check status back to GitHub? To get to +this, we will need a GitHub Application as a unified way of communication between CI system and GitHub. .. _guide#github-app: From 4958a3f8f95c612cd46a5a8c7e08600a0bc5af99 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Thu, 5 Aug 2021 16:30:03 +0300 Subject: [PATCH 13/16] update(docs): add a GitHub App registration comments --- doc/guide.rst | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/doc/guide.rst b/doc/guide.rst index a6592c26..0d834297 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -19,6 +19,7 @@ GitHub application and Pylint analyzer. These are the steps to take: 13. :ref:`Add artifacts to the build ` 14. :ref:`Create a pre-commit job ` 15. :ref:`Register a GitHub Application ` +16. :ref:`Set up pre-commit job with reports ` .. _guide#install: @@ -1004,8 +1005,33 @@ Register a GitHub Application ----------------------------- For the next step (reporting results to GitHub) we will need an active `GitHub Application -`__. +`__. To `register it +`__, +go to you personal account ``Settings``, find ``Developer settings``, and the first page available should be +``GitHub Apps``. Click the ``New GitHub App`` button. +Enter App name (e.g. ``Universum Test App``, but make sure it's unique) and `Homepage URL` (as it's going to be +Jenkins-based, you may simply use Jenkins home URL). Somewhere later find the ``Webhook URL`` and enter the same URL +we used for webhook: ``http://jenkins.url/generic-webhook-trigger/invoke?token=TOKEN``. As the app will receive +its own payloads, you will no longer require the old webhook itself. It can be deactivated or deleted from now on. + +Now go down to ``Repository permissions``. To perform checks and report results, we will need the ``Checks`` set to +`Read & write` access. As for now we are only interested in `Checks`, in ``Subscribe to events`` we also need +to check the ``Check suite`` and ``Check run``. + +This should be enough to create the test app. After successful creation, you will be redirected to Application +personal page. On ``General`` page scroll down to ``Private keys`` and click the ``Generate a private key`` button. +The key will be used later for the App authorization in GitHub, so make sure to save it. + +Now all you need is to install the Application to the repo. Go to ``Install App`` page; choose your account; +select required repo; click ``Install``. + + +.. _guide#report: + +Set up pre-commit job with reports +---------------------------------- .. TBD From 0bb2b8119944a236ba09f3cfe1576cf7968caed0 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Fri, 6 Aug 2021 17:12:12 +0300 Subject: [PATCH 14/16] wip(docs): add a pre-commit creation paragraph --- doc/guide.rst | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/doc/guide.rst b/doc/guide.rst index 0d834297..5c2640da 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -1033,5 +1033,111 @@ select required repo; click ``Install``. Set up pre-commit job with reports ---------------------------------- +Actually, we do have a :ref:`separate manual `, explaining how +`Universum GitHub Application` works and how to apply it. + +First thing not very much explained there is working with ``credentials`` to get the `KEY_FILE`. We recommend +using the `Credentials Jenkins plugin `__, that is most likely already +pre-installed in your Jenkins instance, to store sensitive information, such as a private key. + +On Jenkins, go to ``Manage Jenkins`` and ``Manage Credentials``. Find ``Stores scoped to Jenkins`` and select +``Jenkins``, then ``Global credentials (unrestricted)``. There you should be prompted to add new credentials. + +In a dropdown list select ``GitHub App``. Enter ``universum-test-app`` as an ID and ``Universum Test App`` as +a dscription. For `App ID` check your App page on GitHub (find it by going to ``Settings``, +``Developer settings``, ``GitHub Apps``). Into the ``Key`` enter the contents of the file we acquired after +:ref:`registering GitHub App ` (make sure to strip the ``-----BEGIN/END RSA PRIVATE KEY-----`` +lines). + +Let's turn our existing Jenkins job, ``universum_postcommit``, into a webhook-handling job that uses the newly +created GitHub App, and then create another one, not triggered by any webhooks directly, to simply perform the +checks when need. + +First let's create that simple checking job. Follow the already familiar ``New item``, ``Pipeline`` scenario, +and enter the name (e.g. ``universum_check``). In ``General`` page of settings check the ``This project is +parameterized`` field and add following empty string params to be passed from webhook processor: + + * GIT_REPO + * GIT_REFSPEC + * GIT_CHECKOUT_ID + * GITHUB_INSTALLATION_ID + * GITHUB_CHECK_ID + +All these parameters might be helpful when performing the check and are automatically extracted from payload +by :doc:`GitHub Handler `. + +Then we need to extract the `Credentials` parameters to this job, so add a ``Credentials Parameter`` (let's name it +``GITHUB_APP``), where the credentials type will be ``GitHub App``, and default value set to previously created +``Universum Test App``. + +Then in ``Build Triggers`` check the ``Trigger builds remotely (e.g., from scripts)`` and add the token (e.g. +``GITHUB``). + +Finally add the actual pipeline:: + + pipeline { + agent any + options { + ansiColor('xterm') + } + stages { + stage ('Clean workspace') { + steps { + cleanWs() + } + } + stage ('Universum check') { + steps { + withCredentials([usernamePassword(credentialsId: 'GITHUB_APP', + usernameVariable: 'GITHUB_APP_ID', + passwordVariable: 'GITHUB_PRIVATE_KEY')]) { + sh("{pip} install -U universum[github] pylint") + sh("{python} -m universum --no-diff -vt github --report-to-review -rst -rsu -rof") + archiveArtifacts artifacts: 'artifacts/', followSymlinks: false + } + } + } + } + } + +The contents of the pipeline might now look not very familiar, and will be explained after setting up the handler. + +Let's transform the existing ``universum_postcommit`` into ``github_webhook_handler``, as it already has conveniently +set up triggers and payload processing. Change the name and proceed to variables declared by ``Generic Webhook +Trigger``. As for the payload, we will only need one parameter now, containing the whole payload contents, to be +passed to handler and parsed. So in ``Post content parameters`` leave one with the following contents: + +* `Variable`: ``GITHUB_PAYLOAD`` +* `Expression`: ``$`` + +But for the handler to work properly we will require more metadata, so we also need to add a ``Header parameter`` +with ``Request header`` set to ``x-github-event``. This is a `GitHub event` header sent by GitHub along with the +payload itself. + +Also, now this job also requires predefined parameters, so in ``General`` check the ``This project is parameterized`` +and add the very same ``GITHUB_APP`` credentials parameter, as described above. + +Now, as for the pipeline, change it to the following:: + + + pipeline { + agent any + options { + ansiColor('xterm') + } + stages { + stage ('Run GitHub Handler') { + steps { + withCredentials([usernamePassword(credentialsId: 'GITHUB_APP', + usernameVariable: 'GITHUB_APP_ID', + passwordVariable: 'GITHUB_PRIVATE_KEY')]) { + sh("{pip} install -U universum[github]") + sh("{python} -m universum github-handler -e ${x_github_event}") + } + } + } + } + } + .. TBD From 945d110307a021ac5a920a1d0d71a582a139dde3 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Fri, 6 Aug 2021 17:16:04 +0300 Subject: [PATCH 15/16] fix(docs): typo --- doc/guide.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guide.rst b/doc/guide.rst index 5c2640da..4e3da45a 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -1132,7 +1132,7 @@ Now, as for the pipeline, change it to the following:: usernameVariable: 'GITHUB_APP_ID', passwordVariable: 'GITHUB_PRIVATE_KEY')]) { sh("{pip} install -U universum[github]") - sh("{python} -m universum github-handler -e ${x_github_event}") + sh("{python} -m universum github-handler -e \${x_github_event}") } } } From ff1498222d4a247ea262dba722670e183ffd2490 Mon Sep 17 00:00:00 2001 From: k-dovgan Date: Mon, 9 Aug 2021 18:16:41 +0300 Subject: [PATCH 16/16] update(docs): fix working with credentials; fix chapter splitting NB! Current recipe results in handler 'TypeError'; needs more investigation --- doc/github_handler.rst | 5 +++ doc/guide.rst | 72 ++++++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/doc/github_handler.rst b/doc/github_handler.rst index f637f3cb..521b4bcb 100644 --- a/doc/github_handler.rst +++ b/doc/github_handler.rst @@ -100,6 +100,11 @@ The list of GitHub Handler parameters can be found :ref:`here ` 13. :ref:`Add artifacts to the build ` 14. :ref:`Create a pre-commit job ` -15. :ref:`Register a GitHub Application ` -16. :ref:`Set up pre-commit job with reports ` +15. :ref:`Set up a GitHub App checks ` +16. :ref:`Turn on pre-commit checks reporting ` .. _guide#install: @@ -1001,12 +1001,14 @@ this, we will need a GitHub Application as a unified way of communication betwee .. _guide#github-app: -Register a GitHub Application ------------------------------ +Set up a GitHub App checks +-------------------------- + +Register a GitHub App +~~~~~~~~~~~~~~~~~~~~~ -For the next step (reporting results to GitHub) we will need an active `GitHub Application -`__. To `register it -`__. +To `register it `__, go to you personal account ``Settings``, find ``Developer settings``, and the first page available should be ``GitHub Apps``. Click the ``New GitHub App`` button. @@ -1028,17 +1030,15 @@ Now all you need is to install the Application to the repo. Go to ``Install App` select required repo; click ``Install``. -.. _guide#report: - -Set up pre-commit job with reports ----------------------------------- +Set up Jenkins jobs to work with the GitHub App +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Actually, we do have a :ref:`separate manual `, explaining how -`Universum GitHub Application` works and how to apply it. +Actually, we do have a :ref:`separate manual `, explaining how `Universum GitHub Application` +works and how to apply it. Let's focus on those things not payed enough attention there. -First thing not very much explained there is working with ``credentials`` to get the `KEY_FILE`. We recommend +First thing not very much explained is working with ``credentials`` to get the `KEY_FILE`. We recommend using the `Credentials Jenkins plugin `__, that is most likely already -pre-installed in your Jenkins instance, to store sensitive information, such as a private key. +pre-installed in the Jenkins instance, to store sensitive information such as a private key. On Jenkins, go to ``Manage Jenkins`` and ``Manage Credentials``. Find ``Stores scoped to Jenkins`` and select ``Jenkins``, then ``Global credentials (unrestricted)``. There you should be prompted to add new credentials. @@ -1049,9 +1049,11 @@ a dscription. For `App ID` check your App page on GitHub (find it by going to `` :ref:`registering GitHub App ` (make sure to strip the ``-----BEGIN/END RSA PRIVATE KEY-----`` lines). -Let's turn our existing Jenkins job, ``universum_postcommit``, into a webhook-handling job that uses the newly -created GitHub App, and then create another one, not triggered by any webhooks directly, to simply perform the -checks when need. +Now, for more convenience we are going to split existing ``universum_postcommit`` job into two different jobs: + + * the one triggered by incoming webhooks that :doc:`runs the newly created GitHub App ` + to process the payloads + * the one that performs familiar `Universum` checks given the parsed parameters when needed First let's create that simple checking job. Follow the already familiar ``New item``, ``Pipeline`` scenario, and enter the name (e.g. ``universum_check``). In ``General`` page of settings check the ``This project is @@ -1064,16 +1066,12 @@ parameterized`` field and add following empty string params to be passed from we * GITHUB_CHECK_ID All these parameters might be helpful when performing the check and are automatically extracted from payload -by :doc:`GitHub Handler `. - -Then we need to extract the `Credentials` parameters to this job, so add a ``Credentials Parameter`` (let's name it -``GITHUB_APP``), where the credentials type will be ``GitHub App``, and default value set to previously created -``Universum Test App``. +by :doc:`GitHub Handler `. Note how they not only include `Git` params, but also several `GitHub` ones. Then in ``Build Triggers`` check the ``Trigger builds remotely (e.g., from scripts)`` and add the token (e.g. ``GITHUB``). -Finally add the actual pipeline:: +Finally add the actual pipeline, extracting the previously added credentials into environment variables:: pipeline { agent any @@ -1088,11 +1086,11 @@ Finally add the actual pipeline:: } stage ('Universum check') { steps { - withCredentials([usernamePassword(credentialsId: 'GITHUB_APP', + withCredentials([usernamePassword(credentialsId: 'universum-test-app', usernameVariable: 'GITHUB_APP_ID', passwordVariable: 'GITHUB_PRIVATE_KEY')]) { sh("{pip} install -U universum[github] pylint") - sh("{python} -m universum --no-diff -vt github --report-to-review -rst -rsu -rof") + sh("{python} -m universum --no-diff -vt github") archiveArtifacts artifacts: 'artifacts/', followSymlinks: false } } @@ -1100,9 +1098,11 @@ Finally add the actual pipeline:: } } -The contents of the pipeline might now look not very familiar, and will be explained after setting up the handler. +Note how along with adding the credentials we changed the ``--vcs-type```command line parameter +`__ from simple ``git`` to ``github``. As seen from parameters listed above, using this +VCS type requires valid GitHub App info. -Let's transform the existing ``universum_postcommit`` into ``github_webhook_handler``, as it already has conveniently +Now let's transform the existing ``universum_postcommit`` into ``github_webhook_handler``, as it already has conveniently set up triggers and payload processing. Change the name and proceed to variables declared by ``Generic Webhook Trigger``. As for the payload, we will only need one parameter now, containing the whole payload contents, to be passed to handler and parsed. So in ``Post content parameters`` leave one with the following contents: @@ -1115,9 +1115,13 @@ with ``Request header`` set to ``x-github-event``. This is a `GitHub event` head payload itself. Also, now this job also requires predefined parameters, so in ``General`` check the ``This project is parameterized`` -and add the very same ``GITHUB_APP`` credentials parameter, as described above. +and add the a link to trigger the ``universum_check`` job: + + * Name: ``TRIGGER_URL`` + * Default valuer: ``https://localhost:8080/buildByToken/buildWithParameters?job=universum_check&token=GITHUB`` -Now, as for the pipeline, change it to the following:: +Now, as for the pipeline, we also need to extract GitHub App params, and launch :doc:`the GitHub Handler ` +instead of usual `Universum` check. So let's change it to the following:: pipeline { @@ -1128,7 +1132,7 @@ Now, as for the pipeline, change it to the following:: stages { stage ('Run GitHub Handler') { steps { - withCredentials([usernamePassword(credentialsId: 'GITHUB_APP', + withCredentials([usernamePassword(credentialsId: 'universum-test-app', usernameVariable: 'GITHUB_APP_ID', passwordVariable: 'GITHUB_PRIVATE_KEY')]) { sh("{pip} install -U universum[github]") @@ -1140,4 +1144,10 @@ Now, as for the pipeline, change it to the following:: } +.. _guide#report: + +Turn on pre-commit checks reporting +----------------------------------- + + .. TBD