zk_html/work/gitea-5.html

113 lines
19 KiB
HTML

<!doctype html>
<html>
<head>
<title>Zk | gitea-5</title>
<link rel="stylesheet" type="text/css" href="/style.css" />
<meta name="viewport" content="width=device-width" />
<meta charset="utf-8" />
</head>
<body>
<main>
<header>
<h1>Zk | gitea-5</h1>
</header>
<article class="content">
<h1 id="how-to-set-up-jenkins-with-gitea">How to set up jenkins with gitea</h1>
<p>In the process of developing and releasing software, one of the most useful tools at a developer&rsquo;s disposal is a solution that performs <strong>continuous integration</strong> and <strong>continuous deployment</strong>, or <strong>CI/CD</strong>.</p>
<p>Continuous integration (CI) refers to the practice of multiple developers merging their changes to a codebase back into the main branch often, perhaps daily or even more frequently, relying on smaller chunks of work that are more easily reviewed to and tested during the process of development. In order to ensure that these changes don&rsquo;t leave the main branch in a broken state, a tool that helps with continuous integration will often include functionality that runs test suites within the software package. When a developer proposes a merge of their work back into the main branch, the tests will run automatically and report back whether or not they pass, which may mean that the code is not ready to land.</p>
<p>Continuous deployment or continuous delivery (CD) refers to the idea that changes to code &mdash; whether they&rsquo;re security patches, bug fixes, or new features &mdash; be released quickly and seamlessly to the end users of the application. In the case of applications that the user runs, this will mean a frequent release schedule, offering incremental improvements to the software they are using. In the case of a service such as a website, this will mean frequent deployments of the new features in the code to the site so that the user&rsquo;s experience is continuously improving.</p>
<p>There are several tools that can help with CI/CD. These run as their own web services, which work with many source code management (SCM) systems to perform these tasks automatically. <a href="https://jenkins.io">Jenkins</a> is one such solution, that provides a way of executing <strong>pipelines</strong> &mdash; sets of steps that the service will run through such as building the software and running tests &mdash; that are described in the code itself. Jenkins is a full-featured CI/CD tool with a flexible, declarative pipeline syntax that allows you to accomplish many tasks.</p>
<p>This tutorial aims to show how Jenkins can integrate with the source code management tool Gitea in order to offer fully self-hosted solutions for SCM and CI/CD. You will be connecting Jenkins with Gitea, and creating a sample project for Jenkins to run tests on in order to see how the two services work together.</p>
<h3 id="prerequisites">Prerequisites</h3>
<p>For this tutorial, you will need the following:</p>
<ul>
<li>A server set up running an installation of Gitea. For more information on how to run Gitea on your own server, see this tutorial on <a href="https://www.digitalocean.com/community/tutorials/how-to-install-gitea-on-ubuntu-using-docker">How To Install Gitea on Ubuntu Using Docker</a>, which will walk you through the steps of <a href="https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-20-04">setting up your own Ubuntu server</a>, <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04">Installing Docker</a>, <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-20-04#step-1-installing-docker-compose">Installing Docker Compose</a>, and then installing Gitea <a href="https://docs.digitalocean.com/products/networking/dns/">on your own domain</a>.</li>
<li>A server set up running an installation of Jenkins. For more information on how to set up your own instance of Jenkins, This tutorial on <a href="https://www.digitalocean.com/community/tutorials/how-to-install-jenkins-on-ubuntu-20-04">How to Install Jenkins on Ubuntu 20.04</a> will get you going.</li>
</ul>
<h2 id="step-1-prepare-gitea-for-integration">Step 1 — Prepare Gitea for Integration</h2>
<p>Jenkins communicates to Gitea via a user that you create on your Gitea instance. In order to create this user, log into an account on your Gitea instance with administrative access. Click on your user icon in the upper right corner of the page and go to <strong>Site Administration</strong>, and then the <strong>User Accounts</strong> tab. Click <strong>Create User Account</strong> and make a new account named <code>jenkins</code>. Enter an email and secure password, then uncheck <strong>Require user to change password</strong>; this user will not be used to log into Gitea except to manage its connection to Jenkins, and that will be by the system administrators.</p>
<p>Once you have created the user, you will need to add a team to the organization that contains your source code&rsquo;s repository. On the organization&rsquo;s page, there will be a <strong>Teams</strong> section. Click <strong>New Team</strong> and create a team named <code>ci</code>. You can give this team access to all repositories or just the ones you specify. You may leave the permissions as is unless other work will be undertaken by the <code>ci</code> team members, in which case change them to meet your needs; you will always be able to update this later. Add your <code>jenkins</code> user to this team once it has been created by clicking the <strong>Add Team Member</strong> button on the team&rsquo;s page.</p>
<p>Now that you have the user set up for Jenkins to access, you will need to create an application token. To do this, log out of your current account and then log in as the <code>jenkins</code> user you just created. Click on your user icon in the upper right corner of the page, and click on <strong>Settings</strong>. In the tabs at the top of the page, click <strong>Applications</strong> where you will be able to generate a new access token. In the <strong>Manage Access Tokens</strong> section of the page, fill in the <strong>Token Name</strong> field with <code>jenkins</code> and click <strong>Generate Token</strong>. You will be provided with a token at the top of the page, a series of hexadecimal letters and numbers. Copy this token and paste it somewhere safe, as you will need it in future steps, and it will not be shown again.</p>
<h2 id="step-2-install-the-gitea-plugin">Step 2 — Install the Gitea Plugin</h2>
<p>The first step to integrate Jenkins with Gitea is to install the Gitea plugin in Jenkins. In order to do so, from the main dashboard, click <strong>Manage Jenkins</strong>. Once you&rsquo;re there, you will find a link titled <strong>Manage Plugins</strong>. Once you click that, in the tabs beneath the title of the page, select <strong>Available</strong>. This will allow you to search the Jenkins repository for all available plugins. Filter for &ldquo;Gitea&rdquo; and the plugin will appear in the list. Tick the checkbox next to the plugin and click <strong>Install without restart</strong>.</p>
<p>When the plugin is installed, you will be able to configure Jenkins to use your Gitea server. This is done through the <strong>Manage Jenkins</strong> page again, available via a link on the menu. There, you will see a link to <strong>Configure System</strong>. Scrolling down the page, you will find a <strong>Gitea Servers</strong> section. Click <strong>Add</strong> beneath to add a Gitea server. In that section, enter a name for the Gitea server, and then its full URL.</p>
<p>This section will also have a checkbox labeled <strong>Manage hooks</strong>. By default, Jenkins will only build Gitea branches and pull requests on demand. For each repository configured with Jenkins, you can opt to let Jenkins manage the webhooks that are called when a pull requests is created which will start the Jenkins pipeline. However, checking the <strong>Manage hooks</strong> checkbox while configuring the server will do this by default for all repositories. It acts as an &ldquo;opt out&rdquo; setting, rather than the default &ldquo;opt in&rdquo;. If you do decide to check this box, you will be prompted to enter credentials. Add a new set of credentials, and on the modal pop-up that is shown, set the kind of credentials to &ldquo;Gitea Personal Access Token&rdquo; and the scope to &ldquo;System&rdquo;. This will ensure that the Gitea owner of the access token will only have access to Jenkins and its nodes.</p>
<p><a href="TODO.html"><img alt="Jenkins Gitea server screen" src="TODO" /></a></p>
<p>Name your credential something like <code>jenkins-gitea</code> and paste your token from <strong>Step 1</strong> into the token field. This will give Jenkins application access to Gitea via the token created for the <code>jenkins</code> user. Leave the <strong>ID</strong> and <strong>Description</strong> fields blank and click <strong>Add</strong>. When you are returned to the server configuration, click <strong>Save</strong> to create the Gitea server in Jenkins.</p>
<h2 id="step-3-map-gitea-to-jenkins">Step 3 — Map Gitea to Jenkins</h2>
<p>Now that both Gitea and Jenkins are prepared, you can map them to each other. On the Jenkins dashboard, click <strong>+ New Item</strong>. This will provide you with a list of various types of items that you can create. For the purposes of CI with Gitea, you will need to create an organization. Type the name of you organization in the field provided, click <strong>Organization Folder</strong>, and then click <strong>OK</strong> to create the organization. This will provide you with the ability to set up your organisation. Set the name of the organization and provide a short description, then, under <strong>Projects</strong>, add a Gitea organization via the <strong>Add</strong> drop down provided. This will pre-fill with some of the information you added in the previous step, but you will need to associate credentials with the project. If you created the credentials in the previous step, those will appear in the list when you click <strong>Add</strong> in the credentials section, otherwise you will need to create them as above, using the access token you created in <strong>Step 1</strong>. Follow the instructions in <strong>Step 2</strong> for creating the credentials, making sure to set the kind to &ldquo;Gitea Personal Access Token&rdquo;. In the <strong>Owner</strong> field, enter <code>jenkins</code>, the user you created in <strong>Step 1</strong>.</p>
<p>In the <strong>Behaviors</strong> section, you will be able to set how Jenkins discovers code to run its CI pipeline against. For instance, you can set it so that Jenkins discovers all branches whether or not they have filed pull requests, or what types of pull requests to discover. For now, the default behaviors are fine, so you do not need to change them. The rest of the page contains various other ways that you can tune Jenkins&rsquo;s interaction with Gitea, all of which have sensible defaults, so you do not need to change them, but if you would like to learn more, clicking on the question marks within each section will provide you with more information about how each field works.</p>
<p>When you are done creating the organization folder, click <strong>Save</strong> and you will be shown the results of Jenkins scanning the Gitea organization for repositories and branches that meet its criteria. For now, the criteria is simply whether or not a repository contains a file named <code>Jenkinsfile</code>, which describes the pipeline used to test or deploy the project. We will create the pipeline in the next step</p>
<h2 id="step-5-create-the-jenkins-ci-pipeline">Step 5 — Create the Jenkins CI Pipeline</h2>
<p>Let&rsquo;s create a sample project in order to test this interaction. In Gitea, create a new repository, and then clone it on your local machine. Since Jenkins works with pull requests, switch to a new branch named <code>jenkins</code>:</p>
<div class="codehilite"><pre><span></span><code>git checkout -b jenkins
</code></pre></div>
<p>Using your favorite code editor, create a new file named <code>jenkins_test.py</code> and enter the following into it:</p>
<div class="codehilite"><pre><span></span><code><span class="p">[</span><span class="n">label</span> <span class="n">jenkins_test</span><span class="o">.</span><span class="n">py</span><span class="p">]</span>
<span class="k">assert</span> <span class="mi">1</span> <span class="o">==</span> <span class="mi">1</span>
</code></pre></div>
<p>This simple Python script ensure that 1 really is equal to 1, which is a very important fact to have at hand. Save and close the file in your code editor.</p>
<p>Now, open up a new file in your project named <code>Jenkinsfile</code> (including the capital <code>J</code>), and enter the following:</p>
<div class="codehilite"><pre><span></span><code><span class="k">[label Jenkinsfile]</span><span class="w"></span>
<span class="na">pipeline {</span><span class="w"></span>
<span class="w"> </span><span class="na">agent none</span><span class="w"></span>
<span class="w"> </span><span class="na">stages {</span><span class="w"></span>
<span class="w"> </span><span class="na">stage(&#39;test&#39;) {</span><span class="w"></span>
<span class="w"> </span><span class="na">agent {</span><span class="w"></span>
<span class="w"> </span><span class="na">docker {</span><span class="w"></span>
<span class="w"> </span><span class="na">image &quot;python&quot;</span><span class="w"></span>
<span class="w"> </span><span class="na">}</span><span class="w"></span>
<span class="w"> </span><span class="na">}</span><span class="w"></span>
<span class="w"> </span><span class="na">steps {</span><span class="w"></span>
<span class="w"> </span><span class="na">script {</span><span class="w"></span>
<span class="w"> </span><span class="na">sh &quot;&quot;&quot;</span><span class="w"></span>
<span class="w"> </span><span class="na">python jenkins_test.py</span><span class="w"></span>
<span class="w"> </span><span class="na">&quot;&quot;&quot;</span><span class="w"></span>
<span class="w"> </span><span class="na">}</span><span class="w"></span>
<span class="w"> </span><span class="na">}</span><span class="w"></span>
<span class="w"> </span><span class="na">}</span><span class="w"></span>
<span class="w"> </span><span class="na">}</span><span class="w"></span>
<span class="na">}</span><span class="w"></span>
</code></pre></div>
<p>Let&rsquo;s go over what this pipeline is saying.</p>
<ul>
<li>We set <code>agent none</code> at the beginning as we will be using a docker agent specifically within the <code>test</code> stage.</li>
<li>Jenkins pipelines are made up of various different stages, which can be tasks such as testing, linting, and deploying your code. In this case, we created a <code>test</code> stage to run tests against our Python.</li>
<li>The agent declaration says that this stage should use a Docker container running the <code>python</code> image from the public Docker registry.</li>
<li>The <code>steps</code> section is where the real work occurs. Each step required for testing is provided in order. In our case, we only have one step, which is to run a script in the shell, which calls <code>python jenkins_test.py</code>.</li>
</ul>
<p>Add both of these files to your Git working tree and commit your changes:</p>
<div class="codehilite"><pre><span></span><code>git add .
git commit -m &quot;Added test and Jenkinsfile&quot;
</code></pre></div>
<p>Now, push your branch up to Gitea:</p>
<div class="codehilite"><pre><span></span><code>git push origin jenkins
</code></pre></div>
<p>On the repository page in Gitea, create a new pull request in order to merge your <code>jenkins</code> branch into your main branch (often named <code>main</code> or <code>master</code>). Since Jenkins is watching the repository and now sees that there is a <code>Jenkinsfile</code> in the branch you are trying to merge in, it recognizes that this is a repository that it should track and will begin running the pipeline for that pull request.</p>
<p>&lt;$&gt;[note]
<strong>Note:</strong> Jenkins may not pick up on this change right away depending on whether or not the webhooks are configured for the project. If that&rsquo;s the case, on the Jenkins page for your organization, click <strong>Scan Gitea Organization Now</strong> and it should pick up on the ranch and repository.
&lt;$&gt;</p>
<p>On the Jenkins page for your organization, you should see your repository in the list. When you click on it, you will be provided with a list of pipelines that are running; there should be one in the <strong>Pull Requests</strong> section for &ldquo;PR-1&rdquo;. When you click on that, you should see the status of the current pipeline. If it is running, you can click on <strong>Console Output</strong> on the left menu to view the steps that it is taking such as creating the Docker container, pulling the Python image, and then running the script specified in the Jenkinsfile. If 1 is indeed equal to 1, then this build should be successful.</p>
<p>When you look back at your pull request on Gitea, you will see that there is a new section above the comment box where it is running checks via Jenkins. This can be <strong>in progress</strong> where the indicator is yellow, or <strong>checks passed</strong> if it&rsquo;s green or <strong>checks failed</strong> if it&rsquo;s red. This provides an indicator as to the branch&rsquo;s status within Gitea itself, so that you need not open up Jenkins just to check for a pass or fail.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to set up Jenkins and Gitea so that you can run continuous integration pipelines against your source code repositories. Continuous integration ensures that the quality of your code remains high and that the chances of breaking changes being introduced into your main branch of your code. Just as Gitea provides an excellent self-hosted source code management solution, Jenkins provides an excellent continuous integration solution, and together, they can help keep your project moving quickly and cleanly.</p>
</article>
<footer>
<p>Page generated on 2022-06-30</p>
</footer>
</main>
<script type="text/javascript">
document.querySelectorAll('.tag').forEach(tag => {
let text = tag.innerText;
tag.innerText = '';
tag.innerHTML = `<a href="/tags.html#${text}">${text}</a>`;
});
</script>
</body>
</html>