<?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>Web Development Archives - Efigence</title>
	<atom:link href="https://www.efigence.com/category/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.efigence.com/category/web-development/</link>
	<description>Custom Development &#38; Design for Finance</description>
	<lastBuildDate>Tue, 03 Sep 2024 14:03:37 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>
	<item>
		<title>Spring Boot REST Application with Keycloak SSO Integration</title>
		<link>https://www.efigence.com/technology/spring-boot-rest-application-with-keycloak-sso-integration/</link>
		
		<dc:creator><![CDATA[Aleksandra Bartosiak]]></dc:creator>
		<pubDate>Thu, 23 Jan 2020 09:32:15 +0000</pubDate>
				<category><![CDATA[Security]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://www.efigence.com/spring-boot-rest-application-with-keycloak-sso-integration/</guid>

					<description><![CDATA[<p>The post <a href="https://www.efigence.com/technology/spring-boot-rest-application-with-keycloak-sso-integration/">Spring Boot REST Application with Keycloak SSO Integration</a> appeared first on <a href="https://www.efigence.com">Efigence</a>.</p>
]]></description>
										<content:encoded><![CDATA[
    <section id="wysiwyg_40" class="layout wysiwyg" data-block-theme="light" data-top="medium" data-bottom="medium">
        <div class="row" data-view="1">
            <div class="columns small-12">
                <h2>Prerequisites</h2>
<ul>
<li>Basic knowledge of Spring Boot and Maven</li>
<li>Running Keycloak instance with access to the administration console</li>
</ul>
<h2>What is SSO?</h2>
<p>SSO (single sign-on) allows users to authenticate with multiple applications by logging in only once with the same credentials.</p>
<h2>What is Keycloak?</h2>
<p>According to <a href="https://www.keycloak.org/about.html" target="_blank" rel="noopener noreferrer nofollow">https://www.keycloak.org/about.html</a>: “Keycloak is an open source Identity and Access Management solution aimed at <a href="https://www.efigence.com/software-development/the-future-of-frontend-frameworks/">modern applications</a> and services. It makes it easy to secure applications and services with little to no code.“</p>
<h2>The problem</h2>
<p>Suppose you need to run a new, simple application with REST API and deploy it in an existing environment. The application should be protected from unauthorized access. The key assumption here is that the authorization server (Keycloak) is part of the existing infrastructure so there is no need to define a new one. Let’s define a few general requirements:</p>
<ul>
<li>REST API is available only for authenticated users with a specified role named user</li>
<li>The authentication process is covered by Keycloak</li>
<li>The authorization is performed by the Spring Boot application</li>
</ul>
<p><strong>Read also: </strong><a href="https://www.efigence.com/technology/painless-changelog/">Painless Changelog</a></p>
<h2>The solution</h2>
<p>The final authentication/authorization flow should look like the picture below. Keycloak acts as an SSO. For clarification purposes only the happy path flow is covered.<br />
<img fetchpriority="high" class="aligncenter size-full wp-image-4061" src="https://www.efigence.com/wp-content/uploads/2023/09/1.png" alt="Authentication Sequence" width="566" height="401" /></p>
<h2>Keycloak configuration</h2>
<p>Process description:</p>
<ol>
<li>An unauthenticated user performs a GET request to <tt>/resource</tt></li>
<li>The application realizes that the user is unauthorized and redirects him to the SSO login form.</li>
<li>The user provides credentials via the login form and sends it to SSO</li>
<li>SSO checks the login and password provided</li>
<li>If the login and password are correct, the user is redirected back to the originally requested <tt>/resource</tt></li>
<li>The authenticated user performs GET <tt>/resource</tt> again.</li>
<li>The application checks if the authorized user is assigned to the required role</li>
<li>The requested resource is sent back to the user</li>
</ol>
<p>Keycloak configuration First we need to define a new realm (this step might be skipped if you want to reuse an existing one). From the “select realm” menu choose the “add realm” option, provide the name new-application-realm and hit the “create” button.<br />
<img class="aligncenter size-full wp-image-4064" src="https://www.efigence.com/wp-content/uploads/2023/09/2.png" alt="Add realm" width="1051" height="252" /><br />
Next, create a client. Select “clients” from the sidebar menu and hit “create”.<br />
<img class="aligncenter size-full wp-image-4067" src="https://www.efigence.com/wp-content/uploads/2023/09/3.png" alt="Add client" width="1054" height="298" /><br />
The only required field is “Client ID”. Type new-application-client and click “save”. Note that the name you entered will be referenced later in the Spring Boot application configuration. Now switch to the “settings” tab and type <tt>http://localhost:8088/*</tt> in “Valid Redirect URIs” and save the form. Note port 8088 which your Spring Boot application should be run on.<br />
<img class="aligncenter size-full wp-image-4070" src="https://www.efigence.com/wp-content/uploads/2023/09/4.png" alt="Valid redirect URIs" width="983" height="82" /><br />
The next step is to create a role definition. Simply select “roles” from the sidebar and hit “add role”. In the form fill “role name” with the value “user” and press “save”.<br />
<img class="aligncenter size-full wp-image-4073" src="https://www.efigence.com/wp-content/uploads/2023/09/5.png" alt="Add role" width="1038" height="316" /><br />
The final step is to create a new user in the previously defined role. From the side menu select “users” and click “add user”. Type the username “test” in the appropriate field and save the form. After that switch to “credentials”, provide the password, switch “temporary” to “off” and hit “set password”.<br />
<img class="aligncenter size-full wp-image-4076" src="https://www.efigence.com/wp-content/uploads/2023/09/6.png" alt="Set password" width="1050" height="248" /><br />
To assign a role, select the “role mappings” tab and move the “user” role from “available” to “assigned”.<br />
<img class="aligncenter size-full wp-image-4079" src="https://www.efigence.com/wp-content/uploads/2023/09/7.png" alt="Test" width="1249" height="286" /><br />
After these few steps Keycloak is configured and ready for action! Now the second part – the application.</p>
<p><strong>Read also: </strong><a href="https://www.efigence.com/software-development/benefits-of-immutability-in-software-development/">Benefits of immutability in a software development</a></p>
<h2>Spring Boot application configuration</h2>
<p>Now it’s time to configure the application. Assuming your configuration is Maven based, you need to add the code below to pom.xml:</p>
<div>
<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-generic enlighter-hover enlighter-linenumbers ">
<div class="enlighter-code">
<div class="enlighter">
<div class="">
<div></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">dependencies</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">dependency</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">groupId</span><span class="enlighter-g1">&gt;</span><span class="enlighter-text">org.</span><span class="enlighter-m3">springframework</span><span class="enlighter-text">.</span><span class="enlighter-m3">boot</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/groupId</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">artifactId</span><span class="enlighter-g1">&gt;</span><span class="enlighter-text">spring-boot-starter-web</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/artifactId</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/dependency</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">dependency</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">groupId</span><span class="enlighter-g1">&gt;</span><span class="enlighter-text">org.</span><span class="enlighter-m3">keycloak</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/groupId</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">artifactId</span><span class="enlighter-g1">&gt;</span><span class="enlighter-text">keycloak-spring-boot-starter</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/artifactId</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/dependency</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/dependencies</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">dependencyManagement</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">dependencies</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">dependency</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">groupId</span><span class="enlighter-g1">&gt;</span><span class="enlighter-text">org.</span><span class="enlighter-m3">keycloak</span><span class="enlighter-text">.</span><span class="enlighter-m3">bom</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/groupId</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">artifactId</span><span class="enlighter-g1">&gt;</span><span class="enlighter-text">keycloak-adapter-bom</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/artifactId</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">version</span><span class="enlighter-g1">&gt;</span><span class="enlighter-n0">8.0</span><span class="enlighter-text">.</span><span class="enlighter-m3">1</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/version</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">type</span><span class="enlighter-g1">&gt;</span><span class="enlighter-text">pom</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/type</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">scope</span><span class="enlighter-g1">&gt;</span><span class="enlighter-text">import</span><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/scope</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/dependency</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/dependencies</span><span class="enlighter-g1">&gt;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">&lt;</span><span class="enlighter-text">/dependencyManagement</span><span class="enlighter-g1">&gt;</span></div>
</div>
</div>
</div>
</div>
</div>
<p>What does it do? It simply adds Keycloak starter and security auto configuration for your Spring Boot application. All you need to configure is just a few lines as shown in the snippet below:</p>
<div>
<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-generic enlighter-hover enlighter-linenumbers ">
<div class="enlighter-code">
<div class="enlighter">
<div class="">
<div><span class="enlighter-text">server.</span><span class="enlighter-m3">port</span><span class="enlighter-text">=</span><span class="enlighter-n1">8088</span></div>
</div>
<div class="">
<div></div>
</div>
<div class="">
<div><span class="enlighter-text">keycloak.</span><span class="enlighter-m3">realm</span><span class="enlighter-text"> = </span><span class="enlighter-k1">new</span><span class="enlighter-text">-application-realm</span></div>
</div>
<div class="">
<div><span class="enlighter-text">keycloak.</span><span class="enlighter-m3">auth</span><span class="enlighter-text">-server-url = http:</span><span class="enlighter-c0">//localhost:8080/auth</span></div>
</div>
<div class="">
<div><span class="enlighter-text">keycloak.</span><span class="enlighter-m3">resource</span><span class="enlighter-text"> = </span><span class="enlighter-k1">new</span><span class="enlighter-text">-application-client</span></div>
</div>
<div class="">
<div><span class="enlighter-text">keycloak.</span><span class="enlighter-m3">public</span><span class="enlighter-text">-client = </span><span class="enlighter-k1">true</span></div>
</div>
<div class="">
<div></div>
</div>
<div class="">
<div><span class="enlighter-c0"># protect resource (role &#8216;user&#8217; is required)</span></div>
</div>
<div class="">
<div><span class="enlighter-text">keycloak.</span><span class="enlighter-m3">securityConstraints</span><span class="enlighter-g1">[</span><span class="enlighter-n1">0</span><span class="enlighter-g1">]</span><span class="enlighter-text">.</span><span class="enlighter-m3">authRoles</span><span class="enlighter-g1">[</span><span class="enlighter-n1">0</span><span class="enlighter-g1">]</span><span class="enlighter-text"> = user</span></div>
</div>
<div class="">
<div><span class="enlighter-text">keycloak.</span><span class="enlighter-m3">securityConstraints</span><span class="enlighter-g1">[</span><span class="enlighter-n1">0</span><span class="enlighter-g1">]</span><span class="enlighter-text">.</span><span class="enlighter-m3">securityCollections</span><span class="enlighter-g1">[</span><span class="enlighter-n1">0</span><span class="enlighter-g1">]</span><span class="enlighter-text">.</span><span class="enlighter-m3">patterns</span><span class="enlighter-g1">[</span><span class="enlighter-n1">0</span><span class="enlighter-g1">]</span><span class="enlighter-text"> = /resource/*</span></div>
</div>
</div>
</div>
</div>
</div>
<p>Notice that the application is configured to be run on port 8088 (<tt>server.port</tt>). The second block of settings refers by name to Keycloak’s realm and client defined in the “Keycloak configuration” section. The last part simply allows access to <tt>/resource</tt> only for authenticated users in a “user” role. The last thing to do is to add some code that does real business stuff. In other words, a REST controller. Look at the snippet below:</p>
<div>
<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-generic enlighter-hover enlighter-linenumbers ">
<div class="enlighter-code">
<div class="enlighter">
<div class="">
<div><span class="enlighter-text">@RestController</span></div>
</div>
<div class="">
<div><span class="enlighter-text">public </span><span class="enlighter-k1">class</span><span class="enlighter-text"> NewApplicationRest </span><span class="enlighter-g1">{</span></div>
</div>
<div class="">
<div></div>
</div>
<div class="">
<div><span class="enlighter-text"> @</span><span class="enlighter-m0">GetMapping</span><span class="enlighter-g1">(</span><span class="enlighter-text">path=</span><span class="enlighter-s0">&#8220;/resource&#8221;</span><span class="enlighter-g1">)</span></div>
</div>
<div class="">
<div><span class="enlighter-text"> public String </span><span class="enlighter-m0">getResource</span><span class="enlighter-g1">(){</span></div>
</div>
<div class="">
<div><span class="enlighter-k1">return</span> <span class="enlighter-s0">&#8220;protected resource&#8221;</span><span class="enlighter-text">;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">}</span></div>
</div>
<div class="">
<div></div>
</div>
<div class="">
<div><span class="enlighter-g1">}</span></div>
</div>
</div>
</div>
</div>
</div>
<p>The only resource defined is <tt>/resource</tt> (yes, the resource that appeared in the previous configuration as secured). In case you face an exception with this message when running the application:</p>
<div>Parameter 1 of method setKeycloakSpringBootProperties in org.keycloak.adapters.springboot.KeycloakBaseSpringBootConfiguration<br />
required a bean of type ‘org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver’ that could not be found.</div>
<div></div>
<p>The solution is to define the missing bean somewhere in your application:</p>
<div>
<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-generic enlighter-hover enlighter-linenumbers ">
<div class="enlighter-code">
<div class="enlighter">
<div class="">
<div><span class="enlighter-text">@Bean</span></div>
</div>
<div class="">
<div><span class="enlighter-text">public KeycloakSpringBootConfigResolver </span><span class="enlighter-m0">keycloakConfigResolver</span><span class="enlighter-g1">()</span> <span class="enlighter-g1">{</span></div>
</div>
<div class="">
<div><span class="enlighter-k1">return</span> <span class="enlighter-k1">new</span> <span class="enlighter-m0">KeycloakSpringBootConfigResolver</span><span class="enlighter-g1">()</span><span class="enlighter-text">;</span></div>
</div>
<div class="">
<div><span class="enlighter-g1">}</span></div>
</div>
</div>
</div>
</div>
</div>
<h2>Testing the application</h2>
<p>First you must run the application. When it’s done, point your browser to <tt>http://localhost:8088/resource</tt>. Since you’re not authenticated, you will be redirected to Keycloak’s login form as shown in the picture below:<br />
<img class="aligncenter size-full wp-image-4082" src="https://www.efigence.com/wp-content/uploads/2023/09/8.png" alt="New-application-realm" width="784" height="579" /><br />
Type the credentials for the user you created at the beginning and click “log in”. You should be redirected back to your application as an authenticated user in a “user” role. Your browser should show something like this:<br />
<img class="aligncenter size-full wp-image-4085" src="https://www.efigence.com/wp-content/uploads/2023/09/9.png" alt="Protected resource" width="507" height="90" /><br />
Congratulations! Now your REST API is protected from unauthorized access!</p>
            </div>
        </div>
    </section>



<div id="simple-translate" class="simple-translate-system-theme">
<div>
<div class="simple-translate-button isShow" style="background-image: url('chrome-extension://cllnohpbfenopiakdcjmjcbaeapmkcdl/icons/512.png'); height: 22px; width: 22px; top: 40px; left: 364px;"></div>
<div class="simple-translate-panel " style="width: 300px; height: 200px; top: 0px; left: 0px; font-size: 13px;">
<div class="simple-translate-result-wrapper" style="overflow: hidden;">
<div class="simple-translate-move" draggable="true"></div>
<div class="simple-translate-result-contents">
<p class="simple-translate-candidate" dir="auto">
</div>
</div>
</div>
</div>
</div><p>The post <a href="https://www.efigence.com/technology/spring-boot-rest-application-with-keycloak-sso-integration/">Spring Boot REST Application with Keycloak SSO Integration</a> appeared first on <a href="https://www.efigence.com">Efigence</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Painless Changelog</title>
		<link>https://www.efigence.com/technology/painless-changelog/</link>
		
		<dc:creator><![CDATA[Aleksandra Bartosiak]]></dc:creator>
		<pubDate>Wed, 06 Nov 2019 12:26:15 +0000</pubDate>
				<category><![CDATA[QA]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Tech]]></category>
		<guid isPermaLink="false">https://www.efigence.com/painless-changelog/</guid>

					<description><![CDATA[<p>The post <a href="https://www.efigence.com/technology/painless-changelog/">Painless Changelog</a> appeared first on <a href="https://www.efigence.com">Efigence</a>.</p>
]]></description>
										<content:encoded><![CDATA[
    <section id="wysiwyg_80" class="layout wysiwyg" data-block-theme="light" data-top="medium" data-bottom="medium">
        <div class="row" data-view="1">
            <div class="columns small-12">
                <section id="content_block-0" class="layout content_block" data-pt="large" data-pb="small" data-background="white" data-order="0">
<div class="row align-left seen in-view" data-view="0">
<div class="small-12 columns text-left">
<div class="sub-content">
<h2 class="seen in-view" data-view="0">Everybody needs to add information about their work to the library’s changelog.</h2>
</div>
</div>
</div>
</section>
<section id="wysiwyg_block-1" class="layout wysiwyg_block" data-pt="small" data-pb="large" data-background="white" data-order="1">
<div class="row align-left seen in-view" data-view="0">
<div class="small-12 columns">
<div class="block">
<p>Ok, so you are working in a small team, creating a component library. Some people are <a href="https://www.efigence.com/services-software-maintenance/">fixing bugs</a>, some are adding new functionalities and in general, there is one person working on a specific <a href="https://www.efigence.com/software-development/building-webcomponents/">component</a>. Seems like everything is okay and nobody is interfering with anybody’s work. But there’s one problem – we all need to collect information about our work in the library’s changelog.</p>
<p>The thing is that the changelog is a single file, which every member of the team needs to update. These updates create merge conflicts in git, so after merging one merge request to the master, suddenly the rest of them are having conflicts due to the fact that somebody put information about their change in the same line that everybody else did.</p>
<p>There are some ways to resolve this problem. First of all, you can add free ‘spots’  (<a href="https://about.gitlab.com/blog/2015/02/10/gitlab-reduced-merge-conflicts-by-90-percent-with-changelog-placeholders" rel="nofollow">https://about.gitlab.com/blog/2015/02/10/gitlab-reduced-merge-conflicts-by-90-percent-with-changelog-placeholders</a>) in your changelog and assign a number of them to each member of the team. As this should do the job, we found it rather more like a hack than a clean solution. Secondly, a changelog can be created based on your commit history. To get the most out of it and keep consistency among developers tools like commitizen (<a href="https://github.com/commitizen/cz-cli" rel="nofollow">https://github.com/commitizen/cz-cli</a>) come in handy. But the solution we chose took a different approach to the problem.</p>
<p><strong>Read also: </strong><a href="https://www.efigence.com/technology/spring-boot-rest-application-with-keycloak-sso-integration/">Spring Boot REST application with Keycloak SSO integration</a></p>
<p>It was introduced on GitLab’s blog (<a href="https://about.gitlab.com/blog/2018/07/03/solving-gitlabs-changelog-conflict-crisis/" rel="nofollow">https://about.gitlab.com/blog/2018/07/03/solving-gitlabs-changelog-conflict-crisis/</a>) and it is fantastic. The concept relies on the principle that every <a href="https://www.efigence.com/software-development/is-it-a-source-of-shame-to-be-a-php-developer/">developer</a> adds information about their change in a separate .md file in a ‘release’ folder. Each file name is the ID of the issue in Jira, that asks about a bugfix or a feature. When release day comes, we run our special node script, that reads all of the files, adds the ID of the issue to the end of each line in a file and finally joins all the information to the changelog. Moreover, the number of the current release is passed down as an argument to the script like this:</p>
<p>`npm run update-changelog — 2.1.1`</p>
<p>Of course, there is some room for improvement. For example, instead of giving a specific number of release, our script could accept a string ‘patch’, ‘minor’ or ‘major’ and come up with a proper number based on the prior release. Moreover, the running script could be added to the release pipeline in GitLab so everything would work automatically.</p>
<p>All in all, there are many ways to keep the changelog. Some may argue that it should be based on commit history, some will say that having placeholders in the changelog file works and there is no need to complicate things. And I can say something too – since we have adapted the concept of separate files, keeping the changelog has never seemed so painless for us.</p>
</div>
</div>
</div>
</section>
            </div>
        </div>
    </section>



<div id="simple-translate" class="simple-translate-system-theme">
<div>
<div class="simple-translate-button isShow" style="background-image: url('chrome-extension://cllnohpbfenopiakdcjmjcbaeapmkcdl/icons/512.png'); height: 22px; width: 22px; top: 40px; left: 364px;"></div>
<div class="simple-translate-panel " style="width: 300px; height: 200px; top: 0px; left: 0px; font-size: 13px;">
<div class="simple-translate-result-wrapper" style="overflow: hidden;">
<div class="simple-translate-move" draggable="true"></div>
<div class="simple-translate-result-contents">
<p class="simple-translate-candidate" dir="auto">
</div>
</div>
</div>
</div>
</div><p>The post <a href="https://www.efigence.com/technology/painless-changelog/">Painless Changelog</a> appeared first on <a href="https://www.efigence.com">Efigence</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
