<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>project &#8211; Best DevOps</title>
	<atom:link href="https://www.bestdevops.com/tag/project/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bestdevops.com</link>
	<description>Lets Learn, Do it &#38; Share! Thats a Best DevOps!!!</description>
	<lastBuildDate>Tue, 13 Oct 2026 10:49:52 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>
	<item>
		<title>How to install Gitlab runner on Mac OS?</title>
		<link>https://www.bestdevops.com/how-to-install-gitlab-runner-on-mac-os/</link>
		
		<dc:creator><![CDATA[rahulkr]]></dc:creator>
		<pubDate>Tue, 30 Nov 2021 04:21:45 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[command]]></category>
		<category><![CDATA[GitLab]]></category>
		<category><![CDATA[Operating system]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[Services]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[start]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=22474</guid>

					<description><![CDATA[Hello-tech lover, welcome to the visualizing path of programming. You know better today trends to take up-gradation in technologies and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" src="https://www.bestdevops.com/wp-content/uploads/2021/11/CIFcfAWO5J-ksEmtOoTfMUndu62eVMDOS25K5sp_Hgw.jpg" alt="" class="wp-image-22476" width="729" height="382" srcset="https://www.bestdevops.com/wp-content/uploads/2021/11/CIFcfAWO5J-ksEmtOoTfMUndu62eVMDOS25K5sp_Hgw.jpg 640w, https://www.bestdevops.com/wp-content/uploads/2021/11/CIFcfAWO5J-ksEmtOoTfMUndu62eVMDOS25K5sp_Hgw-300x158.jpg 300w" sizes="(max-width: 729px) 100vw, 729px" /></figure></div>



<p class="wp-block-paragraph">Hello-tech lover, welcome to the visualizing path of programming. You know better today trends to take up-gradation in technologies and their environment around the world. Through this article, we are going to give you lessons on Gitlab runner and we will go very basic step by step and learn how to install, register, and start Gitlab runner. So, if you have no primary knowledge of that then do not worry. We will start from scratch.</p>



<h2 class="wp-block-heading">What is a Gitlab runner?</h2>



<p class="wp-block-paragraph">Gitlab runner is used in Gitlab CI and you have not learnt yet Gitlab CI. Now, this is an open-source continuous <a href="https://www.devopsschool.com/">integration</a> service. It is included with Gitlab, is used to run jobs &amp; send results back to Gitlab. Now, let’s see, what are the steps you have to do for setting up Gitlab runner.</p>



<h2 class="wp-block-heading">How to install Gitlab runner?</h2>



<p class="wp-block-paragraph">Let us see, what we will do about this? You will go to Google and search for Gitlab runner. You will visit the website for Gitlab runner documentation and you will see all the documents over there. This is written in a go programming language, you can see some features like multiple jobs concurrently run. And if you will have to move down, there will be a section of install Gitlab runner. You would find every sort of documentations about Gitlab runner like how to configure, troubleshooting, etc. If you will click on the install option then there will be options like Mac for the operating system. So, you will click on the option to install Mac operating system and there you will have the steps if you want to install it manually. Then you will have to install the binary in your system and you can use that given command from there. You may copy and run it in your terminal then it will download the binary. So, you will have to give permissions from the given command. This is the first way, the second way is homebrew installation. If you will go for homebrew, there will be a website so, you will see there “<strong><em>the missing package manager for Mac OS”</em></strong> like this type of thing will be written there. To install homebrew, it is very simple so, you will have to copy that statement from there and will have to run on terminal. Then you can start using homebrew, it is a good way to install and manage packages on Mac. There will be a command so, you will have to run that on your terminal then this will install Gitlab runner on your Mac operating system. Here are some commands to install, version, start, and stop like</p>



<p class="wp-block-paragraph"><strong>Brew install Gitlab –runner</strong></p>



<p class="wp-block-paragraph"><strong>Gitlab-runner –version</strong></p>



<p class="wp-block-paragraph"><strong>Brew services start GitLab –runner</strong></p>



<p class="wp-block-paragraph"><strong>Brew services stop GitLab –runner</strong></p>



<h2 class="wp-block-heading">How to register Gitlab runner?</h2>



<p class="wp-block-paragraph">Let us see how can we register GitLab runner? So, there you will visit the Gitlab runner documentation. You will find the registration part in that you will have a register link and from there, you would see that what are the step to register the Gitlab runner? Now, on that page, if you will scroll down then you will find all the steps for Mac OS, window OS, etc. so, you will have to run the following command Gitlab –runner register, this is the first command. You will go to your terminal and run the command Gitlab –runner register then there, they shall ask for a Gitlab-ci token for this runner. So, to get the ci token, you will log in to your Gitlab account and you will have to take tokens from Gitlab projects. You will go to your project by doing a sign-in process then you would have to go to project settings. If you will see, scroll down and you will find the setting there. If you will go to settings under that you will get CI /CD section. You will go to CI/CD then you will have a section of runner then you will expand it. You will find the setup runner manually option will be there and there will be a token of your project. You will have to do copy that from there and provide it on the terminal and you will also put tags for your Gitlab ci like ssh, ci. Then you will see registering runner…..succeeded and after this, you will have to enter the name of executors like parallels, custom, Docker-ssh, etc. you have so many executors if you want to run on Docker and some Kubernetes. If you will put simple executor <strong><em>shell</em></strong> and press enter button. Then it will show the runner registered successfully. These are the commands which you have followed.</p>



<h2 class="wp-block-heading">How to start Gitlab runner?</h2>



<p class="wp-block-paragraph"> So, if you have to start Gitlab runner then you can use these <strong><em>brew services start Gitlab –runner</em></strong>. To start Gitlab runner, if you’re not using brew then you will have all the options there like <strong><em>Gitlab –runner stop</em></strong>. You can take <strong><em>Gitlab –runner start </em></strong>if you are not using brew. Then it will be successfully started and the next step will be to check runner is activated in the project. So, you will have to check runner is activated or not, again, you will go to your Gitlab, project, and in settings CI/CD. And there you will expand the runner section, if you will scroll down then you will see your runner will be there, it is started. You can also see the name and text that you had added. So, you have seen that how to use the runner and how to do Gitlab ci? I wish, these lessons will be very helpful for you.</p>



<h4 class="wp-block-heading">Related video:</h4>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe  id="_ytid_54632"  width="675" height="379"  data-origwidth="675" data-origheight="379" src="https://www.youtube.com/embed/j_8gibe4HWk?enablejsapi=1&#038;autoplay=0&#038;cc_load_policy=0&#038;cc_lang_pref=&#038;iv_load_policy=1&#038;loop=0&#038;rel=1&#038;fs=1&#038;playsinline=0&#038;autohide=2&#038;theme=dark&#038;color=red&#038;controls=1&#038;disablekb=0&#038;" class="__youtube_prefs__  epyt-is-override  no-lazyload" title="YouTube player"  allow="fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen data-no-lazy="1" data-skipgform_ajax_framebjll=""></iframe>
</div></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to fork a project on Gitlab?</title>
		<link>https://www.bestdevops.com/how-to-fork-a-project-on-gitlab/</link>
		
		<dc:creator><![CDATA[rahulkr]]></dc:creator>
		<pubDate>Mon, 22 Nov 2021 14:57:33 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[branch]]></category>
		<category><![CDATA[Fork]]></category>
		<category><![CDATA[GitLab]]></category>
		<category><![CDATA[merge]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[Source]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=22449</guid>

					<description><![CDATA[Hello, my dear friends, welcome to the most abundant part of programming that makes your life very great with enormous [&#8230;]]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter size-full is-resized"><img decoding="async" src="https://www.bestdevops.com/wp-content/uploads/2021/11/eXMy_SuLSZgHBamI_KFu7I9QtT5bUQIEXfhCvrDyT2I.png" alt="" class="wp-image-22451" width="825" height="343" srcset="https://www.bestdevops.com/wp-content/uploads/2021/11/eXMy_SuLSZgHBamI_KFu7I9QtT5bUQIEXfhCvrDyT2I.png 640w, https://www.bestdevops.com/wp-content/uploads/2021/11/eXMy_SuLSZgHBamI_KFu7I9QtT5bUQIEXfhCvrDyT2I-300x125.png 300w" sizes="(max-width: 825px) 100vw, 825px" /></figure></div>



<p class="wp-block-paragraph">Hello, my dear friends, welcome to the most abundant part of programming that makes your life very great with enormous pleasure because this is the place where everyone should want to know that what is worth it? and how it plays an important role in real life. So, today we will learn about how can you fork a <a href="https://www.devopsschool.com/">project</a> and manage them. For this, I will go very basic step by step. I wish that you will read it till the end.</p>



<h2 class="wp-block-heading">What is a fork?</h2>



<p class="wp-block-paragraph">Let’s understand this. In very simple words, a fork is a copy of a project, forking a pro/repo allows you to make changes without affecting the original project or copy. Whenever you want to make changes to the project or you do not want to change anything in the original copy then you can create a fork that you can create a copy and make your changes. And later on, you can merge with the original project as well.</p>



<h2 class="wp-block-heading">How to fork a project?</h2>



<p class="wp-block-paragraph">So, here is step no.1</p>



<p class="wp-block-paragraph">Step 1: <strong>log in to Gitlab and go to your project</strong></p>



<p class="wp-block-paragraph">So, you will go to your Gitlab and sign in or log in with your credentials. And then you will go to your project where there will be your single project. You can also go from there with the above project option. You will see, your project will be there then you can also go to your projects from there as well.</p>



<p class="wp-block-paragraph">Step 2: <strong>Click on the fork button</strong></p>



<p class="wp-block-paragraph">So, there on your projects. You will see, there will be a button. That will be a fork, in your project. When you will click on that button then you will get a message like No spaces available for the name to fork the project.</p>



<p class="wp-block-paragraph">I tell you that what will you do? When you will see a message like this. You will see a group option on the top menu then you will click on your groups. And once, you will have it on the group screen. You will see the New Group option beside the corner. Then, you will click on that and give your group name and description. If you want to keep public or private, you can do that with one click. So, your group will have created at that time. If you will go back to your project and there you will again click on the fork option. So, they will ask to select a namespace to fork the project and you will see, your created group will be there. Then you will see that the project has successfully forked. You can also create merge requests over there.</p>



<p class="wp-block-paragraph">For example, On the copy of the project, you can make some changes, and once, you have to change. If you create a merge request to merge with your original branch. Then you will do a new merge request so, you will select source branch and branch name and after that, you will also select the target branch &amp; their name. And you will click on <strong><em>compare branches &amp; continue. </em></strong>If any changes will have been done there so, it will see in that but you will have not done any changes in the copied or forked project. Then, it will show you as usual. If you have done any changes in that &amp; you will do submit a merge request then you will have to realize the changes and you can submit back. And this is how you can do forking of a project and a copy of the project.</p>



<h4 class="wp-block-heading">Related video:</h4>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy"  id="_ytid_69202"  width="675" height="379"  data-origwidth="675" data-origheight="379" src="https://www.youtube.com/embed/0oo3Q2L4i4M?enablejsapi=1&#038;autoplay=0&#038;cc_load_policy=0&#038;cc_lang_pref=&#038;iv_load_policy=1&#038;loop=0&#038;rel=1&#038;fs=1&#038;playsinline=0&#038;autohide=2&#038;theme=dark&#038;color=red&#038;controls=1&#038;disablekb=0&#038;" class="__youtube_prefs__  epyt-is-override  no-lazyload" title="YouTube player"  allow="fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen data-no-lazy="1" data-skipgform_ajax_framebjll=""></iframe>
</div></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How can you start with Gitlab?</title>
		<link>https://www.bestdevops.com/how-can-you-start-with-gitlab/</link>
		
		<dc:creator><![CDATA[rahulkr]]></dc:creator>
		<pubDate>Sat, 20 Nov 2021 11:44:58 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Bitbucket]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[GitLab]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[SDLC]]></category>
		<category><![CDATA[version-control]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=22415</guid>

					<description><![CDATA[Hello, welcome to this techno-friendly environment. Today, I’m going to give you lessons on the most demanding topic that supports [&#8230;]]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://www.bestdevops.com/wp-content/uploads/2021/11/gitlab-logo-white-preview-1024x452.png" alt="" class="wp-image-22417" width="761" height="335" srcset="https://www.bestdevops.com/wp-content/uploads/2021/11/gitlab-logo-white-preview-1024x452.png 1024w, https://www.bestdevops.com/wp-content/uploads/2021/11/gitlab-logo-white-preview-300x132.png 300w, https://www.bestdevops.com/wp-content/uploads/2021/11/gitlab-logo-white-preview-768x339.png 768w, https://www.bestdevops.com/wp-content/uploads/2021/11/gitlab-logo-white-preview-1536x677.png 1536w, https://www.bestdevops.com/wp-content/uploads/2021/11/gitlab-logo-white-preview-2048x903.png 2048w" sizes="auto, (max-width: 761px) 100vw, 761px" /></figure></div>



<p class="wp-block-paragraph">Hello, welcome to this techno-friendly environment. Today, I’m going to give you lessons on the most demanding topic that supports everywhere in the path of programming and the tech world. Now, you could focus on that whatever you want to learn because I’m giving these lessons from scratch. If you need support then you can take deep dives into it.</p>



<h2 class="wp-block-heading">What is Gitlab?</h2>



<p class="wp-block-paragraph">Let’s get started with that. Before, have to start <a href="https://www.devopsschool.com/">Gitlab</a>. Let us see, what is the difference between git and GitLab? If we talk about git, it is a version control system that is used to locally track our changes in your project/folder. Once, you add a folder and your project to git, it will start tracking for changes. Also, you can push &amp; pull changes from remote repositories like GitHub, bit bucket, Gitlab. So, this is what? Git is. Now, what is Gitlab? In fact, Gitlab, GitHub, bit bucket provides similar kind of services. And what is this? These are services that allow you to host your project on a remote repository &amp; have additional features to help in SDLC and CI, CD. They can be features like managing, sharing, wiki, bug tracking, and CI &amp; CD that is continuous integration &amp; continuous deployment. All these services can be provided by these services like Gitlab, GitHub, and bit bucket. These are cloud services so, we are going to focus on Gitlab or towards this article &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>



<h2 class="wp-block-heading">Create an account on Gitlab</h2>



<p class="wp-block-paragraph">So, here.</p>



<p class="wp-block-paragraph"><strong>Step 1:</strong> <strong>Go to <em>Gitlab.com</em> and create an account or sign up.</strong></p>



<p class="wp-block-paragraph">So, you will just go on the search for Gitlab on Google, you will get gitlab.com then you will go there. There will be the website <strong><em>gitlab.com</em></strong>, you will also find some documentation there. You will not worry about whatever will have written there. So, for now, let you go on the register option, and there, you will have to provide the name, username, email id that you use, you will have to confirm your email id and will have to choose a password. After that, you will accept the terms and register them. Then it will send a confirmation email to your email id and from there, you will have been done GitLab sign up from the email.</p>



<p class="wp-block-paragraph">Now, this is going to be step no. 2.</p>



<p class="wp-block-paragraph"><strong>Step 2: Sign in to Gitlab</strong></p>



<p class="wp-block-paragraph">Then you will use your username or email, and password for your sign-in process. So, you will have logged in to Gitlab, you will see lots of options and features over there. For that time, you will have to take create a project from there. You will also see plus button option besides the project option with creating a new drop-down option. You can also create from there.</p>



<h2 class="wp-block-heading">Create a new project on Gitlab</h2>



<p class="wp-block-paragraph">This will take you to the new project options screen. In that, you could create a project by giving your own project name like <em><strong>my first project</strong></em>. You can also give some description which is optional, you could keep it public or private according to your demand. And after that, you can click on a new project option then your project will have been created. Then you will see URL links that will have on the top which will be your project link. You can also go through the clone option, there will be links like <strong><em>clone with SSH</em></strong> and <strong><em>clone with HTTPS. </em></strong>You can copy from there or from the address bar, that project link you can use whenever you want to do push or pull. So, this way, you can create your own project on Gitlab. </p>



<h4 class="wp-block-heading">Related video:&nbsp;&nbsp;</h4>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy"  id="_ytid_65442"  width="675" height="379"  data-origwidth="675" data-origheight="379" src="https://www.youtube.com/embed/_3l5OelRtk8?enablejsapi=1&#038;autoplay=0&#038;cc_load_policy=0&#038;cc_lang_pref=&#038;iv_load_policy=1&#038;loop=0&#038;rel=1&#038;fs=1&#038;playsinline=0&#038;autohide=2&#038;theme=dark&#038;color=red&#038;controls=1&#038;disablekb=0&#038;" class="__youtube_prefs__  epyt-is-override  no-lazyload" title="YouTube player"  allow="fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen data-no-lazy="1" data-skipgform_ajax_framebjll=""></iframe>
</div></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>require ext-dom * -&gt; it is missing from your system. Install or enable PHP&#8217;s dom extension.</title>
		<link>https://www.bestdevops.com/require-ext-dom-it-is-missing-from-your-system-install-or-enable-phps-dom-extension/</link>
		
		<dc:creator><![CDATA[pradeep]]></dc:creator>
		<pubDate>Fri, 06 Aug 2021 07:22:56 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[installPHPComposer]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php&#039;s_domExtenstion]]></category>
		<category><![CDATA[project]]></category>
		<guid isPermaLink="false">https://www.bestdevops.com/?p=18755</guid>

					<description><![CDATA[Make sure you are in htdocs folder while executing the commands. I was trying to install Laravel in a Ubuntu [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading"><strong>Make sure you are in htdocs folder while executing the commands.</strong></h2>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://www.bestdevops.com/wp-content/uploads/2021/08/image-40.png" alt="" class="wp-image-18766" width="523" height="446" srcset="https://www.bestdevops.com/wp-content/uploads/2021/08/image-40.png 737w, https://www.bestdevops.com/wp-content/uploads/2021/08/image-40-300x256.png 300w" sizes="auto, (max-width: 523px) 100vw, 523px" /></figure>



<h2 class="wp-block-heading">I was trying to install Laravel in a Ubuntu virtual machine and got this error </h2>



Your requirements could not be resolved to an installable set of packages.
  Problem 1
    &#8211; phpunit/phpunit[7.5.0, &#8230;, 7.5.20] require ext-dom * -&gt; it is missing from your system. Install or enable PHP&#8217;s dom extension.
    &#8211; Root composer.json requires phpunit/phpunit ^7.5 -&gt; satisfiable by phpunit/phpunit[7.5.0, &#8230;, 7.5.20].



<h3 class="wp-block-heading">And To enable extensions, verify that they are enabled in your .ini files:</h3>



<p class="wp-block-paragraph">But in your server you&#8217;re missing&nbsp;<code>ext-dom</code>.&nbsp;<code>php-xml</code>&nbsp;has all the related packages you need. So, you can simply install it by running:</p>


<pre class="wp-block-code"><span><code class="hljs">sudo apt install php-xml</code></span></pre>


<h3 class="wp-block-heading">Most likely you are missing&nbsp;<code>mbstring</code>&nbsp;too. If you get the error, install this package as well with:</h3>


<pre class="wp-block-code"><span><code class="hljs language-javascript">sudo apt-<span class="hljs-keyword">get</span> install php-mbstring</code></span></pre>


<h3 class="wp-block-heading">Then run:</h3>


<pre class="wp-block-code"><span><code class="hljs language-javascript">composer update
composer <span class="hljs-built_in">require</span> cviebrock/eloquent-sluggable</code></span></pre>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The ReadME Project shares innovative paths to DevOps success</title>
		<link>https://www.bestdevops.com/the-readme-project-shares-innovative-paths-to-devops-success/</link>
					<comments>https://www.bestdevops.com/the-readme-project-shares-innovative-paths-to-devops-success/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Wed, 02 Dec 2020 06:18:42 +0000</pubDate>
				<category><![CDATA[GitHub]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[innersourcing]]></category>
		<category><![CDATA[innovative]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[ReadME]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=14750</guid>

					<description><![CDATA[Source:-https://github.blog GitHub has the privilege of partnering with thousands of organizations to improve their DevOps practices, from established enterprises transforming [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Source:-https://github.blog</p>
<p>GitHub has the privilege of partnering with thousands of organizations to improve their DevOps practices, from established enterprises transforming the way they work to born-in-the-cloud businesses. We often connect developers, teams, and GitHub Enterprise customers with one another to exchange ideas and lessons learned, but we also recognize the value of making DevOps best practices and lessons available to all. Today, we’re excited to add to this body of knowledge with more stories from across the business and open source landscape.</p>
<p>When it comes to DevOps, we have come to recognize that the broader GitHub community is an incredibly important source of information. Because there’s no one size fits all DevOps solution, individual developers and teams can learn a tremendous amount from their peers. They seek guidance on what’s considered a good practice, which toolchains to consider, or how they’re performing relative to similar teams. They ask others about how to build a culture that encourages effective collaboration, which metrics to track to ensure their changes are making an impact, or even what to do when an initiative fails.</p>
<p>In an effort to give our community a space to share these lessons learned and DevOps best practices, we’re featuring articles from leaders in our community on GitHub’s The ReadME Project, starting with three teams featured today. Each talks through one of their end-to-end engineering processes, including toolchains, best practices, and key performance indicators (KPIs)—as well as important learnings they believe will benefit others.</p>
<p>George Swan shares how Autodesk transformed their business by knocking down silos, increasing innersourcing across teams, and standardizing processes into a cohesive pipeline to synchronize product, documentation, and localization releases.<br />
Austin Hemmelgarn describes how site reliability engineers and developers at Netdata continually improve their processes for a distributed team, and how they automate and manage releases for a business built on open source software.<br />
Kevin Mo discusses the impetus behind Front’s move to Kubernetes, and how the company enabled continuous deployment.<br />
We want our global community to continue to learn from each other, so we’re inviting you to nominate individuals and teams with different goals, talents, histories, and challenges to share their unique perspectives, technical expertise, and best practices on GitHub’s The ReadME Project.</p>
<p>In the coming weeks, we’ll be sharing more community contributed articles—not just from businesses, but from open source communities and industry leaders supporting DevOps toolchains. We’re looking forward to learning from individuals, teams, and GitHub Enterprise organizations—and receiving your feedback—so we can all build better software, together.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/the-readme-project-shares-innovative-paths-to-devops-success/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VMware and Pivotal: What the Acquisition Meant for the Cloud Foundry vs. Kubernetes Debate</title>
		<link>https://www.bestdevops.com/vmware-and-pivotal-what-would-a-merger-mean-for-the-cloud-foundry-kubernetes-debate/</link>
					<comments>https://www.bestdevops.com/vmware-and-pivotal-what-would-a-merger-mean-for-the-cloud-foundry-kubernetes-debate/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Sat, 17 Aug 2019 06:32:35 +0000</pubDate>
				<category><![CDATA[Vmware]]></category>
		<category><![CDATA[Foundry]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=7035</guid>

					<description><![CDATA[When VMware moved to acquire Pivotal in 2019, it set the stage for a closer relationship between Cloud Foundry and Kubernetes—two platforms that enterprises use to build and run cloud-native applications. Here is what that deal meant for the PaaS vs. KaaS debate.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on reporting originally published at <a href="https://www.crn.com" rel="noopener">crn.com</a> in August 2019, drawing on commentary from Solstice CTO Mike Koleno.</em></p>



<h2 class="wp-block-heading">Background: Two Platforms, One Strategic Question</h2>



<p class="wp-block-paragraph">Large enterprises evaluating cloud-native application development in 2019 generally faced a choice between two open-source platforms: Cloud Foundry or Kubernetes. Each approach had a distinct philosophy, and the VMware–Pivotal acquisition brought that debate into sharp relief.</p>



<ul class="wp-block-list">
  <li><strong>Cloud Foundry</strong> is an opinionated Platform-as-a-Service (PaaS). It abstracts away infrastructure decisions, giving developers a fast, standardised path to deploying and scaling applications across any cloud.</li>
  <li><strong>Kubernetes</strong> is a container orchestrator that is highly customisable. It gives operations teams fine-grained control over networking, storage, scheduling and runtime behaviour, at the cost of greater operational complexity.</li>
</ul>



<p class="wp-block-paragraph">Both technologies are open source and capable of running workloads at scale across public, private and hybrid clouds. The choice between them generally came down to how much operational complexity an organisation was willing to own.</p>



<h2 class="wp-block-heading">Pivotal&#8217;s Position Before the Acquisition</h2>



<p class="wp-block-paragraph">Pivotal Software was best known in the market as the company behind Pivotal Cloud Foundry (PCF), its commercial distribution of the Cloud Foundry PaaS. Pivotal had spearheaded the Cloud Foundry project and donated the core codebase to the Cloud Foundry Foundation.</p>



<p class="wp-block-paragraph">Despite that brand association, Pivotal had been investing heavily in Kubernetes by 2019. Two parallel workstreams illustrated this:</p>



<ol class="wp-block-list">
  <li><strong>Pivotal Container Service (PKS)</strong> — a jointly developed Kubernetes-as-a-Service (KaaS) offering built with VMware and Google, designed to provision and manage enterprise-grade Kubernetes clusters.</li>
  <li><strong>Kubernetes-based Pivotal Application Service</strong> — a version of Pivotal&#8217;s PaaS layer built on top of Kubernetes rather than Diego, the native Cloud Foundry container runtime. This move signalled that Kubernetes was becoming the preferred underlying runtime even within the Cloud Foundry ecosystem.</li>
</ol>



<p class="wp-block-paragraph">Both Pivotal and the upstream Cloud Foundry project were in the process of replacing Diego with Kubernetes as the container runtime, pointing toward deeper integration regardless of any corporate deal.</p>



<h2 class="wp-block-heading">The Acquisition Logic: What VMware Stood to Gain</h2>



<p class="wp-block-paragraph">VMware and Pivotal were already sister companies under the Dell Technologies umbrella when acquisition talks emerged. Solstice, a Chicago-based technology consulting firm that partnered with both companies, offered a practitioner&#8217;s perspective on the strategic rationale.</p>



<p class="wp-block-paragraph">Solstice CTO Mike Koleno identified three concrete benefits a VMware acquisition of Pivotal would deliver:</p>



<h3 class="wp-block-heading">1. Brand Liberation for Pivotal&#8217;s Platform Portfolio</h3>



<p class="wp-block-paragraph">Pivotal&#8217;s brand was so closely tied to Cloud Foundry that its growing Kubernetes capabilities were largely invisible in the market. Placing both PCF and PKS under the VMware banner would let VMware present them as a complementary portfolio—a PaaS option and a KaaS option—rather than having them compete under a brand defined by one technology.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  <p>&#8220;Putting the Pivotal platform, whether Cloud Foundry or PKS, all of it behind VMware makes a ton of sense and alleviates that brand connection. It allows VMware to say we have a newer set of platforms that cater to different appetites.&#8221;</p>
  <cite>— Mike Koleno, CTO, Solstice</cite>
</blockquote>



<h3 class="wp-block-heading">2. Access to VMware&#8217;s Enterprise Install Base</h3>



<p class="wp-block-paragraph">VMware&#8217;s customer base included a significant portion of the Fortune 500—organisations that had been running VMware infrastructure for over a decade. Most of those customers had not yet adopted cloud-native application development practices. With PCF and PKS available under the VMware umbrella, VMware&#8217;s salesforce could introduce both platforms to an enormous installed base already primed to trust VMware for infrastructure decisions.</p>



<h3 class="wp-block-heading">3. A Simpler Competitive Story for PKS</h3>



<p class="wp-block-paragraph">In 2019, the managed Kubernetes market was intensely competitive, with offerings from AWS, Google Cloud, Microsoft Azure and independent vendors. PKS had been a joint Pivotal–VMware project, which introduced complexity in go-to-market messaging. Folding it into a single VMware-owned product would simplify the sales motion and sharpen its competitive positioning.</p>



<h2 class="wp-block-heading">The PaaS vs. KaaS Debate: Closer Together, Not Merged</h2>



<p class="wp-block-paragraph">Even with both platforms under one corporate roof, Koleno was careful to point out that Cloud Foundry and Kubernetes solve fundamentally different problems and would continue to attract different audiences.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
  <p>&#8220;You&#8217;re going to always have the debate as to how much operational customisation you want to take on as part of the service and platform we provide to the application developers across the enterprise.&#8221;</p>
  <cite>— Mike Koleno, CTO, Solstice</cite>
</blockquote>



<p class="wp-block-paragraph">The practical split he described works as follows:</p>



<ul class="wp-block-list">
  <li><strong>PaaS (Cloud Foundry) users</strong> want to abstract away as much infrastructure as possible. They prioritise developer experience and speed of delivery over operational control. Cloud Foundry handles routing, logging, health management and scaling automatically.</li>
  <li><strong>KaaS (Kubernetes) users</strong> want the additional ~10% of configurability that a PaaS abstracts away—direct access to networking primitives, custom admission controllers, specialised storage classes and so on. They are willing to invest in the operational overhead that comes with that flexibility.</li>
</ul>



<p class="wp-block-paragraph">The convergence Koleno anticipated was at the platform level: Kubernetes becoming the shared runtime underneath Cloud Foundry, with PaaS ergonomics layered on top. The two platforms would not merge conceptually; rather, Cloud Foundry would become a higher-level abstraction over Kubernetes infrastructure.</p>



<h2 class="wp-block-heading">VMware&#8217;s Broader Acquisition Strategy at the Time</h2>



<p class="wp-block-paragraph">The Pivotal acquisition, if completed, would have followed a string of strategically coherent VMware acquisitions in the cloud-native space, including CloudHealth (cloud cost management), Heptio (Kubernetes tooling and expertise, founded by original Kubernetes creators) and Bitnami (application packaging). Acquiring Pivotal would have represented the largest and most strategic move in that sequence, adding a full commercial PaaS and a co-owned KaaS to VMware&#8217;s portfolio in a single transaction.</p>



<h2 class="wp-block-heading">What This Means for Engineering Teams Today</h2>



<p class="wp-block-paragraph">The 2019 VMware–Pivotal discussion remains relevant as a case study in platform strategy. The core engineering trade-offs it surfaced have not disappeared:</p>



<ul class="wp-block-list">
  <li>Kubernetes has become the de facto container orchestration standard, and Cloud Foundry&#8217;s own runtime now runs on top of it in both the open-source and commercial distributions.</li>
  <li>Platform consolidation under a single vendor can reduce integration complexity and simplify procurement, but it introduces vendor lock-in risks that engineering leaders must weigh.</li>
  <li>The choice between a highly opinionated PaaS and a flexible orchestration layer is still an active decision for many enterprises undertaking digital transformation programmes.</li>
  <li>VMware&#8217;s subsequent acquisition by Broadcom in 2023 added another layer of strategic uncertainty for teams running Tanzu (the product line that emerged from the VMware–Pivotal integration).</li>
</ul>



<p class="wp-block-paragraph">For DevOps and platform engineering teams evaluating their options, the underlying principle Koleno articulated in 2019 remains sound: the right platform depends on how much operational complexity your organisation is prepared to own, and whether that complexity delivers meaningful business value for your specific workloads.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio">
  <div class="wp-block-embed__wrapper">
    <iframe loading="lazy" width="675" height="379" src="https://www.youtube.com/embed/?list=PLTCuRW0ikUdMMoQp5eXPd7JE50_OoYZ01&amp;autoplay=0&amp;rel=1&amp;fs=1&amp;controls=1" title="YouTube player" allow="fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
  </div>
</figure>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/vmware-and-pivotal-what-would-a-merger-mean-for-the-cloud-foundry-kubernetes-debate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Microsoft Project Tardigrade: How Azure&#8217;s Self-Healing Resiliency Initiative Works</title>
		<link>https://www.bestdevops.com/microsoft-details-project-tardigrade-an-azure-resiliency-initiative/</link>
					<comments>https://www.bestdevops.com/microsoft-details-project-tardigrade-an-azure-resiliency-initiative/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Fri, 16 Aug 2019 05:54:39 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[Tardigrade]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=6993</guid>

					<description><![CDATA[Microsoft's Project Tardigrade brings multi-phase self-healing and VM state preservation to Azure, protecting virtual machines from kernel failures, firmware issues, and host-level outages without forcing reboots.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>Original reporting via <a href="https://www.neowin.net" rel="noopener">Neowin</a>. Source announcement by Azure CTO Mark Russinovich.</em></p>



<h2 class="wp-block-heading">What Is Project Tardigrade?</h2>



<p class="wp-block-paragraph">Microsoft named Project Tardigrade after the tardigrade — a microscopic animal famously capable of surviving extreme environmental stress. The name is fitting: the initiative is designed to make Azure virtual machines (VMs) similarly resilient against platform-level failures that would otherwise cause downtime or data loss for customers.</p>



<p class="wp-block-paragraph">Azure CTO Mark Russinovich first referenced the project at Microsoft Build 2019 and followed up with a detailed blog post in July 2019 explaining both the motivation and the technical approach. The initiative sits across multiple hardware and software layers of Azure&#8217;s cloud platform, prioritizing platform resiliency and high availability as first-class concerns rather than afterthoughts.</p>



<h2 class="wp-block-heading">The Core Problem Tardigrade Solves</h2>



<p class="wp-block-paragraph">Cloud infrastructure at Azure&#8217;s scale means that host server failures — including kernel panics, firmware faults, and unresponsive host services — are an operational reality. Traditionally, recovering from such failures often required rebooting the physical host, which disrupted every VM running on that server.</p>



<p class="wp-block-paragraph">Project Tardigrade introduces self-healing mechanisms designed to:</p>



<ul class="wp-block-list">
<li>Preserve the in-memory state of running customer VMs during host-level recovery operations.</li>
<li>Initiate rapid recovery with minimal or zero impact to customer workloads in the best-case scenario.</li>
<li>Diagnose and root-cause the underlying failure to prevent it from recurring.</li>
<li>Avoid forcing VM reboots in cases where the host OS can be reset while VMs are suspended briefly.</li>
</ul>



<h2 class="wp-block-heading">The Three-Phase Recovery Workflow</h2>



<p class="wp-block-paragraph">Russinovich described a concrete example recovery workflow that triggers when a host server encounters an operational failure. It proceeds through up to three escalating phases, stopping as early as possible to minimize customer impact.</p>



<h3 class="wp-block-heading">Phase 1 — Service Recycling (Zero Customer Impact)</h3>



<p class="wp-block-paragraph">The first response is the lightest touch: all services running on the affected host are recycled. Running customer VMs are not impacted at this stage. If the faulted service restarts successfully, recovery is complete and no further action is needed. Only if the service fails to restart does the workflow escalate to Phase 2.</p>



<h3 class="wp-block-heading">Phase 2 — Diagnostics and Root Cause Analysis</h3>



<p class="wp-block-paragraph">Before attempting any more disruptive remediation, Azure&#8217;s diagnostics service collects all relevant logs and memory dumps from the host in a systematic way. This comprehensive data capture serves two purposes: it enables Microsoft engineers to root-cause the failure that prevented Phase 1 from succeeding, and it informs future improvements to prevent the same failure class from recurring across the fleet.</p>



<h3 class="wp-block-heading">Phase 3 — OS Reset with VM State Preservation</h3>



<p class="wp-block-paragraph">If Phases 1 and 2 cannot resolve the problem, Tardigrade performs an OS-level reset of the host while keeping customer VMs alive. The process works as follows:</p>



<ol class="wp-block-list">
<li>The current state of every VM running on the host is saved to RAM.</li>
<li>The host operating system begins resetting to a healthy state.</li>
<li>During the reset, running applications inside VMs experience a brief CPU suspension — a short &#8220;freeze&#8221; comparable to a momentary network interruption that retry logic handles transparently.</li>
<li>Once the host OS has successfully reset, each VM reads its preserved state from RAM and resumes normal operation.</li>
</ol>



<p class="wp-block-paragraph">The critical outcome of Phase 3 is that VM reboots are avoided entirely. Customer workloads resume where they left off rather than restarting from scratch.</p>



<h2 class="wp-block-heading">What Failure Scenarios Does Tardigrade Cover?</h2>



<p class="wp-block-paragraph">The three-phase workflow described above addresses host service failures. According to Russinovich&#8217;s post, Tardigrade&#8217;s scope extends to a range of critical failure types including:</p>



<ul class="wp-block-list">
<li>Kernel-level failures on the host</li>
<li>Firmware issues affecting host hardware</li>
<li>Unanticipated platform failures that would ordinarily force a full host restart</li>
</ul>



<p class="wp-block-paragraph">At the time of Russinovich&#8217;s announcement, additional host failure scenarios were being tested to expand the set of recoverable conditions and recovery paths available to the platform.</p>



<h2 class="wp-block-heading">Machine Learning for Predictive and Assisted Recovery</h2>



<p class="wp-block-paragraph">Beyond reactive self-healing, Microsoft outlined a roadmap for making Tardigrade proactive. Two machine learning workstreams were described as planned or in development at the time:</p>



<ul class="wp-block-list">
<li><strong>Anomaly detection:</strong> ML models monitoring host-side resource utilization patterns to identify abnormal behavior before a failure occurs, enabling pre-emptive action.</li>
<li><strong>Repair assistance:</strong> Separate ML algorithms planned to assist in automated repair tasks, reducing the need for manual intervention in recovery workflows.</li>
</ul>



<h2 class="wp-block-heading">Why This Matters for DevOps and Platform Engineers</h2>



<p class="wp-block-paragraph">For teams running production workloads on Azure, Project Tardigrade has practical implications for how you design and operate services:</p>



<ul class="wp-block-list">
<li><strong>Reduced reliance on application-level fault tolerance for host failures:</strong> While application resilience patterns (retries, circuit breakers, multi-region deployment) remain important, Tardigrade reduces the blast radius of infrastructure-level events that were previously unavoidable.</li>
<li><strong>Shorter and less frequent disruptions:</strong> The Phase 3 freeze experience is described as analogous to a brief network blip — something most well-written applications already handle. This is a significantly better outcome than a full VM reboot.</li>
<li><strong>Improved SLA foundations:</strong> Platform-layer self-healing mechanisms underpin the availability commitments Microsoft makes in Azure SLAs. Improvements here flow directly into the reliability you can promise your own customers.</li>
<li><strong>Operational transparency:</strong> The emphasis on root-cause diagnostics in Phase 2 reflects a platform-level commitment to understanding and eliminating recurring failure classes rather than just masking them.</li>
</ul>



<h2 class="wp-block-heading">Context: Azure&#8217;s Broader Reliability Push</h2>



<p class="wp-block-paragraph">Project Tardigrade was announced as part of a wider Microsoft effort to improve Azure reliability that was underway throughout 2019. Russinovich&#8217;s July blog post highlighted several concurrent initiatives. At the same time, Microsoft was expanding Azure&#8217;s service catalog with new reservation and pre-purchase options and rolling additional security features for Azure Files into general availability.</p>



<p class="wp-block-paragraph">The naming choice — tardigrades are among the most stress-tolerant organisms known, surviving vacuum, radiation, and extreme temperatures — signals the engineering aspiration clearly: a cloud platform that continues operating correctly even when its underlying hardware and software components fail in unexpected ways.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/microsoft-details-project-tardigrade-an-azure-resiliency-initiative/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Writing GitHub Webhooks with Bash and Apache CGI</title>
		<link>https://www.bestdevops.com/writing-github-web-hooks-with-bash/</link>
					<comments>https://www.bestdevops.com/writing-github-web-hooks-with-bash/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Thu, 08 Aug 2019 05:56:54 +0000</pubDate>
				<category><![CDATA[GitHub]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[Web Hooks]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=6807</guid>

					<description><![CDATA[Learn how to build GitHub webhooks using Bash shell scripts served through Apache's mod_cgi. This guide covers server setup, CGI basics, JSON parsing with jq, and two practical webhook examples: a repository backup hook and a build-and-package hook.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">A GitHub webhook fires when a specific event occurs in your repository — such as a push — and delivers an HTTP POST payload to a URL you control. This makes webhooks a powerful primitive for automating DevOps workflows: triggering backups, running builds, or kicking off deployments without a heavyweight CI platform.</p>



<p class="wp-block-paragraph">This article walks through setting up a webhook receiver from scratch: configuring Apache with <code>mod_cgi</code>, writing CGI-compatible Bash scripts, parsing the GitHub JSON payload with <code>jq</code>, and building two practical hooks — a simple repository backup and a build-and-package hook.</p>



<h2 class="wp-block-heading">How GitHub Webhooks Work</h2>



<p class="wp-block-paragraph">When a webhook-triggering event occurs (for example, a <code>push</code> to a repository), GitHub sends an HTTP POST request to the URL you have registered in the repository&#8217;s webhook settings. The request body contains a JSON payload describing the event — including details about the repository, the commits pushed, and the actor who triggered it.</p>



<p class="wp-block-paragraph">Your webhook endpoint must:</p>



<ul class="wp-block-list">
<li>Accept an HTTP POST request.</li>
<li>Read and parse the JSON body.</li>
<li>Return a valid HTTP response (typically <code>200 OK</code>) quickly, before GitHub times out the request.</li>
<li>Perform whatever automation logic you need.</li>
</ul>



<h2 class="wp-block-heading">Preparing Apache with mod_cgi</h2>



<p class="wp-block-paragraph">Apache&#8217;s <code>mod_cgi</code> module lets the web server execute server-side scripts and return their standard output as the HTTP response. It is available in the default repositories of all major Linux distributions.</p>



<h3 class="wp-block-heading">Enable mod_cgi</h3>



<p class="wp-block-paragraph">On Debian/Ubuntu-based systems, enable the module with:</p>


<pre class="wp-block-code"><span><code class="hljs">sudo a2enmod cgi
sudo systemctl restart apache2</code></span></pre>


<p class="wp-block-paragraph">On RHEL/CentOS-based systems, <code>mod_cgi</code> is typically compiled in. Confirm it is loaded in your Apache configuration and restart <code>httpd</code> if you make changes.</p>



<h3 class="wp-block-heading">Create the Directory Structure</h3>



<p class="wp-block-paragraph">Use <code>/opt/hooks</code> as the root for all webhook-related files. Inside it, create two subdirectories:</p>



<ul class="wp-block-list">
<li><code>/opt/hooks/html</code> — the virtual host document root.</li>
<li><code>/opt/hooks/cgi-bin</code> — where the Bash webhook scripts live.</li>
</ul>


<pre class="wp-block-code"><span><code class="hljs">sudo mkdir -p /opt/hooks/html /opt/hooks/cgi-bin</code></span></pre>


<h3 class="wp-block-heading">Set Directory Ownership</h3>



<p class="wp-block-paragraph">Apache must be able to read and execute files in these directories. Find the user Apache is running as:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">ps -e -o %U%c | grep <span class="hljs-string">'apache2\|httpd'</span></code></span></pre>


<p class="wp-block-paragraph">The first column shows the username (commonly <code>www-data</code>, <code>apache</code>, or <code>nobody</code>). Grant ownership of the hooks directory tree to that user:</p>


<pre class="wp-block-code"><span><code class="hljs">sudo chown -R www-data /opt/hooks</code></span></pre>


<p class="wp-block-paragraph">Repeat this command any time you add new files or subdirectories under <code>/opt/hooks</code>.</p>



<h3 class="wp-block-heading">Configure the Virtual Host</h3>



<p class="wp-block-paragraph">Add the following virtual host block to your Apache configuration (for example, in <code>/etc/apache2/sites-available/hooks.conf</code> on Debian/Ubuntu, or a file in <code>/etc/httpd/conf.d/</code> on RHEL-based systems). Replace <code>SERVERNAME</code> with the hostname or IP address that GitHub will POST to:</p>


<pre class="wp-block-code"><span><code class="hljs language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">VirtualHost</span> *<span class="hljs-attr">:80</span>&gt;</span>
  ServerName SERVERNAME
  ScriptAlias "/cgi-bin" "/opt/hooks/cgi-bin"
  DocumentRoot /opt/hooks/html
<span class="hljs-tag">&lt;/<span class="hljs-name">VirtualHost</span>&gt;</span></code></span></pre>


<p class="wp-block-paragraph">Key directives:</p>



<ul class="wp-block-list">
<li><strong>DocumentRoot</strong> — serves static files from <code>/opt/hooks/html</code>.</li>
<li><strong>ScriptAlias</strong> — maps the URL path <code>/cgi-bin</code> to <code>/opt/hooks/cgi-bin</code> on disk, and instructs <code>mod_cgi</code> to execute any scripts found there.</li>
</ul>



<p class="wp-block-paragraph">After saving, enable the site and reload Apache:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-tag">sudo</span> <span class="hljs-selector-tag">a2ensite</span> <span class="hljs-selector-tag">hooks</span><span class="hljs-selector-class">.conf</span>
<span class="hljs-selector-tag">sudo</span> <span class="hljs-selector-tag">systemctl</span> <span class="hljs-selector-tag">reload</span> <span class="hljs-selector-tag">apache2</span></code></span></pre>


<p class="wp-block-paragraph"><strong>Note:</strong> This example uses plain HTTP on port 80 for clarity. In production you should configure TLS (HTTPS) and use GitHub&#8217;s webhook secret to verify request authenticity.</p>



<h2 class="wp-block-heading">CGI Basics: HTTP Requests and Bash Scripts</h2>



<p class="wp-block-paragraph">CGI (Common Gateway Interface) is a standard for web servers to execute external programs and return their output as an HTTP response. When Apache receives a request for a path covered by <code>ScriptAlias</code>, it executes the corresponding script and sends its standard output back to the client as the HTTP response body — headers included.</p>



<p class="wp-block-paragraph">Here is an example of a GitHub webhook POST request and the expected response:</p>



<h3 class="wp-block-heading">Example Request</h3>


<pre class="wp-block-code"><span><code class="hljs language-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/cgi-bin/clone.cgi</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: hooks.example.com
<span class="hljs-attribute">Content-Length</span>: 86

{"repository":{"name":"webhook-test","url":"https://github.com/user/webhook-test"}}</code></span></pre>


<h3 class="wp-block-heading">Example Response</h3>


<pre class="wp-block-code"><span><code class="hljs language-http">HTTP/1.1 <span class="hljs-number">200</span> OK
<span class="hljs-attribute">Content-Type</span>: text/json
<span class="hljs-attribute">Content-Length</span>: 18

{"success":"true"}</code></span></pre>


<p class="wp-block-paragraph">A minimal Bash CGI script that illustrates this pattern looks like this:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment">#!/bin/bash</span>

<span class="hljs-comment"># Read the POST body from standard input</span>
JSONPOST=<span class="hljs-string">"$(cat -)"</span>

<span class="hljs-comment"># Output HTTP response headers followed by a blank line</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">"Content-Type: text/json"</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">""</span>

<span class="hljs-comment"># Output the response body</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">'{"success":"true"}'</span></code></span></pre>


<p class="wp-block-paragraph">Two things to note:</p>



<ul class="wp-block-list">
<li>The POST body arrives on <strong>standard input</strong>. <code>cat -</code> reads it into a variable.</li>
<li>The script must output at least one HTTP header (<code>Content-Type</code>) followed by a blank line before any response body. Apache handles the status line itself.</li>
</ul>



<p class="wp-block-paragraph">Scripts must be executable. Set the permission bit after creating each script:</p>


<pre class="wp-block-code"><span><code class="hljs">chmod +x /opt/hooks/cgi-bin/myhook.cgi</code></span></pre>


<h2 class="wp-block-heading">Parsing the GitHub JSON Payload with jq</h2>



<p class="wp-block-paragraph">GitHub&#8217;s push event payload is a JSON object. The most practical tool for extracting fields from JSON in a Bash script is <code>jq</code>, available in the default repositories of all major Linux distributions.</p>



<p class="wp-block-paragraph">Consider this excerpt from a real push payload:</p>


<pre class="wp-block-code"><span><code class="hljs language-json">{
  <span class="hljs-attr">"repository"</span>: {
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"webhook-test"</span>,
    <span class="hljs-attr">"git_url"</span>: <span class="hljs-string">"git://github.com/user/webhook-test.git"</span>,
    <span class="hljs-attr">"ssh_url"</span>: <span class="hljs-string">"git@github.com:user/webhook-test.git"</span>,
    <span class="hljs-attr">"clone_url"</span>: <span class="hljs-string">"https://github.com/user/webhook-test.git"</span>
  },
  <span class="hljs-attr">"commits"</span>: &#91;
    {
      <span class="hljs-attr">"timestamp"</span>: <span class="hljs-string">"2019-06-11T02:44:52Z"</span>
    }
  ]
}</code></span></pre>


<p class="wp-block-paragraph">To extract the HTTPS clone URL, pipe the JSON string into <code>jq</code> using dot notation:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">jq -r <span class="hljs-string">'.repository.clone_url'</span> &lt;&lt;&lt; <span class="hljs-string">"$POSTJSON"</span></code></span></pre>


<p class="wp-block-paragraph">The <code>-r</code> flag outputs raw strings without surrounding quotes, which makes it easy to assign the result to a shell variable:</p>


<pre class="wp-block-code"><span><code class="hljs language-php">REPOURL=<span class="hljs-string">"$(jq -r '.repository.clone_url' &lt;&lt;&lt; "</span>$POSTJSON<span class="hljs-string">")"</span>
REPONAME=<span class="hljs-string">"$(jq -r '.repository.name' &lt;&lt;&lt; "</span>$POSTJSON<span class="hljs-string">")"</span></code></span></pre>


<h2 class="wp-block-heading">Hook #1: Simple Repository Backup</h2>



<p class="wp-block-paragraph">This hook clones a repository to the server the first time a push event fires, and runs <code>git pull</code> on subsequent pushes to keep the local copy current. Save it as <code>/opt/hooks/cgi-bin/backup.cgi</code> and make it executable.</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment">#!/bin/bash</span>

<span class="hljs-comment"># Directory where repository clones are stored</span>
REPODIR=<span class="hljs-string">"/opt/hooks/html/repos"</span>

<span class="hljs-comment"># Helper: emit a JSON result object based on the exit code passed as $1</span>
json_resp() {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'{"result":"'</span><span class="hljs-string">"$(&#91; $1 -eq 0 ] &amp;&amp; echo "</span>success<span class="hljs-string">" || echo "</span>failure<span class="hljs-string">")"</span><span class="hljs-string">'"}'</span>
}

<span class="hljs-comment"># Read GitHub POST payload from stdin</span>
POSTJSON=<span class="hljs-string">"$(cat -)"</span>

<span class="hljs-comment"># Parse the fields we need</span>
REPOURL=<span class="hljs-string">"$(jq -r '.repository.clone_url' &lt;&lt;&lt; "</span>$POSTJSON<span class="hljs-string">")"</span>
REPONAME=<span class="hljs-string">"$(jq -r '.repository.name' &lt;&lt;&lt; "</span>$POSTJSON<span class="hljs-string">")"</span>

<span class="hljs-comment"># Output HTTP response headers</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">"Content-Type: text/json"</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">""</span>

<span class="hljs-comment"># Clone or update</span>
<span class="hljs-keyword">if</span> &#91; -d <span class="hljs-string">"$REPODIR/$REPONAME"</span> ]; then
    <span class="hljs-comment"># Repository already exists — pull latest changes</span>
    pushd . &gt; /dev/<span class="hljs-keyword">null</span>
    cd <span class="hljs-string">"$REPODIR/$REPONAME"</span>
    git pull
    json_resp $?
    popd &gt; /dev/<span class="hljs-keyword">null</span>
<span class="hljs-keyword">else</span>
    <span class="hljs-comment"># First run — clone the repository</span>
    mkdir -p <span class="hljs-string">"$REPODIR/$REPONAME"</span>
    git <span class="hljs-keyword">clone</span> <span class="hljs-string">"$REPOURL"</span> <span class="hljs-string">"$REPODIR/$REPONAME"</span>
    json_resp $?
fi</code></span></pre>


<p class="wp-block-paragraph">How it works:</p>



<ul class="wp-block-list">
<li><strong>REPODIR</strong> — the parent directory for all cloned repositories.</li>
<li><strong>json_resp</strong> — a helper function that converts a shell exit code (0 = success, non-zero = failure) into a JSON response body.</li>
<li><strong>POSTJSON</strong> — the raw GitHub payload, captured from standard input.</li>
<li>The <code>if</code> block checks whether a local clone already exists. If it does, <code>git pull</code> updates it. If not, <code>git clone</code> creates it.</li>
<li>The exit code of the git command is forwarded to <code>json_resp</code>, so GitHub receives a meaningful success or failure indicator.</li>
</ul>



<h2 class="wp-block-heading">Hook #2: Build and Package</h2>



<p class="wp-block-paragraph">This hook extends the backup concept: after cloning or pulling, it runs <code>make</code> to build the project and packages the output into a timestamped <code>.tar.gz</code> archive served from the web root. This is a lightweight foundation for a CI/CD pipeline when a full CI platform is not available or desired.</p>



<p class="wp-block-paragraph">The hook assumes the repository&#8217;s <code>Makefile</code> follows two conventions:</p>



<ul class="wp-block-list">
<li>Running <code>make</code> places build artifacts into a <code>build/</code> subdirectory inside the repository.</li>
<li>Running <code>make clean</code> removes the <code>build/</code> subdirectory.</li>
</ul>



<p class="wp-block-paragraph">Save this as <code>/opt/hooks/cgi-bin/build.cgi</code> and make it executable:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment">#!/bin/bash</span>

WEBROOT=<span class="hljs-string">"/opt/hooks/html/archive"</span>
REPODIR=<span class="hljs-string">"/opt/hooks/html/repos"</span>
WEBURL=<span class="hljs-string">"http://hooks.example.com/archive"</span>

<span class="hljs-comment"># Emit a JSON response with result and, on success, the archive URL</span>
json_package() {
    local exit_code=$<span class="hljs-number">1</span>
    local url=$<span class="hljs-number">2</span>
    <span class="hljs-keyword">if</span> &#91; <span class="hljs-string">"$exit_code"</span> -eq <span class="hljs-number">0</span> ]; then
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"{\"result\":\"success\",\"url\":\"$url\"}"</span>
    <span class="hljs-keyword">else</span>
        <span class="hljs-keyword">echo</span> <span class="hljs-string">'{"result":"package failure"}'</span>
    fi
}

<span class="hljs-comment"># Run make and package the build output</span>
run_make() {
    local clone_exit=$<span class="hljs-number">1</span>

    <span class="hljs-comment"># Clean any previous build</span>
    &#91; -d <span class="hljs-string">"$REPODIR/$REPONAME/build"</span> ] &amp;&amp; make -s -C <span class="hljs-string">"$REPODIR/$REPONAME"</span> clean

    <span class="hljs-keyword">if</span> &#91; <span class="hljs-string">"$clone_exit"</span> -eq <span class="hljs-number">0</span> ]; then
        make -s -C <span class="hljs-string">"$REPODIR/$REPONAME"</span>
        <span class="hljs-keyword">if</span> &#91; -d <span class="hljs-string">"$REPODIR/$REPONAME/build"</span> ]; then
            FILENAME=<span class="hljs-string">"$REPONAME-$COMMITTIME.tar.gz"</span>
            tar -czf <span class="hljs-string">"$WEBROOT/$FILENAME"</span> -C <span class="hljs-string">"$REPODIR/$REPONAME/build"</span> .
            json_package <span class="hljs-string">"$?"</span> <span class="hljs-string">"$WEBURL/$FILENAME"</span>
        <span class="hljs-keyword">else</span>
            <span class="hljs-keyword">echo</span> <span class="hljs-string">'{"result":"build failure"}'</span>
        fi
    <span class="hljs-keyword">else</span>
        <span class="hljs-keyword">echo</span> <span class="hljs-string">'{"result":"clone/pull failure"}'</span>
    fi
}

<span class="hljs-comment"># Read GitHub POST payload</span>
POSTJSON=<span class="hljs-string">"$(cat -)"</span>

<span class="hljs-comment"># Parse required fields</span>
REPOURL=<span class="hljs-string">"$(jq -r '.repository.clone_url' &lt;&lt;&lt; "</span>$POSTJSON<span class="hljs-string">")"</span>
REPONAME=<span class="hljs-string">"$(jq -r '.repository.name' &lt;&lt;&lt; "</span>$POSTJSON<span class="hljs-string">")"</span>
COMMITTIME=<span class="hljs-string">"$(date -d "</span>$(jq -r <span class="hljs-string">'.commits&#91;0].timestamp'</span> &lt;&lt;&lt; <span class="hljs-string">"$POSTJSON"</span>)<span class="hljs-string">" +"</span>%m-%d-%YT%H-%M-%S<span class="hljs-string">")"</span>

<span class="hljs-comment"># Ensure archive directory exists</span>
mkdir -p <span class="hljs-string">"$WEBROOT"</span>

<span class="hljs-comment"># Output HTTP response headers</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">"Content-Type: text/json"</span>
<span class="hljs-keyword">echo</span> <span class="hljs-string">""</span>

<span class="hljs-comment"># Clone or update, then build</span>
<span class="hljs-keyword">if</span> &#91; -d <span class="hljs-string">"$REPODIR/$REPONAME"</span> ]; then
    pushd . &gt; /dev/<span class="hljs-keyword">null</span>
    cd <span class="hljs-string">"$REPODIR/$REPONAME"</span>
    git pull
    run_make $?
    popd &gt; /dev/<span class="hljs-keyword">null</span>
<span class="hljs-keyword">else</span>
    mkdir -p <span class="hljs-string">"$REPODIR/$REPONAME"</span>
    git <span class="hljs-keyword">clone</span> <span class="hljs-string">"$REPOURL"</span> <span class="hljs-string">"$REPODIR/$REPONAME"</span>
    run_make $?
fi</code></span></pre>


<p class="wp-block-paragraph">Key points:</p>



<ul class="wp-block-list">
<li><strong>COMMITTIME</strong> — the timestamp from the first commit in the push payload, reformatted with <code>date</code> so it contains no spaces or colons that would be invalid in a filename.</li>
<li><strong>run_make</strong> — receives the exit code of the preceding <code>git clone</code> or <code>git pull</code>. If that succeeded, it runs <code>make</code>. If a <code>build/</code> directory appears, it archives its contents with <code>tar</code> and returns a JSON object containing the result and the download URL.</li>
<li><strong>json_package</strong> — on success returns both a <code>result</code> and a <code>url</code> attribute so the caller can locate the artifact immediately.</li>
</ul>



<h2 class="wp-block-heading">Registering the Webhook in GitHub</h2>



<p class="wp-block-paragraph">Once your server is reachable from the internet (or from GitHub&#8217;s webhook IP ranges), register the endpoint in your repository:</p>



<ol class="wp-block-list">
<li>Go to your repository on GitHub → <strong>Settings</strong> → <strong>Webhooks</strong> → <strong>Add webhook</strong>.</li>
<li>Set <strong>Payload URL</strong> to <code>http://your-server/cgi-bin/backup.cgi</code> (or <code>build.cgi</code>).</li>
<li>Set <strong>Content type</strong> to <code>application/json</code>.</li>
<li>Choose the <strong>Just the push event</strong> trigger.</li>
<li>Click <strong>Add webhook</strong>. GitHub will send a ping event; check the delivery log to confirm your server responded with <code>200 OK</code>.</li>
</ol>



<h2 class="wp-block-heading">Security Considerations</h2>



<p class="wp-block-paragraph">The examples above are intentionally minimal. Before deploying a webhook receiver to a production or internet-facing server, address the following:</p>



<ul class="wp-block-list">
<li><strong>Use HTTPS.</strong> Configure TLS on the virtual host so the payload is encrypted in transit.</li>
<li><strong>Validate the GitHub signature.</strong> GitHub can sign each request with a shared secret using HMAC-SHA256. Your script should verify the <code>X-Hub-Signature-256</code> header before acting on the payload. Without this check, any party that can reach your endpoint can trigger your automation.</li>
<li><strong>Quote all variables.</strong> The examples above use quoted variables (<code>"$REPONAME"</code>) to guard against word splitting. Double-check this in your own scripts before running them with Apache&#8217;s process privileges.</li>
<li><strong>Limit Apache process permissions.</strong> The Apache user should have only the minimum filesystem permissions required.</li>
<li><strong>Sanitize parsed values.</strong> Values extracted from the JSON payload should be validated before being used in shell commands to prevent command injection.</li>
</ul>



<h2 class="wp-block-heading">Summary</h2>



<p class="wp-block-paragraph">GitHub webhooks, combined with Apache <code>mod_cgi</code> and Bash, provide a lightweight and flexible way to automate repository-driven workflows without a dedicated CI/CD platform. The pattern is straightforward:</p>



<ol class="wp-block-list">
<li>Configure Apache with <code>mod_cgi</code> and a <code>ScriptAlias</code> pointing to your scripts directory.</li>
<li>Write a Bash script that reads <code>stdin</code> (the POST body), outputs HTTP headers, performs the desired action, and returns a JSON result.</li>
<li>Use <code>jq</code> to extract fields from the GitHub payload.</li>
<li>Register the endpoint URL as a webhook in GitHub&#8217;s repository settings.</li>
</ol>



<p class="wp-block-paragraph">From here you can extend either hook — adding Slack notifications, deploying to remote servers over SSH, running test suites, or triggering package uploads — all within Bash and standard Unix tooling.</p>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li><a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/about-webhooks">GitHub Webhooks Documentation</a></li>
<li><a href="https://httpd.apache.org/docs/current/mod/mod_cgi.html">Apache mod_cgi Documentation</a></li>
<li><a href="https://httpd.apache.org/docs/current/mod/mod_alias.html">Apache mod_alias Documentation</a> (covers the <code>ScriptAlias</code> directive)</li>
<li><a href="https://stedolan.github.io/jq/manual/">jq Manual</a></li>
</ul>



<p class="wp-block-paragraph"><em>This article is based on a piece originally written by Andy Carlson for Linux Journal.</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/writing-github-web-hooks-with-bash/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>DeepCode: How AI-Powered Code Reviews Learn from GitHub to Catch Bugs Faster</title>
		<link>https://www.bestdevops.com/deepcode-learns-from-github-project-data-to-give-developers-ai-powered-code-reviews/</link>
					<comments>https://www.bestdevops.com/deepcode-learns-from-github-project-data-to-give-developers-ai-powered-code-reviews/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Wed, 07 Aug 2019 06:20:14 +0000</pubDate>
				<category><![CDATA[GitHub]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Developers]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[Software]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=6787</guid>

					<description><![CDATA[Swiss startup DeepCode uses machine learning trained on billions of lines of open source code to automate code reviews, flag vulnerabilities, and help developers ship cleaner software faster.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on reporting originally published by VentureBeat in August 2019, covering DeepCode&#8217;s $4 million seed round and the technology behind its AI-driven code review platform.</em></p>



<h2 class="wp-block-heading">Why Automated Code Review Matters</h2>



<p class="wp-block-paragraph">As software becomes central to virtually every industry, the volume of code that development teams must produce, review, and maintain has grown enormously. More code means more opportunity for bugs, security vulnerabilities, and technical debt to accumulate — and traditional code review processes struggle to keep pace.</p>



<p class="wp-block-paragraph">Code review sits upstream of software testing. Where testing examines how software behaves from the outside, code review inspects the structure and logic of the source itself, ideally before changes are merged or deployed. In practice, this involves developers, peers, and managers collaborating to catch obvious errors early — a process that scales poorly as codebases grow.</p>



<p class="wp-block-paragraph">Static analysis tools such as Lint have long been available to help, but they tend to focus on a narrow band of stylistic and formatting issues rather than deeper logic errors or security flaws. That gap is what Swiss startup DeepCode set out to close.</p>



<h2 class="wp-block-heading">What DeepCode Does</h2>



<p class="wp-block-paragraph">DeepCode applies machine learning to the code review problem. Its models are trained on billions of lines of code drawn from public open source repositories — primarily GitHub — learning patterns from real-world projects, including earlier versions of files and the subsequent fixes that developers applied.</p>



<p class="wp-block-paragraph">This approach allows DeepCode to go beyond syntax checking. According to cofounder and CEO Boris Paskalev, the system attempts to infer the <em>intent</em> behind a piece of code, not just whether it compiles or conforms to style guidelines. That means it can flag more serious issues such as:</p>



<ul class="wp-block-list">
<li><strong>Cross-site scripting (XSS) vulnerabilities</strong></li>
<li><strong>SQL injection risks</strong></li>
<li><strong>Logic errors and known bug patterns</strong></li>
<li><strong>Security anti-patterns learned from open source fixes</strong></li>
</ul>



<p class="wp-block-paragraph">The training pipeline works by examining how bugs appeared in historical versions of code and how they were subsequently resolved. This creates what DeepCode describes as a live knowledge base of known bugs and their solutions, which the model applies when reviewing new code submissions.</p>



<p class="wp-block-paragraph">Beyond pattern matching on known issues, DeepCode also uses predictive and inferential algorithms to surface problems in code that may not have been explicitly fixed in any training sample — extrapolating from what it has learned to flag novel risks.</p>



<h2 class="wp-block-heading">How It Integrates into a Development Workflow</h2>



<p class="wp-block-paragraph">DeepCode integrates directly with version control platforms. Developers connect it to their GitHub or Bitbucket accounts for cloud-hosted projects, and the tool reviews each commit automatically, flagging potential issues as part of the normal pull request flow. GitLab is supported for on-premises deployments.</p>



<p class="wp-block-paragraph">For teams that want deeper integration, DeepCode also exposes an API, allowing larger enterprises to embed its review capabilities into custom internal tooling. At the time of this reporting (2019), the company was also working on its first IDE plugin, which would bring inline suggestions directly into the developer&#8217;s editor.</p>



<p class="wp-block-paragraph">The workflow, in summary:</p>



<ol class="wp-block-list">
<li>Developer commits code to a connected repository.</li>
<li>DeepCode reviews each commit automatically.</li>
<li>Flagged issues are surfaced in the pull request interface or via API.</li>
<li>Developers receive suggested fixes, not just error locations.</li>
</ol>



<h2 class="wp-block-heading">Claimed Accuracy and Time Savings</h2>



<p class="wp-block-paragraph">The obvious question for any automated review tool is: how accurate is it? Paskalev stated that developers typically spend around 30% of their time finding and fixing bugs, and that DeepCode can save roughly half of that — representing a meaningful reduction in overhead for active development teams.</p>



<p class="wp-block-paragraph">The argument for the machine learning approach is scale: because DeepCode learns from the global open source community rather than any single team&#8217;s experience, it can in principle identify a broader range of issues than any individual reviewer or small group of reviewers. That said, no automated tool achieves perfect accuracy, and human review remains part of the process for edge cases and novel code patterns.</p>



<h2 class="wp-block-heading">Background: ETH Zurich Spin-Out with Deep Research Roots</h2>



<p class="wp-block-paragraph">DeepCode was founded in 2016 as a spin-out from ETH Zurich (Swiss Federal Institute of Technology). The founding team includes CTO Veselin Raychev, formerly a software engineer at Google and a PhD researcher at ETH, and adviser Martin Vechev, a professor at ETH whose research group focuses on reliable and secure software systems.</p>



<p class="wp-block-paragraph">That academic lineage gives the company a credible foundation in program analysis and formal methods — fields that underpin serious static and dynamic analysis tooling.</p>



<h2 class="wp-block-heading">Funding, Pricing, and Language Support</h2>



<p class="wp-block-paragraph">In August 2019, DeepCode announced a $4 million seed round led by Earlybird, with participation from 3VC and Btov Partners. The company had previously raised $1 million in an earlier seed round.</p>



<p class="wp-block-paragraph">Alongside the funding announcement, DeepCode revised its pricing model:</p>



<ul class="wp-block-list">
<li><strong>Free</strong> for open source projects and educational use</li>
<li><strong>Free</strong> for enterprise teams of up to 30 developers</li>
<li><strong>$20 per developer per month</strong> for cloud deployments beyond the free tier</li>
<li><strong>$50 per developer per month</strong> for on-premises deployments</li>
</ul>



<p class="wp-block-paragraph">At the time, DeepCode supported Java, JavaScript, and Python, with plans to expand to C#, PHP, and C/C++ using the new funding. Known open source users of the platform included Embark Framework, the European Environment Agency (EEA), and PyMedusa.</p>



<h2 class="wp-block-heading">Context: The Broader AI Code Review Market</h2>



<p class="wp-block-paragraph">DeepCode was operating in a market that was attracting significant investment. The automated software testing market was estimated at $8.5 billion in 2018, with projections for continued growth. Alongside testing tools such as Functionize, Testim, and Mabl, code analysis and review was emerging as a distinct and investable category.</p>



<p class="wp-block-paragraph">The broader context included Microsoft&#8217;s $7.5 billion acquisition of GitHub and significant venture funding for GitLab — signals that the infrastructure supporting software development workflows had become strategically valuable at the enterprise level.</p>



<p class="wp-block-paragraph"><em>Note: DeepCode was subsequently acquired by Snyk in 2020. Readers researching this technology today should look into Snyk Code, which incorporates the DeepCode engine, for current capabilities and pricing.</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/deepcode-learns-from-github-project-data-to-give-developers-ai-powered-code-reviews/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Use a Hybrid DevOps Approach in IT Project Management</title>
		<link>https://www.bestdevops.com/how-to-use-a-hybrid-devops-approach-in-project-management/</link>
					<comments>https://www.bestdevops.com/how-to-use-a-hybrid-devops-approach-in-project-management/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Sat, 03 Aug 2019 10:53:11 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[approach]]></category>
		<category><![CDATA[department]]></category>
		<category><![CDATA[hybrid]]></category>
		<category><![CDATA[project]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=6676</guid>

					<description><![CDATA[Learn how to blend DevOps collaboration with traditional project management accountability — keeping task handoffs and traceability while gaining the speed and teamwork that DevOps enables.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on a post originally sourced from TechRepublic. The editorial content below has been substantially rewritten and expanded for a DevOps engineering audience.</em></p>



<h2 class="wp-block-heading">The Problem: Waterfall Accountability vs. DevOps Agility</h2>



<p class="wp-block-paragraph">In traditional IT project management, <strong>handoffs</strong> are the formal transfer of a task or deliverable from one individual, team, or department to the next. In waterfall-style projects, these handoffs serve two critical functions:</p>



<ul class="wp-block-list">
<li><strong>Traceability:</strong> They create a clear record of when work moved between stages.</li>
<li><strong>Accountability:</strong> They peg responsibility to a named individual or function at each stage.</li>
</ul>



<p class="wp-block-paragraph">Project managers rely on these handoffs to assess progress, identify blockers, and report status to stakeholders. Without them, it becomes difficult to answer basic questions: Who owns this task right now? Is it done? What is blocking it?</p>



<p class="wp-block-paragraph">DevOps, by design, challenges this model. Cross-functional teams collaborate continuously across requirements, development, QA, and deployment — often without formal handoffs between distinct roles or departments. This fluidity accelerates delivery, but it can also obscure ownership and make it harder for a project manager to assess completion or readiness for production.</p>



<p class="wp-block-paragraph">If you are an IT project manager moving from waterfall to DevOps, the key question is: <strong>What do you keep, and what do you leave behind?</strong></p>



<h2 class="wp-block-heading">The Case for a Hybrid Approach</h2>



<p class="wp-block-paragraph">Rather than treating DevOps and traditional project management as mutually exclusive, a hybrid model lets you retain what works best from each:</p>



<ul class="wp-block-list">
<li><strong>From DevOps:</strong> Collaborative, cross-functional teams; continuous feedback loops; flexibility to incorporate change mid-project.</li>
<li><strong>From waterfall:</strong> Explicit task ownership; tracked handoffs; a defined endpoint that marks the transition to production.</li>
</ul>



<p class="wp-block-paragraph">The result is a model where teams move fast and collaborate openly, but where a project manager can still answer: who is responsible for each task, where is it in the workflow, and is the project on track to deliver its intended business value?</p>



<h2 class="wp-block-heading">Six Practical Steps for a Hybrid DevOps Project Management Model</h2>



<h3 class="wp-block-heading">1. Start Small and Demonstrate Value Early</h3>



<p class="wp-block-paragraph">If you are introducing DevOps practices to an organisation accustomed to waterfall, begin with a small, well-scoped project that produces visible business value quickly. A successful, tangible outcome builds organisational trust in DevOps methods and makes it easier to secure support for larger initiatives.</p>



<h3 class="wp-block-heading">2. Choose the Right Business Partners</h3>



<p class="wp-block-paragraph">DevOps depends on strong working relationships between IT and the business. Start your DevOps collaborations with departments that are already comfortable engaging with IT — those with technically literate staff who understand system constraints and can participate meaningfully in requirements and testing. Weak IT-business relationships are a common reason DevOps adoption stalls.</p>



<h3 class="wp-block-heading">3. Assign a Single Project Manager</h3>



<p class="wp-block-paragraph">Even when a project is co-sponsored between IT and a business unit, assign one project manager with clear overall responsibility. Dual ownership at the project management level creates confusion about escalation paths and reporting lines. The PM does not need to be an expert in every technical domain, but they do need full visibility across all workstreams and the authority to resolve cross-team conflicts.</p>



<h3 class="wp-block-heading">4. Use Project Tracking Software to Maintain Visibility</h3>



<p class="wp-block-paragraph">In a DevOps project, work moves quickly and task ownership can shift. Use project tracking tools — such as Jira, Azure DevOps, or similar platforms — to ensure that every task has a named owner and a current status. Require team members to update their tasks independently so the project manager always has an accurate picture of progress without relying on status meetings alone.</p>



<p class="wp-block-paragraph">Key things to track explicitly:</p>



<ul class="wp-block-list">
<li>Who owns each task right now</li>
<li>When a task was handed off from one person or sub-team to another</li>
<li>Whether a task is blocked, and who is responsible for resolving the blocker</li>
</ul>



<h3 class="wp-block-heading">5. Maintain Sub-Group Accountabilities Within Cross-Functional Teams</h3>



<p class="wp-block-paragraph">DevOps cross-functional teams typically span requirements, development, QA, and deployment. While collaboration across these disciplines is the point, that does not mean accountability disappears. Organise the team into sub-groups with clearly defined responsibilities at each phase, and track handoffs between those sub-groups just as you would in a traditional project.</p>



<p class="wp-block-paragraph">For example, when the development sub-group completes a feature build, a tracked handoff to the QA sub-group creates a clear record that the build is ready for testing, who accepted it, and when. This preserves the traceability that project managers and auditors need without sacrificing collaboration.</p>



<h3 class="wp-block-heading">6. Define a Clear Project Endpoint</h3>



<p class="wp-block-paragraph">One of the risks in continuous-delivery DevOps projects is that scope creep becomes institutionalised — the project never ends because there is always another feature or improvement to add. Establish a defined production deployment target upfront. This represents the ultimate handoff: from the development team to the live production environment and the business users who depend on it.</p>



<p class="wp-block-paragraph">A defined endpoint does not prevent future iterations. It simply ensures that the project delivers a concrete, deployable outcome that justifies the investment made so far.</p>



<h2 class="wp-block-heading">Why This Hybrid Model Works</h2>



<p class="wp-block-paragraph">The hybrid approach succeeds because it addresses the practical needs of both technical teams and organisational stakeholders:</p>



<ul class="wp-block-list">
<li><strong>Technical teams</strong> retain the collaborative, flexible working style that makes DevOps effective.</li>
<li><strong>Project managers</strong> retain the visibility and accountability mechanisms they need to report status and manage risk.</li>
<li><strong>Business stakeholders</strong> get regular, demonstrable progress toward a production outcome tied to real business goals.</li>
</ul>



<p class="wp-block-paragraph">Neither pure waterfall nor unstructured DevOps is well-suited to most enterprise IT environments. A hybrid model, with deliberate handoffs embedded in a collaborative DevOps workflow, gives engineering teams and project managers a practical middle ground.</p>



<h2 class="wp-block-heading">Key Takeaways</h2>



<ul class="wp-block-list">
<li>Task handoffs are not incompatible with DevOps — they can be adapted to provide traceability within a collaborative model.</li>
<li>A single, empowered project manager is essential even when teams are cross-functional and co-sponsored.</li>
<li>Project tracking tools must be actively maintained by team members to give the PM reliable visibility.</li>
<li>Sub-group accountability within DevOps teams bridges the gap between collaborative execution and individual ownership.</li>
<li>Every DevOps project needs a defined production endpoint to avoid perpetual scope expansion.</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/how-to-use-a-hybrid-devops-approach-in-project-management/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Kubernetes Authentication: The Bound Service Account Token Migration Challenge</title>
		<link>https://www.bestdevops.com/kubernetes-authentication-project-wrestles-with-migration-problems/</link>
					<comments>https://www.bestdevops.com/kubernetes-authentication-project-wrestles-with-migration-problems/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Fri, 26 Jul 2019 06:45:56 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[wrestles]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=6411</guid>

					<description><![CDATA[GKE's Workload Identity feature highlights both the progress and the persistent gaps in Kubernetes authentication. Here's what the Bound Service Account Token Volumes migration problem means for cluster operators.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on reporting originally published by TechTarget (techtarget.com) in July 2019. Some details may have changed in subsequent Kubernetes releases.</em></p>



<h2 class="wp-block-heading">Background: Kubernetes Authentication Has Come a Long Way</h2>



<p class="wp-block-paragraph">Since Kubernetes 1.0, authentication and role-based access control (RBAC) have matured considerably. However, one area remained stuck in the pre-1.0 era as of mid-2019: the management of service account access tokens that secure connections between Kubernetes pods and the Kubernetes API server.</p>



<p class="wp-block-paragraph">These legacy tokens were long-lived, lacked automatic rotation, had no expiration enforcement, and carried no audience binding — meaning a token issued for the API server could theoretically be presented to any other service. The risks are largely ones of mismanagement and blast radius rather than a fundamental cryptographic flaw, but at scale those risks add up quickly.</p>



<h2 class="wp-block-heading">What Workload Identity Revealed About the Problem</h2>



<p class="wp-block-paragraph">In mid-2019, Google released Workload Identity for Google Kubernetes Engine (GKE), positioning it as the recommended way to authenticate containerized GKE application workloads against Google Cloud Platform (GCP) services. Workload Identity uses the bounded, expiring service account tokens introduced in beta with Kubernetes 1.12 to create a cleaner authentication chain between GKE pods and GCP APIs.</p>



<p class="wp-block-paragraph">The practical benefits are significant:</p>



<ul class="wp-block-list">
<li><strong>No manual secret management:</strong> Users no longer need to create, distribute, or rotate Google Cloud IAM service account keys themselves.</li>
<li><strong>Automatic token rotation:</strong> Workload Identity handles credential rotation transparently.</li>
<li><strong>Short-lived, audience-bound tokens:</strong> Tokens expire automatically and are scoped to specific intended audiences, limiting the blast radius of any credential leak.</li>
<li><strong>Reduced dependency on third-party secret stores:</strong> Teams relying on tools like HashiCorp Vault purely for secrets rotation and audience isolation can reduce that overhead.</li>
</ul>



<p class="wp-block-paragraph">Josh Koenig, head of product at Pantheon Platform — a web operations platform hosting more than 200,000 Drupal and WordPress sites — described the motivation directly:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>&#8220;Without this, you end up having to manage a bunch of secrets and access [controls] yourself, which creates lots of opportunities for human error, which has actually bitten us in the past.&#8221;</p><cite>Josh Koenig, Head of Product, Pantheon Platform</cite></blockquote>



<p class="wp-block-paragraph">Koenig described a specific incident in which a misconfigured development cluster could have exposed an SSL certificate. Pantheon&#8217;s team caught the mistake and re-provisioned the cluster, but the near-miss illustrated the fragility of manual credential management. Pantheon used HashiCorp Vault for production workloads, but found its overhead too heavy for development environments — a gap that Workload Identity could close.</p>



<h2 class="wp-block-heading">Kubernetes Authentication Within Clusters: The Lagging Half</h2>



<p class="wp-block-paragraph">Workload Identity specifically improves authentication between GKE pods and <em>external</em> GCP services. Communications that cross the cluster boundary to cloud-managed APIs are higher-value targets for attackers and therefore benefit most immediately from stronger token semantics.</p>



<p class="wp-block-paragraph">Intra-cluster pod-to-API-server authentication is a separate problem. The Kubernetes SIG-Auth working group has been developing an analogous improvement for that path: <strong>Bound Service Account Token Volumes</strong>. When complete, this feature would bring the same automatic rotation, expiration, and audience-binding properties that Workload Identity relies on into every Kubernetes environment — not just GKE.</p>



<p class="wp-block-paragraph">Mike Danese, a Google software engineer and chair of Kubernetes SIG-Auth at the time, explained the security rationale:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>&#8220;Our legacy tokens were only meant for use against the Kubernetes API Server, and using those tokens against something like Vault or Google poses some potential escalations or security risks. We&#8217;ll push on [API Server authentication tokens] a little bit because we think it improves the default security posture of Kubernetes open source.&#8221;</p><cite>Mike Danese, Chair of Kubernetes SIG-Auth (as of 2019)</cite></blockquote>



<h2 class="wp-block-heading">The Migration Snag: Bound Service Account Token Volumes</h2>



<p class="wp-block-paragraph">Bound Service Account Token Volumes entered alpha in Kubernetes 1.13 (released December 2018). The core problem the feature solves is that legacy service account tokens are stored as Kubernetes Secrets mounted into pods. The new token format requires a distinct, purpose-built projected volume type — the <code>ServiceAccountToken</code> projected volume source — rather than the legacy Secret-backed approach.</p>



<p class="wp-block-paragraph">That volume type difference is where the migration headache originates. Early adopters encountered several compatibility issues:</p>



<ul class="wp-block-list">
<li><strong>File permission conflicts:</strong> SIG-Auth took a strict stance on file permissions for the new token volumes, which broke some workloads that relied on legacy permission assumptions.</li>
<li><strong>Pod Security Policy interactions:</strong> Existing PSP configurations that permitted legacy token volumes did not automatically permit the new projected volume type, requiring policy updates across clusters.</li>
<li><strong>Audience binding requirements:</strong> Some tooling that consumed service account tokens for non-API-server purposes (e.g., Vault authentication, custom webhooks) needed updates to present the correct audience claim.</li>
</ul>



<p class="wp-block-paragraph">Danese acknowledged the tension between correctness and backward compatibility:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>&#8220;We could soften our stance on some of the improvements to break legacy clients in fewer ways — for example, we&#8217;ve taken a hard stance on file permissions, which disrupted some legacy clients&#8230; We have some subtle interaction with other security features like Pod Security Policy that we could potentially pave over, by making changes or allowances in Pod Security Policies that would allow old Pod Security Policies to use the new tokens instead of the legacy tokens.&#8221;</p><cite>Mike Danese, Kubernetes SIG-Auth Chair</cite></blockquote>



<h2 class="wp-block-heading">Beta Delayed Beyond Kubernetes 1.15 and 1.16</h2>



<p class="wp-block-paragraph">As of the time of this reporting (July 2019), the Bound Service Account Token Volumes feature had not reached beta status in Kubernetes 1.15 (released June 2019) and was not expected to reach beta in Kubernetes 1.16 (due September 2019). Danese confirmed this directly. The impact on GKE users of the eventual migration was also still undetermined at the time.</p>



<p class="wp-block-paragraph">Chris Riley, DevOps delivery director at CPrime Inc., framed what is at stake if the upgrade is deferred too long:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>&#8220;The issues that are discussed as the abilities of Workload Identity — to reduce blast radius, require the refresh of tokens, enforce a short time to live and bind them to a single pod — would be the potential impacts for current Kubernetes users&#8221; if the tokens aren&#8217;t upgraded eventually.</p><cite>Chris Riley, DevOps Delivery Director, CPrime Inc.</cite></blockquote>



<h2 class="wp-block-heading">What This Means for Cluster Operators</h2>



<p class="wp-block-paragraph">For teams running Kubernetes in 2019 and evaluating their authentication posture, the practical takeaways from this situation are:</p>



<ol class="wp-block-list">
<li><strong>Audit your service account token usage.</strong> Understand which workloads use legacy auto-mounted service account tokens and for what purposes. Any token being presented to a non-Kubernetes endpoint (Vault, cloud APIs, webhooks) warrants closer scrutiny.</li>
<li><strong>Treat manual secret management as a risk.</strong> As Pantheon&#8217;s experience shows, manually managed credentials in development environments can cause real incidents. Where Workload Identity or equivalent managed authentication is available, prefer it.</li>
<li><strong>Watch Pod Security Policy configurations.</strong> The token volume migration will require PSP updates. Teams with complex PSP configurations should track SIG-Auth progress and test in non-production environments ahead of any broader rollout.</li>
<li><strong>Consider managed Kubernetes for reduced migration overhead.</strong> Riley noted that his consulting clients were increasingly delegating complex migration work to cloud providers precisely because of situations like this. Managed Kubernetes services can absorb migration complexity at the platform level.</li>
<li><strong>Follow SIG-Auth KEPs.</strong> The Bound Service Account Token Volumes work is tracked through the Kubernetes Enhancement Proposal (KEP) process. Following the relevant KEP is the most reliable way to track beta and GA promotion timelines.</li>
</ol>



<h2 class="wp-block-heading">The Broader Signal: Kubernetes Technical Debt Is Real</h2>



<p class="wp-block-paragraph">This episode illustrates a challenge inherent to any project at Kubernetes&#8217; scale and adoption level: improving foundational security primitives requires coordinating migration paths across thousands of distinct deployments, tooling integrations, and organizational policies. The alpha-to-beta delay on Bound Service Account Token Volumes is not a failure — it reflects the project taking backward compatibility seriously. But it does underscore that improvements to core security primitives in mature, widely deployed projects move slowly and require careful operator preparation.</p>



<p class="wp-block-paragraph">As Riley summarized: &#8220;The value of services like Workload Identity is the additional integration these providers are doing into other cloud services, simplifying the adoption and increasing overall reliability of Kubernetes. I expect them to do the hard work and support migration or simple adoption of future technologies.&#8221;</p>



<p class="wp-block-paragraph"><em><strong>Note:</strong> This article reflects the state of the Kubernetes project as of July 2019. Bound Service Account Token Volumes subsequently progressed through beta and reached general availability in later Kubernetes releases. Readers should consult the current Kubernetes documentation for up-to-date guidance.</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/kubernetes-authentication-project-wrestles-with-migration-problems/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Top Java Deployment Tools to Use on Your Next Project</title>
		<link>https://www.bestdevops.com/the-top-java-deployment-tools-to-use-on-your-next-project/</link>
					<comments>https://www.bestdevops.com/the-top-java-deployment-tools-to-use-on-your-next-project/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Thu, 13 Jun 2019 09:54:00 +0000</pubDate>
				<category><![CDATA[Gradle]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Top]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=5363</guid>

					<description><![CDATA[As development teams scale, handwritten scripts and low-level JDK calls break down fast. Here is a practical guide to the most important Java deployment tools—from Maven and Gradle to Jenkins CI and beyond.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">As software development teams grow, application packaging and deployment tasks become significantly harder to manage. Handwritten shell scripts and raw JDK utility calls simply do not scale. Choosing the right Java deployment toolchain early in a project pays dividends throughout the software development lifecycle.</p>



<p class="wp-block-paragraph">This article covers the most widely used Java deployment tools and frameworks, explaining what each one does well, where it fits in a deployment pipeline, and when you might reach for something else.</p>



<h2 class="wp-block-heading">1. Apache Maven</h2>



<p class="wp-block-paragraph">Maven is the de facto standard build tool for Java enterprise projects. It is not purely a deployment tool—it can compile source code, resolve and download JAR dependencies from remote repositories, run unit tests, package applications into JARs or WARs, and push release artifacts to repositories such as Sonatype Nexus or JFrog Artifactory.</p>



<p class="wp-block-paragraph">Maven&#8217;s core strength is its opinionated, convention-over-configuration model. Projects that follow Maven&#8217;s standard directory layout get a huge amount of functionality for free through the build lifecycle phases (<code>validate</code>, <code>compile</code>, <code>test</code>, <code>package</code>, <code>install</code>, <code>deploy</code>).</p>



<p class="wp-block-paragraph">Where Maven really extends into deployment territory is through its plugin ecosystem. Plugins such as the <strong>Tomcat Maven Plugin</strong> or the <strong>WebSphere Deployment Plugin</strong> allow teams to push packaged applications directly to application servers as part of a Maven build. While Maven&#8217;s XML-based POM files can feel verbose for complex projects, its ubiquity means tooling support is excellent across IDEs, CI servers, and cloud platforms.</p>



<h3 class="wp-block-heading">When to use Maven</h3>



<ul class="wp-block-list">
<li>Enterprise Java projects that need a well-understood, standardised build lifecycle</li>
<li>Teams that rely heavily on artifact repositories like Nexus or Artifactory</li>
<li>Projects with large transitive dependency graphs that benefit from Maven&#8217;s dependency mediation</li>
</ul>



<h2 class="wp-block-heading">2. Gradle</h2>



<p class="wp-block-paragraph">Gradle builds on many of Maven&#8217;s best practices while addressing its most common pain points. Instead of XML, Gradle uses a Groovy-based (or, more recently, Kotlin-based) DSL for build scripts, which makes build logic far easier to read and maintain for teams comfortable with a programming language.</p>



<p class="wp-block-paragraph">Gradle&#8217;s incremental build system and build cache can dramatically reduce build times on large multi-module projects. Like Maven, Gradle covers the full spectrum from compilation through packaging to deployment. The Gradle API is highly extensible—custom tasks can interact with remote servers, container registries, or cloud APIs without requiring a separate orchestration layer.</p>



<p class="wp-block-paragraph">Gradle is the default build tool for Android projects and has seen strong adoption in large-scale server-side Java and Kotlin microservice architectures.</p>



<h3 class="wp-block-heading">When to use Gradle</h3>



<ul class="wp-block-list">
<li>Projects where build performance and incremental compilation matter</li>
<li>Teams that want a programmable build model rather than declarative XML configuration</li>
<li>Multi-module monorepos where Maven&#8217;s all-or-nothing build model is a bottleneck</li>
</ul>



<h2 class="wp-block-heading">3. Jenkins CI</h2>



<p class="wp-block-paragraph">Jenkins is the most widely deployed open-source continuous integration and continuous delivery (CI/CD) server in the Java ecosystem. Its primary role is <strong>orchestration</strong>: Jenkins does not compile code itself, does not run tests directly, and does not package JARs. Instead, it delegates those tasks to the appropriate underlying tools—Maven, Gradle, or the JDK compiler—and coordinates the sequence of steps from source checkout through to production deployment.</p>



<p class="wp-block-paragraph">This separation of concerns is one of Jenkins&#8217; greatest strengths. A typical Jenkins pipeline might:</p>



<ol class="wp-block-list">
<li>Pull source code from a Git repository</li>
<li>Invoke Gradle or Maven to compile and run unit tests</li>
<li>Build a Docker image and push it to a container registry</li>
<li>Deploy the image to a staging environment</li>
<li>Run integration or smoke tests</li>
<li>Promote the release to production on approval</li>
</ol>



<p class="wp-block-paragraph">Jenkins&#8217; Declarative Pipeline syntax (via <code>Jenkinsfile</code>) allows pipeline definitions to live alongside application code in source control, making pipeline changes subject to the same review process as application changes.</p>



<p class="wp-block-paragraph">Jenkins is not the only CI/CD option. Other strong contenders in this space include:</p>



<ul class="wp-block-list">
<li><strong>JetBrains TeamCity</strong> – polished UI, deep IDE integration</li>
<li><strong>Atlassian Bamboo</strong> – tight integration with Jira and Bitbucket</li>
<li><strong>AWS CodeDeploy / CodePipeline</strong> – native choice for AWS-hosted workloads</li>
<li><strong>GitHub Actions</strong> – increasingly popular for projects already hosted on GitHub</li>
<li><strong>GitLab CI/CD</strong> – strong choice when using GitLab as the source repository</li>
</ul>



<h3 class="wp-block-heading">When to use Jenkins</h3>



<ul class="wp-block-list">
<li>Teams that need maximum flexibility and a large plugin ecosystem</li>
<li>On-premises or hybrid environments where a self-hosted CI server is required</li>
<li>Complex multi-stage pipelines with conditional logic, approvals, and parallel stages</li>
</ul>



<h2 class="wp-block-heading">4. Enterprise Release Automation Tools</h2>



<p class="wp-block-paragraph">For organisations managing complex, multi-tier Java deployments across many environments—development, QA, staging, pre-production, and production—dedicated release automation platforms provide capabilities that general-purpose CI tools can struggle to match out of the box.</p>



<p class="wp-block-paragraph">Tools in this category (historically including CA Release Automation, now part of Broadcom&#8217;s portfolio, as well as alternatives such as XL Deploy from Digital.ai and Octopus Deploy) are designed around modelling the full deployment pipeline: which components go where, in what order, with what approval gates, and how to roll back if something goes wrong.</p>



<p class="wp-block-paragraph">These platforms tend to shine when:</p>



<ul class="wp-block-list">
<li>Deployments span multiple application servers, databases, and message brokers that must be updated in a specific sequence</li>
<li>Compliance requirements demand audit trails of every deployment action and approval</li>
<li>Release coordinators—not just developers—need visibility and control over what goes to production</li>
</ul>



<p class="wp-block-paragraph">For teams deploying Java microservices to Kubernetes, many of these vendors also offer Kubernetes-native deployment capabilities, or teams can move to Helm, ArgoCD, or Flux as purpose-built Kubernetes deployment tools.</p>



<h2 class="wp-block-heading">5. Low-Level Java Deployment Utilities</h2>



<p class="wp-block-paragraph">High-level tools like Maven, Gradle, and Jenkins work by calling lower-level utilities under the hood. When a high-level tool fails, understanding the underlying utilities is essential for effective troubleshooting.</p>



<p class="wp-block-paragraph">Useful low-level tools in a Java deployment context include:</p>



<ul class="wp-block-list">
<li><strong>javac / java</strong> – The JDK compiler and runtime. If Maven reports a compilation failure, running <code>javac</code> directly against the offending class can clarify whether the issue is in the source code or in Maven&#8217;s configuration.</li>
<li><strong>jar</strong> – The JDK&#8217;s archive tool for creating and inspecting JAR files.</li>
<li><strong>SSH clients (OpenSSH, PuTTY)</strong> – For connecting to remote servers to inspect logs, restart services, or verify file placement.</li>
<li><strong>SCP / WinSCP / rsync</strong> – For securely transferring files to remote hosts when the automated pipeline has failed and a hotfix must be placed manually.</li>
<li><strong>FTP clients (FileZilla, WS-FTP)</strong> – Useful in legacy environments where FTP is still the transfer mechanism for deployable artifacts.</li>
<li><strong>curl / wget</strong> – For testing HTTP endpoints after deployment, or for pulling artifacts from a repository manually.</li>
</ul>



<p class="wp-block-paragraph">The general principle: when a high-level build step fails, strip away the abstraction and reproduce the failure using the most direct tool available. This narrows the problem space dramatically.</p>



<h2 class="wp-block-heading">Full-Suite Java Deployment Frameworks</h2>



<p class="wp-block-paragraph">Some teams prefer a vertically integrated platform that covers source control, CI/CD pipelines, artifact storage, issue tracking, and code review in a single product. The main players here are:</p>



<ul class="wp-block-list">
<li><strong>GitLab</strong> – Source control, CI/CD pipelines, container registry, and security scanning in one platform. GitLab CI/CD is well-suited to Java projects and supports Maven and Gradle natively.</li>
<li><strong>Bitbucket + Atlassian suite</strong> – Bitbucket Pipelines combined with Jira and Bamboo covers the full software development lifecycle for teams already invested in the Atlassian ecosystem.</li>
<li><strong>JetBrains Space</strong> – An integrated platform from the makers of IntelliJ IDEA, combining code hosting, CI/CD, and team collaboration tools.</li>
<li><strong>GitHub + GitHub Actions</strong> – Increasingly a full-platform option with Actions handling CI/CD, Packages for artifact storage, and Projects for planning.</li>
</ul>



<p class="wp-block-paragraph">The trade-off with integrated platforms is flexibility versus convenience. Best-of-breed tool combinations (e.g., GitHub + Jenkins + Nexus + Artifactory) give teams fine-grained control and the ability to swap individual components, but require more integration effort. Integrated platforms reduce that overhead at the cost of some flexibility.</p>



<h2 class="wp-block-heading">Choosing the Right Combination</h2>



<p class="wp-block-paragraph">No single tool covers every aspect of Java deployment. A typical modern Java project will use several tools together:</p>



<figure class="wp-block-table"><table><thead><tr><th>Layer</th><th>Common Tool Choices</th></tr></thead><tbody><tr><td>Build &amp; package</td><td>Maven, Gradle</td></tr><tr><td>CI/CD orchestration</td><td>Jenkins, GitHub Actions, GitLab CI</td></tr><tr><td>Artifact storage</td><td>Nexus Repository, JFrog Artifactory</td></tr><tr><td>Container deployment</td><td>Docker, Helm, ArgoCD</td></tr><tr><td>Release management</td><td>Octopus Deploy, Digital.ai Deploy, Spinnaker</td></tr><tr><td>Low-level troubleshooting</td><td>SSH, SCP, curl, javac</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">The right combination depends on team size, deployment complexity, compliance requirements, and existing infrastructure. Start with a build tool (Maven or Gradle), add a CI/CD server (Jenkins or a cloud-native equivalent), connect it to an artifact repository, and layer in release automation only when deployment complexity demands it.</p>



<p class="wp-block-paragraph"><em>Originally sourced from an article on theserverside.com (2019). Tool availability and market position have evolved since the original publication date.</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/the-top-java-deployment-tools-to-use-on-your-next-project/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
