<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>CI/CD on Haseeb Majid</title>
    <link>https://haseebmajid.dev/tags/ci/cd/</link>
    <description>Recent content in CI/CD on Haseeb Majid</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Sat, 15 Apr 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://haseebmajid.dev/tags/ci/cd/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How to Get Code Coverage From Playwright Tests in a Sveltekit App</title>
      <link>https://haseebmajid.dev/posts/2023-04-15--how-to-get-code-coverage-from-playwright-tests-in-a-sveltekit-app-/</link>
      <pubDate>Sat, 15 Apr 2023 00:00:00 +0000</pubDate>
      <author>Me</author>
      <guid>https://haseebmajid.dev/posts/2023-04-15--how-to-get-code-coverage-from-playwright-tests-in-a-sveltekit-app-/</guid>
      <description>&lt;p&gt;&lt;img
        loading=&#34;lazy&#34;
        src=&#34;https://haseebmajid.dev/posts/2023-04-15--how-to-get-code-coverage-from-playwright-tests-in-a-sveltekit-app-/images/code_coverage.jpg&#34;
        type=&#34;&#34;
        alt=&#34;Code Coverage Meme&#34;
        
      /&gt;&lt;/p&gt;
&lt;p&gt;In this post, I will show you how to get code coverage reports from your Playwright tests in your SvelteKit app.
So let&amp;rsquo;s imagine we are starting with the basic SvelteKit template. First, we need to install:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm i -D vite-plugin-istanbul
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We need the vite plugin to instrument our code using Istanbul.
Istanbul is a tool which allows us to instrument our code such that it can determine which lines were covered
by our tests.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><img
        loading="lazy"
        src="/posts/2023-04-15--how-to-get-code-coverage-from-playwright-tests-in-a-sveltekit-app-/images/code_coverage.jpg"
        type=""
        alt="Code Coverage Meme"
        
      /></p>
<p>In this post, I will show you how to get code coverage reports from your Playwright tests in your SvelteKit app.
So let&rsquo;s imagine we are starting with the basic SvelteKit template. First, we need to install:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm i -D vite-plugin-istanbul
</span></span></code></pre></div><p>We need the vite plugin to instrument our code using Istanbul.
Istanbul is a tool which allows us to instrument our code such that it can determine which lines were covered
by our tests.</p>
<h2 id="viteconfigts">vite.config.ts</h2>
<p>First, let&rsquo;s update our <code>vite.config.ts</code> (or <code>.js</code>) file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">sveltekit</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@sveltejs/kit/vite&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">defineConfig</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;vitest/config&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">istanbul</span> <span class="kr">from</span> <span class="s2">&#34;vite-plugin-istanbul&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">defineConfig</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">build</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">sourcemap</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="nx">sveltekit</span><span class="p">(),</span>
</span></span><span class="line hl"><span class="cl">    <span class="nx">istanbul</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">include</span><span class="o">:</span> <span class="s2">&#34;src/*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">exclude</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;node_modules&#34;</span><span class="p">,</span> <span class="s2">&#34;test/&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nx">extension</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;.ts&#34;</span><span class="p">,</span> <span class="s2">&#34;.svelte&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nx">requireEnv</span>: <span class="kt">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">forceBuildInstrument</span>: <span class="kt">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">}),</span>
</span></span><span class="line"><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">test</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">include</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;src/**/*.{test,spec}.{js,ts}&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><blockquote>
<p>forceBuildInstrument - Optional boolean to enforce the plugin to add instrumentation in build mode. Defaults to false.</p>
</blockquote>
<p>In theory, we should just be able to use <code>requireEnv: true</code> and then pass the <code>VITE_COVERAGE=true</code> environment variable.
To our playwright tests job, so instead I just set the <code>forceBuildInstrument</code>. Now, this always instrument our builds with Istanbul.
However, we can do something like <code>process.env.NODE_ENV === &quot;test&quot;</code>. Which will only run when <code>NODE_ENV</code> is <code>test</code>.
In this example, we will keep it simple and leave it as is.</p>
<h2 id="tests">tests</h2>
<p>Now let&rsquo;s go to our <code>tests</code> folder we need to add a new file called <code>baseFixtures.ts</code> [1], which looks like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">fs</span> <span class="kr">from</span> <span class="s1">&#39;fs&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">path</span> <span class="kr">from</span> <span class="s1">&#39;path&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">crypto</span> <span class="kr">from</span> <span class="s1">&#39;crypto&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">test</span> <span class="kr">as</span> <span class="nx">baseTest</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@playwright/test&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">istanbulCLIOutput</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">(),</span> <span class="s1">&#39;.nyc_output&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kd">function</span> <span class="nx">generateUUID</span><span class="p">()</span><span class="o">:</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">crypto</span><span class="p">.</span><span class="nx">randomBytes</span><span class="p">(</span><span class="mi">16</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="s1">&#39;hex&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">test</span> <span class="o">=</span> <span class="nx">baseTest</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">context</span>: <span class="kt">async</span> <span class="p">({</span> <span class="nx">context</span> <span class="p">},</span> <span class="nx">use</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="nx">context</span><span class="p">.</span><span class="nx">addInitScript</span><span class="p">(()</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;beforeunload&#39;</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nb">window</span> <span class="kr">as</span> <span class="kt">any</span><span class="p">).</span><span class="nx">collectIstanbulCoverage</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">((</span><span class="nb">window</span> <span class="kr">as</span> <span class="kt">any</span><span class="p">).</span><span class="nx">__coverage__</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">promises</span><span class="p">.</span><span class="nx">mkdir</span><span class="p">(</span><span class="nx">istanbulCLIOutput</span><span class="p">,</span> <span class="p">{</span> <span class="nx">recursive</span>: <span class="kt">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="nx">context</span><span class="p">.</span><span class="nx">exposeFunction</span><span class="p">(</span><span class="s1">&#39;collectIstanbulCoverage&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">coverageJSON</span>: <span class="kt">string</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">coverageJSON</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nx">fs</span><span class="p">.</span><span class="nx">writeFileSync</span><span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">istanbulCLIOutput</span><span class="p">,</span> <span class="sb">`playwright_coverage_</span><span class="si">${</span><span class="nx">generateUUID</span><span class="p">()</span><span class="si">}</span><span class="sb">.json`</span><span class="p">),</span> <span class="nx">coverageJSON</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="nx">use</span><span class="p">(</span><span class="nx">context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">page</span> <span class="k">of</span> <span class="nx">context</span><span class="p">.</span><span class="nx">pages</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="nb">window</span> <span class="kr">as</span> <span class="kt">any</span><span class="p">).</span><span class="nx">collectIstanbulCoverage</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">((</span><span class="nb">window</span> <span class="kr">as</span> <span class="kt">any</span><span class="p">).</span><span class="nx">__coverage__</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">expect</span> <span class="o">=</span> <span class="nx">test</span><span class="p">.</span><span class="nx">expect</span><span class="p">;</span>
</span></span></code></pre></div><p>We will use <code>test</code> and <code>expect</code> functions from this module instead of the playwright ones. As this module,
will collect the corresponding coverage files into <code>.nyc_output</code> in a JSON file.</p>
<p>Now open our tests file and update them to use the base fixture module from this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">expect</span><span class="p">,</span> <span class="nx">test</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@playwright/test&#39;</span><span class="p">;</span>
</span></span></code></pre></div><p>to this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">expect</span><span class="p">,</span> <span class="nx">test</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;./baseFixtures.js&#34;</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="run-the-tests">Run the Tests</h2>
<p>Now we can run the tests like <code>npm run test</code>, this should create a new file <code>.nyc_output</code>.
To see the actual coverage we need to use <code>nyc</code> we can do that:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter<span class="o">=</span>text --exclude-after-remap <span class="nb">false</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># output</span>
</span></span><span class="line"><span class="cl">--------------<span class="p">|</span>---------<span class="p">|</span>----------<span class="p">|</span>---------<span class="p">|</span>---------<span class="p">|</span>-------------------
</span></span><span class="line"><span class="cl">File          <span class="p">|</span> % Stmts <span class="p">|</span> % Branch <span class="p">|</span> % Funcs <span class="p">|</span> % Lines <span class="p">|</span> Uncovered Line <span class="c1">#s </span>
</span></span><span class="line"><span class="cl">--------------<span class="p">|</span>---------<span class="p">|</span>----------<span class="p">|</span>---------<span class="p">|</span>---------<span class="p">|</span>-------------------
</span></span><span class="line"><span class="cl">All files     <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span>        <span class="m">0</span> <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span>                   
</span></span><span class="line"><span class="cl"> +page.svelte <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span>        <span class="m">0</span> <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span> <span class="m">16</span>                
</span></span><span class="line"><span class="cl"> +page.ts     <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span>      <span class="m">100</span> <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span>     <span class="m">100</span> <span class="p">|</span>                   
</span></span><span class="line"><span class="cl">--------------<span class="p">|</span>---------<span class="p">|</span>----------<span class="p">|</span>---------<span class="p">|</span>---------<span class="p">|</span>-------------------
</span></span></code></pre></div><h3 id="c8">C8</h3>
<p>If we want to generate a C8 (Coberatura) report we can do:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter<span class="o">=</span>cobertura --exclude-after-remap <span class="nb">false</span>
</span></span></code></pre></div><p>This will save the code coverage data in the C8 format in the <code>coverage</code> folder.</p>
<h3 id="junit">JUnit</h3>
<p>We can also generate a JUnit file, first we need to add the following to our <code>playwright.config.ts</code> file:
<code>reporter: [[&quot;junit&quot;, { outputFile: &quot;results.xml&quot; }]]</code>. Then to generate the report we need to run
<code>PLAYWRIGHT_JUNIT_OUTPUT_NAME=results.xml npm run test</code>, we pass an environment variable to tell playwright where to save
the JUnit file.</p>
<h2 id="optional-run-in-gitlab-ci">(Optional) Run in GitLab CI</h2>
<p>If we put all of this together we can run the tests in GitLab CI and get the code coverage, JUnit and Coberatura reports like so:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">node</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">stages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">tests:e2e</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l">test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">script</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">npx playwright install</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">npm run test -- --reporter=junit</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=cobertura --exclude-after-remap false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=text --exclude-after-remap false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">coverage</span><span class="p">:</span><span class="w"> </span><span class="l">/All files[^|]*\|[^|]*\s+([\d\.]+)/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">artifacts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">reports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">junit</span><span class="p">:</span><span class="w"> </span><span class="l">results.xml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">coverage_report</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">coverage_format</span><span class="p">:</span><span class="w"> </span><span class="l">cobertura</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">coverage/cobertura-coverage.xml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">when</span><span class="p">:</span><span class="w"> </span><span class="l">always</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">paths</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">test-results/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">expire_in</span><span class="p">:</span><span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="l">week</span><span class="w">
</span></span></span></code></pre></div><p>GitLab will be able to show some useful information using this code coverage data, such as lines covered in an open MR.
It can show if the code coverage has gone up or down within the MR as well.</p>
<p>That&rsquo;s it! Hopefully, this post has helped you set up retrieving code coverage from your playwright tests!</p>
<h2 id="appendix">Appendix</h2>
<ul>
<li><a href="https://gitlab.com/hmajid2301/blog/-/tree/main/content/posts/2023-04-15--how-to-get-code-coverage-from-playwright-tests-in-a-sveltekit-app-/example">Example source code</a></li>
<li><a href="https://github.com/microsoft/playwright/discussions/20841">Playwright Discussion</a></li>
<li><a href="https://github.com/stevez/playwright-test-coverage/tree/integrate-vite-plugin-istanbul">Inspired By this repo</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>TIL: How to Deploy &#39;Multiple&#39; Sites on One GitLab Page Site</title>
      <link>https://haseebmajid.dev/posts/2023-04-06-til-how-to-deploy-multiple-sites-on-one-gitlab-page-site/</link>
      <pubDate>Thu, 06 Apr 2023 00:00:00 +0000</pubDate>
      <author>Me</author>
      <guid>https://haseebmajid.dev/posts/2023-04-06-til-how-to-deploy-multiple-sites-on-one-gitlab-page-site/</guid>
      <description>&lt;p&gt;I have a repo which I use to store all of my conference and similar talks. This repo includes any code examples
and most importantly the slides.&lt;/p&gt;
&lt;p&gt;At the moment all the slides are RevealJS &amp;ldquo;sites&amp;rdquo;, which means it&amp;rsquo;s a presentation built in HTML. Now I would like
to have all my talks deployed to single GitLab pages site. For example something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://hmajid2301.io/talks/an-intro-to-pocketbase/&#34;&gt;https://hmajid2301.io/talks/an-intro-to-pocketbase/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hmajid2301.io/talks/docker-as-a-dev-tool/&#34;&gt;https://hmajid2301.io/talks/docker-as-a-dev-tool/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So how can we do this ? Simple! In our job to deploy the site we just need to add &lt;code&gt;public/docker-as-a-dev-tool&lt;/code&gt; and &lt;code&gt;public/an-intro-to-pocketbase&lt;/code&gt;
respectively. Which ever path we provide is that path we will be able to access those slides on.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have a repo which I use to store all of my conference and similar talks. This repo includes any code examples
and most importantly the slides.</p>
<p>At the moment all the slides are RevealJS &ldquo;sites&rdquo;, which means it&rsquo;s a presentation built in HTML. Now I would like
to have all my talks deployed to single GitLab pages site. For example something like:</p>
<ul>
<li><a href="https://hmajid2301.io/talks/an-intro-to-pocketbase/">https://hmajid2301.io/talks/an-intro-to-pocketbase/</a></li>
<li><a href="https://hmajid2301.io/talks/docker-as-a-dev-tool/">https://hmajid2301.io/talks/docker-as-a-dev-tool/</a></li>
</ul>
<p>So how can we do this ? Simple! In our job to deploy the site we just need to add <code>public/docker-as-a-dev-tool</code> and <code>public/an-intro-to-pocketbase</code>
respectively. Which ever path we provide is that path we will be able to access those slides on.</p>
<p>Here is an example <code>.gitlab-ci.yml</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="c"># .gitlab-ci.yml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">stages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">pages</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">pages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l">pages</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">only</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">scripts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">mkdir -p public/docker-as-a-dev-tool</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">mv docker-as-a-dev-tool public/docker-as-a-dev-tool</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">artifacts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">paths</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">public</span><span class="w">
</span></span></span></code></pre></div><p>Voila that&rsquo;s it! Now we have multiple slides deployed to the same GitLab pages site.
So I can keep all of my talks nice and neat in a single repo.</p>
<h2 id="appendix">Appendix</h2>
<ul>
<li><a href="https://gitlab.com/hmajid2301/talks">My Talks Project</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>TIL: How to Run Parallel Jobs on Gitlab CI (Different Stages)</title>
      <link>https://haseebmajid.dev/posts/2023-03-03-til-how-to-run-parallel-jobs-on-gitlab-ci/</link>
      <pubDate>Fri, 03 Mar 2023 00:00:00 +0000</pubDate>
      <author>Me</author>
      <guid>https://haseebmajid.dev/posts/2023-03-03-til-how-to-run-parallel-jobs-on-gitlab-ci/</guid>
      <description>&lt;p&gt;&lt;strong&gt;TIL: How to Run Parallel Jobs on Gitlab CI (Different Stages)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you are familiar with Gitlab CI you probably know that jobs in the same stages will run in parallel.
However you can also run jobs in different stages at the same time. Let&amp;rsquo;s see our &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;stages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;deploy&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;stage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;task format&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;lint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;stage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;task lint&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;deploy:preview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;stage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;deploy&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;only&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;merge_request&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;docker&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;task deploy&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So for my use case when a user creates a merge request, I want to run some tests against the code,
such as linting and formatting. But also deploy my app to a preview environment. Whilst these jobs
belong to different stages.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><strong>TIL: How to Run Parallel Jobs on Gitlab CI (Different Stages)</strong></p>
<p>If you are familiar with Gitlab CI you probably know that jobs in the same stages will run in parallel.
However you can also run jobs in different stages at the same time. Let&rsquo;s see our <code>.gitlab-ci.yml</code> looks like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">stages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">deploy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">format</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l">test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">script</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">task format</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">lint</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l">test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">script</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">task lint</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">deploy:preview</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l">deploy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">only</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">merge_request</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">docker</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">script</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">task deploy</span><span class="w">
</span></span></span></code></pre></div><p>So for my use case when a user creates a merge request, I want to run some tests against the code,
such as linting and formatting. But also deploy my app to a preview environment. Whilst these jobs
belong to different stages.</p>
<p>The deploy job shouldn&rsquo;t really depend on the jobs in the <code>test</code> stage as we still want to deploy our
app regardless so we can test in the preview environment.</p>
<p>We can do that using <code>needs</code> <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> keywords, so our <code>deploy:preview</code> job will now look like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">deploy:preview</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l">deploy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">only</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">merge_request</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w">  </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">docker</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">script</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">task deploy</span><span class="w">
</span></span></span></code></pre></div><p>Now our job will run at the same time as the <code>test</code> stage jobs.
The <code>needs</code> keyword is used to run our job out of order.</p>
<blockquote>
<p>An empty array ([]), to set the job to start as soon as the pipeline is created. - Gitlab CI Docs</p>
</blockquote>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://docs.gitlab.com/ee/ci/yaml/#needs">https://docs.gitlab.com/ee/ci/yaml/#needs</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    
    <item>
      <title>How Can We Update GitLab CI on the Status of the Netlify Deploy Part I</title>
      <link>https://haseebmajid.dev/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/</link>
      <pubDate>Tue, 17 Jan 2023 00:00:00 +0000</pubDate>
      <author>Me</author>
      <guid>https://haseebmajid.dev/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/</guid>
      <description>&lt;p&gt;In this post, I will show you how you can update your GitLab CI pipeline with the status of your Netlify deploys.
As it is quite nice to have everything in one place if our CI pipeline passed or failed.&lt;/p&gt;
&lt;p&gt;I have spoken about this in a
&lt;a href=&#34;https://haseebmajid.dev/posts/2022-12-03-my-workflow-to-create-a-new-post-using-hugo,-netlifycms,-netlify-and-gitlab-together&#34;&gt;previous article&lt;/a&gt;,
how you might go about setting up merge request preview environments with Netlify.&lt;/p&gt;
&lt;p&gt;&lt;img
        loading=&#34;lazy&#34;
        src=&#34;https://haseebmajid.dev/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/images/netlify_mr_comment.png&#34;
        type=&#34;&#34;
        alt=&#34;Netlify MR comment&#34;
        
      /&gt;&lt;/p&gt;
&lt;p&gt;This can be set up to also leave comments as shown above, and notify us if our website deployed successfully. Which will look like so:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In this post, I will show you how you can update your GitLab CI pipeline with the status of your Netlify deploys.
As it is quite nice to have everything in one place if our CI pipeline passed or failed.</p>
<p>I have spoken about this in a
<a href="/posts/2022-12-03-my-workflow-to-create-a-new-post-using-hugo,-netlifycms,-netlify-and-gitlab-together">previous article</a>,
how you might go about setting up merge request preview environments with Netlify.</p>
<p><img
        loading="lazy"
        src="/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/images/netlify_mr_comment.png"
        type=""
        alt="Netlify MR comment"
        
      /></p>
<p>This can be set up to also leave comments as shown above, and notify us if our website deployed successfully. Which will look like so:</p>
<p><img
        loading="lazy"
        src="/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/images/netlify_notifications.png"
        type=""
        alt="Netlify Notifications"
        
      /></p>
<p>However, there is currently no way to update our CI pipeline/GitLab on the main branch when our app is deployed on Netlify <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.
Netlify does allow us to set up webhooks depending on the different statuses of our builds. So what we need is to set up webhooks
on Netlify, then have that call something say a serverless function which will then call the GitLab to commit status API. When we update
the commit status it looks something like this:</p>
<p><a href="images/main_branch_ci.png">GitLab CI</a></p>
<h2 id="netlify-gitlab-commit-status">Netlify GitLab Commit Status</h2>
<p>I have created this simple script in Golang <a href="https://gitlab.com/hmajid2301/netlify-gitlab-commit-status">here</a>.
Which does this for us.
In my case, I have it deployed as a google cloud function and have set up CI in that project so it automatically deploys
when we push to the main branch.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">deploy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">google/cloud-sdk:latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">only</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">script</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">gcloud auth activate-service-account --key-file $GCLOUD_SERVICE_KEY</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">gcloud config set project haseeb-majid</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">gcloud functions deploy netlify-build-commit-status --region us-central1 --gen2 --runtime go119 --trigger-http --allow-unauthenticated --entry-point=webhook</span><span class="w">
</span></span></span></code></pre></div><details
  class="notice warning"
  open="true"
>
    <summary class="notice-title">Limitation</summary>
  
  At the moment the script will only work with repositories you are the owner of in GitLab.
Hence you cannot just say point to my google cloud function and get it to work with your repository.
</details>

<h2 id="google-cloud">Google Cloud</h2>
<h3 id="set-up">Set Up</h3>
<p>Assuming you want to deploy this as a cloud function as well, fork my repo.
Then go to <a href="https://console.cloud.google.com/welcome">Google cloud platform</a> (GCP).</p>
<ol>
<li>Create a new project if you need to.</li>
<li>Go to service accounts and create a new service account i.e. I called my <code>functions@[project].iam.gserviceaccount.com</code></li>
<li>Assign the service account at least these two permissions <code>Cloud Functions Developer</code>, <code>Service Account User</code></li>
<li>Go to <code>Secret Manager</code>, then create two secrets
<ol>
<li><code>JWS_SECRET</code>: A secret shared with Netlify webhooks so we can confirm the webhook came from Netlify</li>
<li><code>GITLAB_TOKEN</code>: Used to interact with GitLab API
<ol>
<li>Create on GitLab by clicking on your Avatar (top right)</li>
<li>Select <code>Preferences</code></li>
<li>Select <code>Access Token</code> (left sidebar)</li>
<li>Create a new token with <code>api, read_repository</code> (as shown in the image below)</li>
</ol>
</li>
</ol>
</li>
</ol>
<p>You set permissions on the service account in IAM like so:</p>
<p><a href="images/iam_gcp.png">GCP IAM Permissions</a></p>
<p>You can create a GitLab token like so:</p>
<p><a href="images/gitlab_access_token.png">GitLab Access Token</a></p>
<h3 id="cloud-function">Cloud Function</h3>
<p>I think the easiest way to deploy this function the first time is to do it manually so we can also add our secrets.
Which CI currently does not do for us. Here are the settings I have used:</p>
<p>First, let&rsquo;s create a new function and use gen2 which comes with a bunch of improvements.</p>
<p><img
        loading="lazy"
        src="/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/images/function_gen2.png"
        type=""
        alt="Function Gen2"
        
      /></p>
<p>Next, let&rsquo;s set the max instance count to 1, we don&rsquo;t need 100 instances running this code 😂.</p>
<p><img
        loading="lazy"
        src="/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/images/function_resources.png"
        type=""
        alt="Function Resources"
        
      /></p>
<p>Next, add the secrets we created above as ENV variables, in this example, I have added just <code>GITLAB_TOKEN</code> but we also need <code>JWS_SECRET</code>.
Also with the same name as the ENV variable.</p>
<p><img
        loading="lazy"
        src="/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/images/function_secrets.png"
        type=""
        alt="Function Secrets"
        
      /></p>
<p>Finally copy the code from the repo over to this section including <code>go.mod</code> file.</p>
<p></p>
<p>After this, we should be able to deploy using CI from now on. Take note of the URL of the function.</p>
<h3 id="gitlab">GitLab</h3>
<p>We do need to do one final thing to setup GitLab CI to publish our cloud function we will need to get the JSON key file-related
to our service account and put that as a secret CI/CD variable in GitLab. To do this:</p>
<ul>
<li>Go to your service account</li>
<li>Go to <code>keys</code> and select <code>Add Key</code> &gt; <code>Create new key</code></li>
<li>Select <code>JSON</code></li>
<li>Copy the contents of the files and go to GitLab CI/CD settings for your project
<ul>
<li>Call this variable <code>GCLOUD_SERVICE_KEY</code></li>
<li>When creating a new variable specify the type as <code>file</code> (see image below)</li>
</ul>
</li>
</ul>
<p>GCP service account key export:</p>
<p><img
        loading="lazy"
        src="/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/images/gcp_keys.png"
        type=""
        alt="GCP Service Keys"
        
      /></p>
<p>CI/CD variables for repo in GitLab:</p>
<p><a href="images/gitlab_ci_vars.png">GitLab CI</a></p>
<p>Create a new variable:</p>
<p><a href="images/gitlab_ci_new_var.png">GitLab CI</a></p>
<h2 id="netlify">Netlify</h2>
<p>Now that we deployed our function let&rsquo;s go to Netlify, go to your site settings on Netlify.</p>
<ul>
<li>Then go to <code>Build &amp; Deploy</code> (left-hand side)</li>
<li>Go to <code>Deploy notifications</code></li>
<li><code>Add notifications</code> &gt; <code>Outgoing webhook</code>
<ul>
<li>Select <code>Deploy Started</code></li>
<li>Paste the URL of the cloud function and the JWS secret</li>
</ul>
</li>
</ul>
<p>Now do this also for <code>Deploy failed</code> and `Deploy succeeded</p>
<p><img
        loading="lazy"
        src="/posts/2023-01-17-how-can-we-update-gitlab-ci-on-the-status-of-the-netlify-deploy-part-i/images/netlify_deploy.png"
        type=""
        alt="Outgoing webhook"
        
      /></p>
<p>Now Netlify will call out the cloud function and depending on the Netlify status it will set the relevant commit status
on our GitLab repo/CI.</p>
<p>In part II we will go over how the code works! But for now, you should be able to get &ldquo;deploy&rdquo; statuses in GitLab CI.
Which is nice. It will be called <code>Deploy to Netlify</code>, this is set within the code itself.</p>
<h2 id="appendix">Appendix</h2>
<ul>
<li><a href="https://gitlab.com/hmajid2301/netlify-gitlab-commit-status">Netlify GitLab Commit Status Repo</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://answers.netlify.com/t/gitlab-commit-status/79572">https://answers.netlify.com/t/gitlab-commit-status/79572</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
