<?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>Forem: Babu Annamalai</title>
    <description>The latest articles on Forem by Babu Annamalai (@mysticmind).</description>
    <link>https://forem.com/mysticmind</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%2F773133%2Ff83155a8-3541-4fd4-acd6-ba36f9fcb7b5.jpeg</url>
      <title>Forem: Babu Annamalai</title>
      <link>https://forem.com/mysticmind</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mysticmind"/>
    <language>en</language>
    <item>
      <title>How to create unique file names in bash shell</title>
      <dc:creator>Babu Annamalai</dc:creator>
      <pubDate>Wed, 12 Apr 2023 08:39:05 +0000</pubDate>
      <link>https://forem.com/mysticmind/how-to-create-unique-file-names-in-bash-shell-462j</link>
      <guid>https://forem.com/mysticmind/how-to-create-unique-file-names-in-bash-shell-462j</guid>
      <description>&lt;p&gt;For debugging purposes, we had to profile a python program using &lt;code&gt;cProfile&lt;/code&gt; which will create a &lt;code&gt;.prof&lt;/code&gt; file with the profiled data. Also we wanted to create unique file names for each run using a bash shell.&lt;/p&gt;

&lt;p&gt;We had couple of options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Unix epoch time which is a number and can be suffixed to a file to make it unique.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;uuidgen&lt;/code&gt; to create a GUID. Since it is for dev/debugging purposes, we wanted to shorten it and use only the last part of the GUID. I am quite aware that just using the last part may not be always unique, it is for some dev/debugging so it is okay for our purposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will run through to how to generate a unique file name using both the methods below:&lt;/p&gt;

&lt;p&gt;In the below script, we are using &lt;code&gt;$(date +"%s")&lt;/code&gt; which provide the current date time as an epoch. The output is something like &lt;code&gt;test-1681287886.prof&lt;/code&gt;&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="nv"&gt;PROFILE_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;test-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s2"&gt;"%s"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;.prof
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROFILE_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with the below script, we using a combination of &lt;code&gt;uuidgen&lt;/code&gt; and piping it to &lt;code&gt;cut&lt;/code&gt; to get the last part of GUID. The output is like &lt;code&gt;test-5F4C3E649454.prof&lt;/code&gt;. With regards to the args for &lt;code&gt;cut&lt;/code&gt;, &lt;code&gt;-d "-"&lt;/code&gt; argument refers to using &lt;code&gt;-&lt;/code&gt; as the delimiter and &lt;code&gt;-f5&lt;/code&gt; argument refers to getting the 5th field from the array after splitting 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="nv"&gt;PROFILE_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;test-&lt;span class="si"&gt;$(&lt;/span&gt;uuidgen | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"-"&lt;/span&gt; &lt;span class="nt"&gt;-f5&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;.prof
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROFILE_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>bash</category>
    </item>
    <item>
      <title>VitePress fenced code block syntax highlighting quirks with .NET or other languages.</title>
      <dc:creator>Babu Annamalai</dc:creator>
      <pubDate>Wed, 12 Oct 2022 02:41:29 +0000</pubDate>
      <link>https://forem.com/mysticmind/vitepress-fenced-code-block-syntax-highlighting-quirks-with-net-or-other-languages-ci4</link>
      <guid>https://forem.com/mysticmind/vitepress-fenced-code-block-syntax-highlighting-quirks-with-net-or-other-languages-ci4</guid>
      <description>&lt;p&gt;This post was originally published at &lt;a href="https://mysticmind.dev/vitepress-fenced-code-block-syntax-highlighting-quirks-with-net-or-other-languages"&gt;https://mysticmind.dev/vitepress-fenced-code-block-syntax-highlighting-quirks-with-net-or-other-languages&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VitePress uses &lt;a href="https://github.com/shikijs/shiki"&gt;Shiki&lt;/a&gt; for syntax highlighting which is a fantastic library. Shiki automatically fetches language grammar from VSCode so the language names etc for the fenced code block comes from it. &lt;/p&gt;

&lt;p&gt;For .NET, the language names captured are &lt;code&gt;csharp&lt;/code&gt; and &lt;code&gt;fsharp&lt;/code&gt; by default. This means that the syntax highlighting will work only if you use &lt;code&gt;csharp&lt;/code&gt; or &lt;code&gt;fsharp&lt;/code&gt;. But idiomatic usage use the file extensions &lt;code&gt;cs&lt;/code&gt; and &lt;code&gt;fs&lt;/code&gt; for syntax highlighting so this tends to be an issue. I did send a PR to Shiki to resolve this. But there are many moving parts i.e. Shiki will need to do a release with the fix then VitePress picking it up and in turn do a release.&lt;/p&gt;

&lt;p&gt;If you are stuck, not only with .NET languages or any other language as well, there is a easy fix under your control. Edit your VitePress &lt;code&gt;config.js&lt;/code&gt; file and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BUNDLED_LANGUAGES&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shiki&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Include `cs` as alias for csharp&lt;/span&gt;
&lt;span class="nx"&gt;BUNDLED_LANGUAGES&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;csharp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;aliases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Include `fs` as alias for fsharp&lt;/span&gt;
&lt;span class="nx"&gt;BUNDLED_LANGUAGES&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fsharp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;aliases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>vitepress</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>A fun little poem on frontend JS frameworks</title>
      <dc:creator>Babu Annamalai</dc:creator>
      <pubDate>Fri, 08 Apr 2022 16:54:49 +0000</pubDate>
      <link>https://forem.com/mysticmind/a-fun-little-poem-on-frontend-js-frameworks-4kbc</link>
      <guid>https://forem.com/mysticmind/a-fun-little-poem-on-frontend-js-frameworks-4kbc</guid>
      <description>&lt;p&gt;I took the popular JS frontend frameworks in &lt;a href="https://2021.stateofjs.com/en-US/libraries/front-end-frameworks"&gt;The state of JS 2021&lt;/a&gt; and wanted to write a little fun poem including most of them. Here is my take below:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let your mind be Lit with Vue, Stimulus and Ember to Vite your way with Svelte in an Angular vortex. Alpine in the Solid woods will make you Preact but don't React. Eventually everything is a Remix. Eagerly waiting for what is Next. :-)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that there is no implied meaning to how the poem is structured. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>.NET build tool using Bullseye and SimpleExec</title>
      <dc:creator>Babu Annamalai</dc:creator>
      <pubDate>Wed, 23 Feb 2022 06:28:08 +0000</pubDate>
      <link>https://forem.com/mysticmind/net-build-tool-using-bullseye-and-simpleexec-1jbe</link>
      <guid>https://forem.com/mysticmind/net-build-tool-using-bullseye-and-simpleexec-1jbe</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published at &lt;a href="https://mysticmind.dev/dotnet-build-tool-using-bullseye-and-simpleexec"&gt;https://mysticmind.dev/dotnet-build-tool-using-bullseye-and-simpleexec&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt; was quite a popular build tool used by projects of all sizes targeting .NET Framework on Windows. I have written many complex build systems using NAnt in the past. But XML based DSL was quite clunky to use and maintain. Besides, it was always a daunting task to explain to a new dev on the team. With .NET Core/.NET becoming a cross-platform framework, &lt;a href="https://cakebuild.net/"&gt;CAKE&lt;/a&gt; and &lt;a href="https://fake.build/"&gt;FAKE&lt;/a&gt; gained a lot of adoption providing a C# and F# based DSL for build tasks accordingly. &lt;/p&gt;

&lt;p&gt;I personally advocate &lt;a href="https://github.com/adamralph/bullseye"&gt;Bullseye&lt;/a&gt; in combination with &lt;a href="https://github.com/adamralph/simple-exec"&gt;SimpleExec&lt;/a&gt; as a build tool for .NET projects due to its sheer simplicity by providing a bare bones API to define the tasks and their dependent tasks in plain C# code. Both these libraries are build by &lt;a href="https://twitter.com/adamralph"&gt;Adam Ralph&lt;/a&gt;. It does not enforce any specific model or structure to write your build tasks. When someone runs through the build script, it is fairly straight forward to understand whats going on. We use this build tool setup for &lt;a href="https://github.com/JasperFx/marten"&gt;Marten&lt;/a&gt; for both local dev and CI build tasks and has worked well so far. Also many OSS projects have adopted it.&lt;/p&gt;

&lt;p&gt;We will take a simple &lt;a href="https://github.com/mysticmind/bullseye-sample"&gt;sample .NET project&lt;/a&gt; available in GitHub which has the following setup and then attempt to add a build script for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;code&gt;src/WebApp&lt;/code&gt; folder contains a .NET 6 web app with a Razor page to serve the index. The project uses minimal API. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/WebApp/static/css/site.css&lt;/code&gt; contains the css file for the web app which is referenced in the Razor page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;package.json&lt;/code&gt; at the root folder which has dev dependencies to &lt;code&gt;esbuild&lt;/code&gt; and defines 2 scripts as below:

&lt;ul&gt;
&lt;li&gt;minify - &lt;code&gt;esbuild --minify ./src/WebApp/static/css/site.css --outdir=./src/WebApp/wwwroot/css&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;watch - &lt;code&gt;esbuild --watch ./src/WebApp/static/css/site.css --outdir=./src/WebApp/wwwroot/css&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;ESBuild is used to minify the static assets i.e. css files from &lt;code&gt;src/WebApp/static/css&lt;/code&gt;  and adds it under &lt;code&gt;wwwroot/css&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let us look at adding a build script using Bullseye and SimpleExec:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;build&lt;/code&gt; folder at the top level&lt;/li&gt;
&lt;li&gt;Add a new console project under the &lt;code&gt;build&lt;/code&gt; folder as below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new console
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;Bullseye&lt;/code&gt;  and &lt;code&gt;SimpleExec&lt;/code&gt; NuGet packages to &lt;code&gt;build.csproj&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Bullseye
dotnet add package SimpleExec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;Program.cs&lt;/code&gt; to add the build targets in your favourite editor and add the following code (uses .NET 6 minimal API). The inline comments should be self explanatory.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Bullseye&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Targets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;SimpleExec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create a build target for npm install to make esbuild available for use&lt;/span&gt;
&lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"npm:install"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"install"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Create build target esbuild:dist target which will minify&lt;/span&gt;
&lt;span class="c1"&gt;// CSS under static/css and add it to wwwroot/css folder&lt;/span&gt;
&lt;span class="c1"&gt;// This build target has a depedency on `npm:install` build target&lt;/span&gt;

&lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"esbuild:dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;DependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"npm:install"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"run minify"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Create build target esbuild:dist target which will allow to&lt;/span&gt;
&lt;span class="c1"&gt;// watch for changes in dev env&lt;/span&gt;
&lt;span class="c1"&gt;// This build target has a depedency on `npm:install` build target&lt;/span&gt;
&lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"esbuild:watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;DependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"npm:install"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"run watch"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Create a build target Clean the web project output from previous build&lt;/span&gt;
&lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"clean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dotnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"clean src/WebApp/WebApp.csproj"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Create a build target to compile the web project&lt;/span&gt;
&lt;span class="c1"&gt;// This build target depends on `clean` build target&lt;/span&gt;
&lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"compile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;DependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"clean"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dotnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"build ./src/WebApp/WebApp.csproj -c Release"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Create a build target to watch for changes in dev&lt;/span&gt;
&lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dotnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"watch --project ./src/WebApp/WebApp.csproj"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Create a default target&lt;/span&gt;
&lt;span class="c1"&gt;// This target depends on `esbuild:dist` and `compile` build targets&lt;/span&gt;
&lt;span class="nf"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;DependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"esbuild:dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"compile"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// run the build target requested and exit&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;RunTargetsAndExitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;At the top level folder, let us create &lt;code&gt;build.sh&lt;/code&gt; with executable permission as below to be used in *nix environments to run a the build
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

dotnet run &lt;span class="nt"&gt;--project&lt;/span&gt; build/build.csproj &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;build.cmd&lt;/code&gt; with the following content to be used in Windows commandline
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@echo Off
dotnet run --project build/build.csproj -- %*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;build.ps1&lt;/code&gt; with the following content to be used from PowerShell prompt
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="bp"&gt;$Error&lt;/span&gt;&lt;span class="n"&gt;ActionPreference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stop"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build/build.csproj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$args&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To run the default build target, we use the below:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see an output as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
...
Time Elapsed 00:00:04.88
build: compile: Succeeded &lt;span class="o"&gt;(&lt;/span&gt;5.66 s&lt;span class="o"&gt;)&lt;/span&gt;
build: default: Succeeded
build: ──────────────────────────────────────
build: Target        Outcome    Duration
build: ────────────  ─────────  ─────────────
build: npm:install   Succeeded  868 ms  10.1%
build: esbuild:dist  Succeeded  206 ms  2.4%
build: clean         Succeeded  1.82 s  21.3%
build: compile       Succeeded  5.66 s  66.1%
build: default       Succeeded
build: ──────────────────────────────────────
build: Succeeded &lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;8.55 s&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To run any other build target, pass the target name as the parameter to the build file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In this example, `esbuild:dist` is the build target&lt;/span&gt;
./build.sh esbuild:dist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see an output as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
...
⚡ Done &lt;span class="k"&gt;in &lt;/span&gt;4ms
build: esbuild:dist: Succeeded &lt;span class="o"&gt;(&lt;/span&gt;184 ms&lt;span class="o"&gt;)&lt;/span&gt;
build: ──────────────────────────────────────
build: Target        Outcome    Duration
build: ────────────  ─────────  ─────────────
build: npm:install   Succeeded  1.58 s  89.6%
build: esbuild:dist  Succeeded  184 ms  10.4%
build: ──────────────────────────────────────
build: Succeeded &lt;span class="o"&gt;(&lt;/span&gt;esbuild:dist&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1.76 s&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to make changes with hot reload in dev, you would run the .NET project with watch using build script &lt;code&gt;./build.sh watch&lt;/code&gt; and also the ESBuild task for CSS &lt;code&gt;./build.sh esbuild:watch&lt;/code&gt; on two terminal windows and work with it. Build tool shortens the typing required to run things.&lt;/p&gt;

&lt;p&gt;Bullseye generates a nice coloured output on the terminal and also adapts the colour profile according to the CI environments such as GitHub, GitLab etc.&lt;/p&gt;

&lt;p&gt;If you are looking at a more full fledged build tool in action, you can take a look at the build tool setup for Marten &lt;a href="https://github.com/JasperFx/marten/tree/master/build"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding :-)&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>build</category>
    </item>
    <item>
      <title>GitHub action to publish .NET packages to NuGet</title>
      <dc:creator>Babu Annamalai</dc:creator>
      <pubDate>Wed, 23 Feb 2022 06:19:57 +0000</pubDate>
      <link>https://forem.com/mysticmind/github-action-to-publish-net-packages-to-nuget-59nf</link>
      <guid>https://forem.com/mysticmind/github-action-to-publish-net-packages-to-nuget-59nf</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published at &lt;a href="https://mysticmind.dev/github-action-to-publish-net-packages-to-nuget"&gt;https://mysticmind.dev/github-action-to-publish-net-packages-to-nuget&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I have been a co-maintainer of .NET OSS library &lt;a href="https://github.com/JasperFx/marten"&gt;Marten&lt;/a&gt; and largely involved in taking care of the DevOps stuff pertaining to CI pipeline, build and docs system. In the early days, the build was driven using a &lt;a href="https://github.com/ruby/rake"&gt;RAKE&lt;/a&gt; build script written by &lt;a href="https://twitter.com/jeremydmiller"&gt;Jeremy Miller&lt;/a&gt;, our lead dev and creator of Marten. NuGet packages were published from the local dev machine after confirming that we had bumped up the versions of the packages in preparation for the release. Apparently, this being a manual step, we publish the NuGet packages but sometimes tend to forget tagging and creation of release in GitHub (you know how an OSS author life is around managing day job and doing open source work).&lt;/p&gt;

&lt;p&gt;We were also using &lt;a href="https://www.appveyor.com/"&gt;AppVeyor&lt;/a&gt; for CI during the early periods of the library and I managed to add a step at the end of the CI pipeline to do a NuGet publish, when a tag was created in GitHub. This completely removed any human error or any inadvertent omissions due to lack of time etc. This worked well for us other than the occasional NuGet publish failures due to expired API key. We had to jump into AppVeyor dashboard to see what was going on and fix things. Eventually, we migrated all the CI builds to use GitHub actions so that we can lookup things all in one-place without logging into different systems. This is a huge convenience and time saver for us. We settled on doing a manual GitHub action trigger (user invoked) especially for publishing NuGet packages rather than keep it automated so that we can inspect and keep an eye on the NuGet publish as it happens after we tag and add a release in GitHub.&lt;/p&gt;

&lt;p&gt;Following is a sample of the GitHub action YAML script for publishing package to NuGet with detailed comments adapted from the one we use with Marten :&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;NuGet Manual Publish&lt;/span&gt;

&lt;span class="c1"&gt;# workflow_dispatch is used to manually invoke the GH action&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Setting the required env flags&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release&lt;/span&gt;
  &lt;span class="na"&gt;DOTNET_CLI_TELEMETRY_OPTOUT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;DOTNET_SKIP_FIRST_TIME_EXPERIENCE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;dotnet_core_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;6.0.x&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;publish_job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# CI running on linux&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="c1"&gt;# This step clones the source code to the CI build machine&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;Checkout code&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="c1"&gt;# This step installs the .NET SDK&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;Install .NET &lt;/span&gt;&lt;span class="m"&gt;6&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/setup-dotnet@v1&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;dotnet-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.dotnet_core_version }}&lt;/span&gt;

      &lt;span class="c1"&gt;# Run dotnet pack to create the nupkg file for the project and store in artifacts folder&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;Run Pack&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;dotnet pack src/proj/proj.csproj -o ./artifacts --configuration ${{ env.config }}&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;

      &lt;span class="c1"&gt;# Find all the created nupkg files and publish it to NuGet, we use the wonderful swiss-army knife capability `find -exec` to find and then execute an action on it.&lt;/span&gt;
      &lt;span class="c1"&gt;# NUGET_DEPLOY_KEY is the NuGet API key stored in the repo GH action secrets&lt;/span&gt;
      &lt;span class="c1"&gt;# If you also publish symbol packages, find the snupkg files and publish it to NuGet&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;Publish to NuGet&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;find . -name '*.nupkg' -exec dotnet nuget push "{}" -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_DEPLOY_KEY }} --skip-duplicate \;&lt;/span&gt;
          &lt;span class="s"&gt;find . -name '*.snupkg' -exec dotnet nuget push "{}" -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_DEPLOY_KEY }} \;&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can take look at the current version of GH action used for publishing NuGet packages in Marten &lt;a href="https://github.com/JasperFx/marten/blob/master/.github/workflows/on-manual-do-nuget-publish.yml"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Stay tuned, I will be writing more posts detailing the build scripts, CI build systems (GitHub Actions, Azure Pipelines, AppVeyor), matrix builds which we use to run integration tests on various versions of Postgres based on my experiences building and maintaining these for Marten. Also will ramble on various other topics on Marten, Postgres, jsonb, Python, building desktop apps with Electron/Tauri, node.js, Tailwind CSS, alpine.js etc.&lt;/p&gt;

&lt;p&gt;Good day :-)&lt;/p&gt;

</description>
      <category>github</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
