<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Idan Elhalwani</title>
    <description>The latest articles on DEV Community by Idan Elhalwani (@idane).</description>
    <link>https://dev.to/idane</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F476912%2F2ef41d82-92f0-428a-95fe-0127f7dd9935.PNG</url>
      <title>DEV Community: Idan Elhalwani</title>
      <link>https://dev.to/idane</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/idane"/>
    <language>en</language>
    <item>
      <title>Ostara Version 0.10.0 Has Been Released</title>
      <dc:creator>Idan Elhalwani</dc:creator>
      <pubDate>Mon, 12 Jun 2023 08:48:00 +0000</pubDate>
      <link>https://dev.to/krud/ostara-version-0100-has-been-released-50ap</link>
      <guid>https://dev.to/krud/ostara-version-0100-has-been-released-50ap</guid>
      <description>&lt;p&gt;Hello and welcome to the first major update of Ostara! &lt;/p&gt;

&lt;p&gt;We've been working hard the last 3 weeks on our latest release and I'm happy to say it's finally here: we are super excited to release version 0.10.0 of Ostara and bring it one step closer out of Alpha. This release is full of new features and improvements to make your experience smoother than ever. Among the many awesome updates, the one we are most thrilled about is the newly introduced Metrics Notifications!&lt;/p&gt;

&lt;p&gt;Before diving into the specifics, let's quickly brush up on Ostara.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Recap
&lt;/h2&gt;

&lt;p&gt;If you're new around here or just need a quick memory jog, Ostara is your go-to solution for managing and monitoring Spring Boot Actuator-enabled microservices. &lt;/p&gt;

&lt;p&gt;With a primary focus on simplicity and user-friendliness, Ostara provides you with real-time insights into the health and performance of your microservices, allowing you to monitor critical metrics such as CPU and memory usage. &lt;/p&gt;

&lt;p&gt;For more information, see my &lt;a href="https://dev.to/krud/introducing-ostara-3o6b"&gt;previous article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metric Notifications
&lt;/h2&gt;

&lt;p&gt;Managing microservices can get a tad complex, and that's where Ostara's new feature comes into play - Metric Notifications. Let's take a deep dive into this key update in version 0.10.0.&lt;/p&gt;

&lt;p&gt;Metric Notifications in Ostara serves as your personalized alarm system, alerting you when something goes amiss with your metrics. This feature introduces a level of proactive monitoring that is set to redefine how you interact with your metrics data.&lt;/p&gt;

&lt;p&gt;In the Metric Notifications interface, you can now create custom alert rules for your application metrics. Once these rules are in place, Ostara will monitor your instances for metric updates and evaluate them, notifying you if the value has crossed the threshold that was set.&lt;/p&gt;

&lt;p&gt;You can define the metric you wish to monitor and set the trigger value. Ostara currently supports two types of rules:&lt;/p&gt;

&lt;h4&gt;
  
  
  Simple rule
&lt;/h4&gt;

&lt;p&gt;Monitors a single metric and triggers when the metric crosses your defined trigger value.&lt;/p&gt;

&lt;h4&gt;
  
  
  Relative rule
&lt;/h4&gt;

&lt;p&gt;Tracks the relative value between two metrics, triggering when this value crosses your defined trigger value. For instance, you can set a rule for free disk space on your instance, where the first metric is disk.free and the relative value is disk.total. You can set a trigger for when the relative value drops below 20%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3AcPTHBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjuz0y028svubnccqyi0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3AcPTHBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjuz0y028svubnccqyi0.gif" alt="Relative rule" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's talk about how Ostara evaluates these rules. Ostara provides three comparison operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lower than '&amp;lt;': Triggers a notification if the metric value (or relative value) falls below the trigger value.&lt;/li&gt;
&lt;li&gt;Greater than '&amp;gt;': Triggers a notification if the metric value (or relative value) exceeds the trigger value.&lt;/li&gt;
&lt;li&gt;Between: Triggers a notification if the metric value (or relative value) falls within the set trigger values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this is all too confusing and you're just looking to play around with the new rules, we've also added &lt;strong&gt;Predefined Rules&lt;/strong&gt; that will allow you to instantly create a variety of default rules to play around with;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GVw6Er_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/631lwizpdh1fpeh1hun8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GVw6Er_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/631lwizpdh1fpeh1hun8.gif" alt="Predefined rules" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more information, visit &lt;a href="https://docs.ostara.dev/features/application-features/monitor/metric-notifications"&gt;Metric Notifications&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  All The Other Goodies in Version 0.10.0
&lt;/h2&gt;

&lt;p&gt;We've managed to achieve quite a lot in this version, here are some of the other features you will encounter:&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Health Notifications
&lt;/h3&gt;

&lt;p&gt;This feature sends immediate alerts if your application's health status changes. It's designed to help you react quickly to potential issues, reducing manual monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notification settings
&lt;/h3&gt;

&lt;p&gt;With the addition of OS level notifications, we've also added the option to turn them off completely in Settings, or just their sound.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5r6r0dIn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hk1qznj9ir1h5mva96eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5r6r0dIn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hk1qznj9ir1h5mva96eg.png" alt="Notification Settings" width="626" height="876"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Global, App and Folder Dashboard
&lt;/h3&gt;

&lt;p&gt;There are three new dashboards for you to explore - the Global Dashboard, the App Dashboard and the Folder Dashboard. These dashboards provide a concise overview of the status of your applications and folders. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JfuYcypQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0w9bxvtju8yq68o6eu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JfuYcypQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0w9bxvtju8yq68o6eu3.png" alt="Global Dashboard" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Export/Import Configurations
&lt;/h3&gt;

&lt;p&gt;For those who manage multiple systems, want a backup of your configuration, or want to share your configurations with your friends and colleagues, you can now export and import Ostara configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instance Shutdown
&lt;/h3&gt;

&lt;p&gt;We've added support for the shutdown capability on Actuator, allowing you to shutdown your instances directly from Ostara;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pyc9bEf_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32s3zp4rolbba75cxwx4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pyc9bEf_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32s3zp4rolbba75cxwx4.gif" alt="Shutdown example" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And a lot more! You can find the full changelog at the end of this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Start with Ostara
&lt;/h3&gt;

&lt;p&gt;If you're ready to dive into Ostara 0.10.0, head over to our &lt;a href="https://ostara.dev"&gt;website&lt;/a&gt;, download the version for your OS, and follow the &lt;a href="https://docs.ostara.dev/getting-started/quick-start"&gt;Quick Start guide&lt;/a&gt;. You'll be up and monitoring in no time!&lt;/p&gt;

&lt;h3&gt;
  
  
  Contributions
&lt;/h3&gt;

&lt;p&gt;Ostara is in pre release so we would greatly appreciate any feedback, recommendations and/or requests as well as any contributions. We would also love to hear from other Spring Boot developers. Head to the &lt;a href="https://github.com/krud-dev/ostara"&gt;repository&lt;/a&gt; to participate and keep an eye out for our upcoming Beta program!&lt;/p&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;p&gt;Changelog: &lt;a href="https://docs.ostara.dev/getting-started/changelog"&gt;https://docs.ostara.dev/getting-started/changelog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ostara home: &lt;a href="https://ostara.dev"&gt;https://ostara.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ostara repository: &lt;a href="https://github.com/krud-dev/ostara"&gt;https://github.com/krud-dev/ostara&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ostara documentation: &lt;a href="https://docs.ostara.dev/"&gt;https://docs.ostara.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Join us on Discord! &lt;a href="https://discord.gg/8pUtGUYncD"&gt;https://discord.gg/8pUtGUYncD&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>opensource</category>
      <category>discuss</category>
      <category>devops</category>
    </item>
    <item>
      <title>Introducing Ostara</title>
      <dc:creator>Idan Elhalwani</dc:creator>
      <pubDate>Tue, 16 May 2023 13:09:11 +0000</pubDate>
      <link>https://dev.to/krud/introducing-ostara-3o6b</link>
      <guid>https://dev.to/krud/introducing-ostara-3o6b</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--POLUvm7M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8xpnsrv87hpb9pp8qr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--POLUvm7M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8xpnsrv87hpb9pp8qr8.png" alt="Ostara UI" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(A previous version of this article introduced Ostara under its previous name, Boost, the article has been amended to reflect this)&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Ostara
&lt;/h2&gt;

&lt;p&gt;Ostara is a modern tool for managing and monitoring actuator-enabled microservices that aims to make the process more user-friendly and straightforward. &lt;/p&gt;

&lt;p&gt;One of our main goals with Ostara was to create a tool that just works out of the box, without needing anything besides a functioning Actuator API on the other end.&lt;/p&gt;

&lt;p&gt;Ostara allows you to gain insights into the performance and health of your microservices by providing real-time monitoring of critical metrics such as CPU and memory usage.&lt;/p&gt;

&lt;p&gt;One of the key benefits of Ostara is its simplicity. The tool is designed to be easy to use and requires minimal setup. All you need is a running instance of your microservice with Actuator enabled, and you can start monitoring and managing it with Ostara.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;The first question to ask is &lt;strong&gt;&lt;u&gt;why even use Ostara, when excellent tools such as Spring Boot Admin already exist?&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As Spring Boot Admin users, we had to ask ourselves this question before embarking on the development journey of Ostara.&lt;/p&gt;

&lt;p&gt;For all its greatness, one thing Spring Boot Admin that cannot be said about Spring Boot Admin is that it's plug and play or 'off-the-shelf'.&lt;/p&gt;

&lt;p&gt;To setup Spring Boot Admin, we start by having to create Spring project for the server itself (In our case, which is true for many, also meant we have to setup a full CI/CD flow, complete with Helm charts and Docker images in order to create a full production flow)&lt;/p&gt;

&lt;p&gt;If we needed additional features such as authentication, notifications and so on, we would need to add them directly to the project. &lt;/p&gt;

&lt;p&gt;All of this, despite the infinite versatility it offers (because it is essentially a blank slate), raises the startup costs of Spring Boot Admin considerably and even more so when you remember that you have to continually maintain this project as with any other project within your code ecosystem, either due to security updates to unrelated dependencies you may have needed to add, or in order to update Spring to match your main project(s).&lt;/p&gt;

&lt;p&gt;But aren't there ready-made images of Spring Boot Admin Server? A quick Google search will show a few (often outdated) pre-built ones that people in the community have created for different scenarios, including this official &lt;code&gt;codecentric/spring-boot-admin&lt;/code&gt; Docker image which states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This repository contains pre-build Docker Images containing basic and hence not production-ready builds of Spring Boot Admin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now onto the client, in order to register instances on Spring Boot Admin, you have to add the &lt;code&gt;spring-boot-admin-starter-client&lt;/code&gt; dependency to your app and point it at the admin server. From personal production experience in mature projects, this isn't always a pleasant, straightforward experience.&lt;/p&gt;

&lt;p&gt;If your project guards Actuator's endpoints with Spring Security, you also have to configure the client to send the server the credentials it will need when registering itself.&lt;/p&gt;

&lt;p&gt;Alternatively, if you use Spring Cloud Discovery within your ecosystem you will be able to use that in order to discover instances, dependency free, but not hassle free, as you will again have to add this to your server's project and configure on both ends.&lt;/p&gt;

&lt;p&gt;The second part is performance. Spring Boot Admin lacks in a lot of areas when it comes to performance. The simplest example is the Thread Dump page, where if you stick around long enough without refreshing, it will eventually crash your tab.&lt;/p&gt;

&lt;p&gt;With Ostara, we aimed for a solution that just &lt;em&gt;works&lt;/em&gt; performantly with your existing setups, no matter their size &lt;br&gt;
 or scale and without requiring any prior modifications in your code or environment with the only prerequisite being the presence of Spring Actuator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Overview
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A robust and user-friendly UI for an ever-growing list of Actuator endpoints (&lt;a href="https://docs.ostara.dev/features/instance-features/insights"&gt;Full list&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Health monitoring of your applications and their individual instances&lt;/li&gt;
&lt;li&gt;Neatly organize your applications and instances into different folders, with color coding and unique icons&lt;/li&gt;
&lt;li&gt;Modify the loggers of your applications and individual instances on the fly&lt;/li&gt;
&lt;li&gt;Evict caches from applications and individual instances on the fly&lt;/li&gt;
&lt;li&gt;View cache statistics&lt;/li&gt;
&lt;li&gt;View HTTP request statistics&lt;/li&gt;
&lt;li&gt;Bean dependency visualization&lt;/li&gt;
&lt;li&gt;Spring Integration Graph visualization&lt;/li&gt;
&lt;li&gt;Application Security built in, interact with your secured Actuator instances with no extra code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Future
&lt;/h2&gt;

&lt;p&gt;Some of our planned features for future releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service discovery support&lt;/li&gt;
&lt;li&gt;Notifications&lt;/li&gt;
&lt;li&gt;Custom themes&lt;/li&gt;
&lt;li&gt;A plugin ecosystem for custom Actuator endpoints&lt;/li&gt;
&lt;li&gt;Support for non-official actuator endpoints, such as &lt;a href="https://www.togglz.org/documentation/spring-boot-starter.html"&gt;Togglz&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Native support for non-Spring Actuator facades such as &lt;a href="https://gitlab.com/mikeyGlitz/gohealth"&gt;gohealth&lt;/a&gt;, &lt;a href="https://github.com/rcruzper/express-actuator"&gt;express-actuator&lt;/a&gt; and &lt;a href="https://github.com/SolarEdgeTech/pyctuator"&gt;pyctuator&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up Ostara
&lt;/h2&gt;

&lt;p&gt;Setting up Ostara is super simple, simply head over and download the &lt;a href="https://github.com/krud-dev/ostara/releases/latest"&gt;latest release&lt;/a&gt; for your OS and follow the &lt;a href="https://docs.ostara.dev/getting-started/quick-start"&gt;Quick Start&lt;/a&gt; to create your first instance and begin monitoring with Ostara&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributions
&lt;/h2&gt;

&lt;p&gt;Ostara is in pre release so we would greatly appreciate any feedback, recommendations and/or requests as well as any contributions. We would also love to hear from other Spring Boot developers. Head to the &lt;a href="https://github.com/krud-dev/ostara"&gt;repository&lt;/a&gt; to participate!&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ostara home: &lt;a href="https://ostara.dev"&gt;https://ostara.dev&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ostara repository: &lt;a href="https://github.com/krud-dev/ostara"&gt;https://github.com/krud-dev/ostara&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ostara documentation: &lt;a href="https://docs.ostara.dev/"&gt;https://docs.ostara.dev/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>spring</category>
      <category>devops</category>
      <category>java</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Spring Boot + Electron, a case study</title>
      <dc:creator>Idan Elhalwani</dc:creator>
      <pubDate>Mon, 15 May 2023 11:45:08 +0000</pubDate>
      <link>https://dev.to/krud/spring-boot-electron-a-case-study-2p75</link>
      <guid>https://dev.to/krud/spring-boot-electron-a-case-study-2p75</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;We recently finished writing our desktop app for Spring Actuator, &lt;a href="https://github.com/krud-dev/ostara/" rel="noopener noreferrer"&gt;Ostara&lt;/a&gt;. Initially, we decided to rely on Electron's main process and write our "backend" in Node. We quickly hit roadblock after roadblock, until a decision was made to ditch the backend entirely, rewrite it in Spring Boot and Kotlin in the JVM ecosystem, and have the renderer communicate with it via REST.&lt;/p&gt;

&lt;p&gt;We did this for a multitude of reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First and foremost, we wanted the versatility of being able to run the project on and off Electron, and possibly with a remote backend. Our initial Node implementation relied heavily on IPC between the main and renderer and we knew that, for the most part, had to go.&lt;/li&gt;
&lt;li&gt;It's a mature and robust ecosystem, and especially one where we knew we would be able to make rapid progress&lt;/li&gt;
&lt;li&gt;We would be able to leverage our own JVM libraries, namely &lt;a href="https://shapeshift.krud.dev/" rel="noopener noreferrer"&gt;ShapeShift&lt;/a&gt; and a yet-unreleased framework we use for CRUD operations with traditional ORMs and ODMs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ecosystem Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/krud-dev/ostara/" rel="noopener noreferrer"&gt;Ostara&lt;/a&gt; is based off of &lt;a href="https://github.com/electron-react-boilerplate/electron-react-boilerplate" rel="noopener noreferrer"&gt;electron-react-boilerplate&lt;/a&gt; and uses &lt;a href="https://www.electron.build/" rel="noopener noreferrer"&gt;electron-builder&lt;/a&gt; to package the application.&lt;/p&gt;

&lt;p&gt;The daemon uses JDK 17 with Kotlin, Spring Boot and Gradle&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Daemon
&lt;/h2&gt;

&lt;p&gt;Before we set out to research and implement this daemon for Ostara, we laid out a list of requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A user should not need to install Java.&lt;/li&gt;
&lt;li&gt;No significant downgrades to the developer experience.&lt;/li&gt;
&lt;li&gt;The daemon process should be robust and resilient.&lt;/li&gt;
&lt;li&gt;Support two-way communication in a manner that is similar to IPC, but doesn't tie us to Electron.&lt;/li&gt;
&lt;li&gt;The startup time for the daemon should be under 20 seconds at all times.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's break these down.&lt;/p&gt;

&lt;h3&gt;
  
  
  A user should not need to install Java
&lt;/h3&gt;

&lt;p&gt;The rationale here is simple, right? The user installed your app, they don't really care about your app's dependencies, and they certainly don't want to be given (either automatically or otherwise) a shopping list before they can use it. &lt;/p&gt;

&lt;p&gt;Now, this may sound like a silly argument to make when you realize Ostara's primary target audience is &lt;em&gt;JVM developers&lt;/em&gt; who certainly have JDK on their workstation. But &lt;em&gt;which&lt;/em&gt; JDK? Spring Boot developers come in all shapes and sizes, some will still run JDK 8 on their workstation while others will be on the cutting edge.&lt;/p&gt;

&lt;p&gt;Overall, the goal of this requirement was to reduce our footprint and (visible) overhead as much as possible while allowing maximum versatility.&lt;/p&gt;

&lt;p&gt;Now right off the bat, let me just say that an alternative to this process called &lt;a href="https://docs.oracle.com/javase/9/tools/jlink.htm" rel="noopener noreferrer"&gt;jlink&lt;/a&gt; exists. We opted not to use it, so I will not elaborate on it further.&lt;/p&gt;

&lt;p&gt;The app is packaged 4 times, once for Windows (x64), once for Linux (x64), and twice for Mac (ARM and x64). Each one of these has its own unique JDK.&lt;/p&gt;

&lt;p&gt;The goal would be to download the respective JDK, where it would eventually find its way inside the finished package for each operating system and architecture.&lt;/p&gt;

&lt;p&gt;An additional goal we set was to avoid bloating the repository with zip files that we can easily download on the spot and being forced to use Git LFS, so committing the JDKs was not an option.&lt;/p&gt;

&lt;p&gt;To achieve the procurement part, we wrote &lt;a href="https://github.com/krud-dev/ostara/blob/master/devops/jdkutil.py" rel="noopener noreferrer"&gt;jdkutil&lt;/a&gt;, a pure Python tool with no external dependencies.&lt;/p&gt;

&lt;p&gt;The tool is very simple in its operation. Given a list of categorized URLs (In our case, &lt;a href="https://github.com/krud-dev/ostara/blob/master/devops/jdks.csv" rel="noopener noreferrer"&gt;this csv&lt;/a&gt;), it will download them, verify the checksum matches, and unzip them into a directory tree matching this pattern: &lt;code&gt;{platform}/{arch}/jdk&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As a visual example, for the four variants above we will receive the following tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jdks/
├── linux
│   └── x64
│       └── jdk
├── mac
│   ├── arm64
│   │   └── jdk
│   └── x64
│       └── jdk
└── windows
    └── x64
        └── jdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the JDKs were ready in this format, all we had to do was add the following to the &lt;code&gt;extraResources&lt;/code&gt; block of the &lt;code&gt;build&lt;/code&gt; section within our &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"extraResources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jdks/${os}/${arch}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"filter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"**/*"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;electron-builder&lt;/code&gt; runs, it will &lt;a href="https://www.electron.build/file-patterns#file-macros" rel="noopener noreferrer"&gt;populate&lt;/a&gt; &lt;code&gt;${os}&lt;/code&gt; and &lt;code&gt;${arch}&lt;/code&gt; according to the operating system and architecture being built, so at the end of this process we should have an arch specific, OS specific folder called &lt;code&gt;jdk&lt;/code&gt; in every package that we create, with the correct JDK for the designated platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  No significant downgrades to the developer experience
&lt;/h3&gt;

&lt;p&gt;While a developer is expected to have JDK 17 installed, if they are only working on the Electron side there should be no additional steps to run or perform.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup
&lt;/h4&gt;

&lt;p&gt;A "frontend" developer shouldn't need to setup a working environment to work on the daemon, but they will still need to be able to run the current development version and build it from scratch.&lt;/p&gt;

&lt;p&gt;Likewise, a "backend" developer should be able to run their daemon from their IDE of choice and be able to hook it up to the process.&lt;/p&gt;

&lt;p&gt;Finally, in a packaged state we will have a jar as well as a custom JDK that we will need to use.&lt;/p&gt;

&lt;p&gt;This lead us to split the way we start the daemon into two ways.&lt;/p&gt;

&lt;p&gt;The first is the "Packaged" approach, where Electron already knows the location of a prebuilt JAR and simply runs the process. &lt;/p&gt;

&lt;p&gt;The second is the "Remote" approach. In this approach, Electron doesn't actually start the process, but simply receives a predetermined port and address (Usually localhost) and creates a connection with the daemon over HTTP.&lt;/p&gt;

&lt;p&gt;The remote approach covers both development use-cases. In order to achieve this, we split our &lt;code&gt;start&lt;/code&gt; command into two:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"concurrently &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;npm run start:daemon&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;ts-node ./.erb/scripts/check-port-in-use.js &amp;amp;&amp;amp; npm run start:renderer&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start:thin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ts-node ./.erb/scripts/check-port-in-use.js &amp;amp;&amp;amp; npm run start:renderer"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A "frontend" developer in this case would run &lt;code&gt;start&lt;/code&gt;, which would then in turn compile and run the daemon locally. Since the app isn't packaged, the app will automatically determine that it needs to use a Remote daemon with the default host and port.&lt;/p&gt;

&lt;p&gt;A "backend" developer would run &lt;code&gt;start:thin&lt;/code&gt; which essentially does everything except start the daemon, with the expectation that the daemon is already running. Like the previous example, the app will automatically determine that it needs to use a Remote daemon with the default host and port.&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementing health checks
&lt;/h4&gt;

&lt;p&gt;Since the Daemon, like any process had the possibility of crashing or freezing, the next step was to implement health checks. We opted for a simple polling HTTP health check from the Electron main process to the daemon.&lt;/p&gt;

&lt;p&gt;For this process we created 3 events in the Electron main process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;daemon-ready&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;daemon-healthy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;daemon-unhealthy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The flow created around these events is simple.&lt;/p&gt;

&lt;p&gt;Upon app start, the user will be sent to the splash screen. Once the &lt;code&gt;daemon-ready&lt;/code&gt; event is fired, the splash screen is closed and is replaced by the main screen. If at any point during this time we receive the &lt;code&gt;daemon-unhealthy&lt;/code&gt; event, the user's screen is replaced with the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4fuwl01gujitj04tj2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4fuwl01gujitj04tj2r.png" alt="Example of crashed daemon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If, during this time, &lt;code&gt;daemon-healthy&lt;/code&gt; is fired, then the screen returns to normal.&lt;/p&gt;

&lt;h4&gt;
  
  
  Support two-way communication in a manner that is similar to IPC, but doesn't tie us to Electron
&lt;/h4&gt;

&lt;p&gt;To achieve two-way communication between the Electron renderer and the daemon, we opted to use Websockets with the STOMP protocol. This approach decoupled the communication between the renderer and the daemon from the Electron framework, allowing for greater flexibility in the future and the ability to break away from Electron entirely if needed&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In conclusion, despite the unorthodox choice, we successfully developed a robust and resilient daemon for our Electorn app using Spring Boot, all while addressing our primary goals.&lt;/p&gt;

&lt;p&gt;By doing so, we have created a flexible and scalable app that can run on and off Electron with the potential for remote backend functionality. Additionally, we have opened the door for further expansion and improvements in the future, should the need arise.&lt;/p&gt;

</description>
      <category>electron</category>
      <category>springboot</category>
      <category>kotlin</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Creating an automatic Helm Repository with GitHub Actions</title>
      <dc:creator>Idan Elhalwani</dc:creator>
      <pubDate>Wed, 10 Feb 2021 15:35:00 +0000</pubDate>
      <link>https://dev.to/krud/creating-an-automatic-helm-repository-with-github-actions-2ml5</link>
      <guid>https://dev.to/krud/creating-an-automatic-helm-repository-with-github-actions-2ml5</guid>
      <description>&lt;p&gt;I needed a Helm repository to house my private charts, but at the same time I didn't want to have to deal with and maintain a server for it.&lt;/p&gt;

&lt;p&gt;In my research I discovered that it is possible and quite easy to use a git repository for this purpose. Great! However, I feel that did not go far enough for my use. For once, I did not want to have to manually package and index the repository on every chart change and so I decided to expand on it. &lt;/p&gt;

&lt;h2&gt;
  
  
  The end result
&lt;/h2&gt;

&lt;p&gt;At the end, we should have a Helm repository that updates itself on every change to the git repository structured as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── master
│   ├── charts/
│   │   └── example/
│   └── sync_repo.sh
└── repo
    ├── example-0.1.0.tgz
    └── index.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full example is available at my &lt;a href="https://github.com/Idane/helm-repo-example"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;For this, create a new git repository, clone it locally and create a new chart in the &lt;code&gt;charts&lt;/code&gt; directory;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;charts
&lt;span class="nb"&gt;cd &lt;/span&gt;charts
helm create example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's done and committed, we will create an &lt;strong&gt;orphan branch&lt;/strong&gt; to store the actual Helm repository. Why an orphan branch? On every commit to the repository, CircleCI will do its own commit to update the Helm repository. &lt;/p&gt;

&lt;p&gt;While this step is optional, it prevents developers from having to pull-rebase every time they make a change to the repo, and has the added benefit of keeping the history of the master branch clean.&lt;br&gt;
Create an orphan branch called &lt;code&gt;repo&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;--orphan&lt;/span&gt; repo
git &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; 
&lt;span class="nb"&gt;touch &lt;/span&gt;index.yaml
git add index.yaml
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'Initial Commit'&lt;/span&gt;
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's return to the &lt;code&gt;master&lt;/code&gt; branch. Our next step is to create a script which our CI will use on every commit. The script will package all charts, and re-generate the &lt;code&gt;index.yaml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Use your text editor of choice to create &lt;code&gt;sync_repo.sh&lt;/code&gt; and add the following to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; repo
&lt;span class="nb"&gt;cd &lt;/span&gt;repo
helm package ../charts/&lt;span class="k"&gt;*&lt;/span&gt;
helm repo index &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At last, we add the last piece of this puzzle and integrate GitHub Actions into this process. &lt;/p&gt;

&lt;p&gt;Our action will pick off where our shell script left us off; It will clone the separate &lt;code&gt;repo&lt;/code&gt; branch and copy the generated files to it, finally committing and pushing back the changes to origin.&lt;/p&gt;

&lt;p&gt;For this, we'll create the following action at &lt;code&gt;.github/workflows/sync_repo.yml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sync Helm Repo&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;master&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;master'&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;master'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;repo'&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;repo'&lt;/span&gt;   
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure/setup-helm@v1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sync Helm Repo&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd master &amp;amp;&amp;amp; sh sync_repo.sh&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Move repo folder&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;mv master/repo/* repo/&lt;/span&gt;
          &lt;span class="s"&gt;cd repo&lt;/span&gt;
          &lt;span class="s"&gt;git config user.email "idan@elhalwani.com"&lt;/span&gt;
          &lt;span class="s"&gt;git config user.name "Idan Elhalwani"&lt;/span&gt;
          &lt;span class="s"&gt;git add -A&lt;/span&gt;
          &lt;span class="s"&gt;git diff --quiet &amp;amp;&amp;amp; git diff --staged --quiet || git commit -m "Update repo [SKIP CI]" -m "${{ github.event.head_commit.message }}"&lt;/span&gt;
          &lt;span class="s"&gt;git push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down the action;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Move our generated files from the master branch folder to the repo branch folder&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;master/repo/&lt;span class="k"&gt;*&lt;/span&gt; repo/
&lt;span class="nb"&gt;cd &lt;/span&gt;repo
&lt;span class="c"&gt;# Configure git for when we're ready to commit&lt;/span&gt;
git config user.email &lt;span class="s2"&gt;"idan@elhalwani.com"&lt;/span&gt;
git config user.name &lt;span class="s2"&gt;"Idan Elhalwani"&lt;/span&gt;
&lt;span class="c"&gt;# Add all new files and attempt to commit. If there is nothing new, the commit won't go through and nothing will be pushed&lt;/span&gt;
git add &lt;span class="nt"&gt;-A&lt;/span&gt;
git diff &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git diff &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Update repo [SKIP CI]"&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ github.event.head_commit.message &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;At this point, we have a fully functional and automatically updating Helm repository. To use it, get the raw URL for the &lt;code&gt;repo&lt;/code&gt; branch. &lt;/p&gt;

&lt;p&gt;In our case, we will add the repository as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add example https://raw.githubusercontent.com/idane/helm-repo-example/repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>helm</category>
      <category>kubernetes</category>
      <category>github</category>
      <category>ci</category>
    </item>
  </channel>
</rss>
