<?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>Github on Techobyte Blog</title>
    <link>/tags/github/</link>
    <description>Recent content in Github on Techobyte Blog</description>
    <generator>Hugo</generator>
    <language>en-US</language>
    <lastBuildDate>Sun, 16 Aug 2026 00:00:00 -0400</lastBuildDate>
    <atom:link href="/tags/github/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Renovate Automation</title>
      <link>/posts/renovate-automation/</link>
      <pubDate>Sun, 16 Aug 2026 00:00:00 -0400</pubDate>
      <guid>/posts/renovate-automation/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;Mend Renovate logo&#34; loading=&#34;lazy&#34; src=&#34;/posts/renovate-automation/mend-renovate-logo.png#center&#34;&gt;&lt;/p&gt;
&lt;style type=&#34;text/css&#34;&gt;
     
    .notice {
        --title-color: #fff;
        --title-background-color: #6be;
        --content-color: #444;
        --content-background-color: #e7f2fa;
    }

    .notice.info {
        --title-background-color: #fb7;
        --content-background-color: #fec;
    }

    .notice.tip {
        --title-background-color: #5a5;
        --content-background-color: #efe;
    }

    .notice.warning {
        --title-background-color: #c33;
        --content-background-color: #fee;
    }

     
    @media (prefers-color-scheme:dark) {
        .notice {
            --title-color: #fff;
            --title-background-color: #069;
            --content-color: #ddd;
            --content-background-color: #023;
        }

        .notice.info {
            --title-background-color: #a50;
            --content-background-color: #420;
        }

        .notice.tip {
            --title-background-color: #363;
            --content-background-color: #121;
        }

        .notice.warning {
            --title-background-color: #800;
            --content-background-color: #400;
        }
    }

    body.dark .notice {
        --title-color: #fff;
        --title-background-color: #069;
        --content-color: #ddd;
        --content-background-color: #023;
    }

    body.dark .notice.info {
        --title-background-color: #a50;
        --content-background-color: #420;
    }

    body.dark .notice.tip {
        --title-background-color: #363;
        --content-background-color: #121;
    }

    body.dark .notice.warning {
        --title-background-color: #800;
        --content-background-color: #400;
    }

     
    .notice {
        padding: 18px;
        line-height: 24px;
        margin-bottom: 24px;
        border-radius: 4px;
        color: var(--content-color);
        background: var(--content-background-color);
    }

    .notice p:last-child {
        margin-bottom: 0
    }

     
    .notice-title {
        margin: -18px -18px 12px;
        padding: 4px 18px;
        border-radius: 4px 4px 0 0;
        font-weight: 700;
        color: var(--title-color);
        background: var(--title-background-color);
    }

     
    .icon-notice {
        display: inline-flex;
        align-self: center;
        margin-right: 8px;
    }

    .icon-notice img,
    .icon-notice svg {
        height: 1em;
        width: 1em;
        fill: currentColor;
    }

    .icon-notice img,
    .icon-notice.baseline svg {
        top: .125em;
        position: relative;
    }
&lt;/style&gt;&lt;div class=&#34;notice tip&#34;  id=&#34;Renovate Cloud&#34; &gt;
    &lt;p class=&#34;notice-title&#34;&gt;
        &lt;span class=&#34;icon-notice baseline&#34;&gt;
            &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;300.5 134 300 300&#34;&gt;
  &lt;path d=&#34;M551.281 252.36c0-3.32-1.172-6.641-3.515-8.985l-17.774-17.578c-2.344-2.344-5.469-3.711-8.789-3.711-3.32 0-6.445 1.367-8.789 3.71l-79.687 79.493-44.141-44.14c-2.344-2.344-5.469-3.712-8.79-3.712-3.32 0-6.444 1.368-8.788 3.711l-17.774 17.579c-2.343 2.343-3.515 5.664-3.515 8.984 0 3.32 1.172 6.445 3.515 8.789l70.704 70.703c2.343 2.344 5.664 3.711 8.789 3.711 3.32 0 6.64-1.367 8.984-3.71l106.055-106.056c2.343-2.343 3.515-5.468 3.515-8.789ZM600.5 284c0 82.813-67.188 150-150 150-82.813 0-150-67.188-150-150 0-82.813 67.188-150 150-150 82.813 0 150 67.188 150 150Z&#34;/&gt;
&lt;/svg&gt;

        &lt;/span&gt; Renovate Cloud &lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><img alt="Mend Renovate logo" loading="lazy" src="/posts/renovate-automation/mend-renovate-logo.png#center"></p>
<style type="text/css">
     
    .notice {
        --title-color: #fff;
        --title-background-color: #6be;
        --content-color: #444;
        --content-background-color: #e7f2fa;
    }

    .notice.info {
        --title-background-color: #fb7;
        --content-background-color: #fec;
    }

    .notice.tip {
        --title-background-color: #5a5;
        --content-background-color: #efe;
    }

    .notice.warning {
        --title-background-color: #c33;
        --content-background-color: #fee;
    }

     
    @media (prefers-color-scheme:dark) {
        .notice {
            --title-color: #fff;
            --title-background-color: #069;
            --content-color: #ddd;
            --content-background-color: #023;
        }

        .notice.info {
            --title-background-color: #a50;
            --content-background-color: #420;
        }

        .notice.tip {
            --title-background-color: #363;
            --content-background-color: #121;
        }

        .notice.warning {
            --title-background-color: #800;
            --content-background-color: #400;
        }
    }

    body.dark .notice {
        --title-color: #fff;
        --title-background-color: #069;
        --content-color: #ddd;
        --content-background-color: #023;
    }

    body.dark .notice.info {
        --title-background-color: #a50;
        --content-background-color: #420;
    }

    body.dark .notice.tip {
        --title-background-color: #363;
        --content-background-color: #121;
    }

    body.dark .notice.warning {
        --title-background-color: #800;
        --content-background-color: #400;
    }

     
    .notice {
        padding: 18px;
        line-height: 24px;
        margin-bottom: 24px;
        border-radius: 4px;
        color: var(--content-color);
        background: var(--content-background-color);
    }

    .notice p:last-child {
        margin-bottom: 0
    }

     
    .notice-title {
        margin: -18px -18px 12px;
        padding: 4px 18px;
        border-radius: 4px 4px 0 0;
        font-weight: 700;
        color: var(--title-color);
        background: var(--title-background-color);
    }

     
    .icon-notice {
        display: inline-flex;
        align-self: center;
        margin-right: 8px;
    }

    .icon-notice img,
    .icon-notice svg {
        height: 1em;
        width: 1em;
        fill: currentColor;
    }

    .icon-notice img,
    .icon-notice.baseline svg {
        top: .125em;
        position: relative;
    }
</style><div class="notice tip"  id="Renovate Cloud" >
    <p class="notice-title">
        <span class="icon-notice baseline">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="300.5 134 300 300">
  <path d="M551.281 252.36c0-3.32-1.172-6.641-3.515-8.985l-17.774-17.578c-2.344-2.344-5.469-3.711-8.789-3.711-3.32 0-6.445 1.367-8.789 3.71l-79.687 79.493-44.141-44.14c-2.344-2.344-5.469-3.712-8.79-3.712-3.32 0-6.444 1.368-8.788 3.711l-17.774 17.579c-2.343 2.343-3.515 5.664-3.515 8.984 0 3.32 1.172 6.445 3.515 8.789l70.704 70.703c2.343 2.344 5.664 3.711 8.789 3.711 3.32 0 6.64-1.367 8.984-3.71l106.055-106.056c2.343-2.343 3.515-5.468 3.515-8.789ZM600.5 284c0 82.813-67.188 150-150 150-82.813 0-150-67.188-150-150 0-82.813 67.188-150 150-150 82.813 0 150 67.188 150 150Z"/>
</svg>

        </span> Renovate Cloud </p><p>Since writing this article, I have moved to using Renovate&rsquo;s cloud version, which has a <a href="https://docs.mend.io/renovate/latest/mend-renovate-cloud-resource-tiers#Renovate-Cloud---Community-vs-Enterprise">generous free tier</a>. I am still using the same <code>renovate.json</code> for each repository, but I let the Renovate platform take over scheduling runs and opening pull requests.</p>
<p>The Renovate community cloud runs the bot when it needs to run, instead of waiting for the next pipeline execution. When a change is merged into the main branch, Renovate will automatically re-run to update the dashboard issue, keeping things more up to date than the pipeline version.</p>
<p>When the free tier inevitably changes for the worse, whether due to Mend deciding it&rsquo;s time to squeeze, or selling to Private Equity and enshittifying itself, I will look into <a href="https://docs.mend.io/renovate/latest/mend-renovate-enterprise-self-hosted">self-hosting my own Renovate server</a> (or more realistically, will find a different tool).</p>
<p>Most of the content in this article is still relevant, besides the Github workflow; when using Renovate cloud, this should be disabled so the two don&rsquo;t interfere with each other.</p></div>

<hr>
<p>Every now and then, I test drive a new tool and find it so immediately useful, it becomes a core part of my toolkit practically overnight. I have experienced this with <a href="https://docs.astral.sh/uv">Astral&rsquo;s <code>uv</code> for manging Python projects</a>, <a href="https://atuin.sh/">Atuin for shell history</a>, <a href="https://www.chezmoi.io/"><code>chezmoi</code> for dotfiles management</a>, and so on. When I set out a few weeks ago to test drive <a href="https://github.com/renovatebot/renovate">Renovate</a>, I only intended to dip my toes in a repository or two to see if I found it useful enough to add it to the repositories I spend the most time maintaining.</p>
<p>Instead, I found the tool immediately useful, simple to configure, and easy to bend to my needs. Overnight, I found myself creating a centralized, reusable version of the pipeline that easily adds Renovate support to new and existing repositories. I even rewrote the bespoke Bash scripting I was using to automate bumping and rebuilding Docker images in <a href="https://github.com/redjax/Dockerfiles">my Dockerfiles repository</a> because Renovate made managing all of the different versions much simpler.</p>
<h2 id="what-is-renovate">What is Renovate?</h2>
<p>Renovate is a tool that automates dependency bumping. It supports an array of <a href="https://docs.renovatebot.com/modules/platform/">Git platforms</a> and <a href="https://docs.renovatebot.com/modules/manager/">package managers</a>, and can read comments in your source code to check a version against <a href="https://docs.renovatebot.com/modules/datasource/">different data sources</a>, like a <a href="https://docs.renovatebot.com/modules/datasource/github-releases/">Github release</a> or <a href="https://docs.renovatebot.com/modules/datasource/docker/">a Docker registry</a>. If you have used <a href="https://docs.github.com/en/code-security/tutorials/secure-your-dependencies/dependabot-quickstart">Github&rsquo;s Dependabot</a>, they serve similar purposes.</p>
<p>The <a href="https://docs.renovatebot.com/">Renovate docs</a> do a pretty good job of explaining how and why you might use Renovate. It&rsquo;s a flexible tool with <a href="https://docs.renovatebot.com/getting-started/use-cases/">many use cases</a> and sensible, useful defaults. You can also create <a href="https://docs.renovatebot.com/presets-customManagers/">custom managers</a> using regex to bump versions the tool doesn&rsquo;t find automatically. It can open an issue in your issue tracker to serve as a &ldquo;dashboard,&rdquo; with the tool updating it after every run, and you can configure automations like &ldquo;merge all patch and minor versions automatically, but don&rsquo;t merge major version bumps automatically.&rdquo;</p>
<h2 id="adopting-renovate">Adopting Renovate</h2>
<p>I have a Github repository named <a href="https://github.com/redjax/PipelineTemplates">PipelineTemplates</a>, where I centralize my CI/CD workflows into reusable components and workflows. I keep my pipelines for Github, Gitlab, Forgejo, Concourse, etc. in this central repository to reduce my bad habit of copying, pasting, and slightly tweaking pipelines to do the same task. I wrote about the impetus for this repository and the adoption process in <a href="/posts/centralized-pipelines">my &ldquo;Centralized CI/CD Pipelines&rdquo; post</a>. My interest in Renovate originally started as an exercise to create a centralized, reusable workflow to run Renovate across a couple of my Hugo site repositories like <a href="https://github.com/redjax/redkb">RedKB</a> and <a href="https://github.com/redjax/blog">this blog</a>.</p>
<p>I created the <a href="https://github.com/redjax/PipelineTemplates/blob/main/.github/workflows/renovate.yml">Renovate pipeline file</a> in my central repository, and gave it inputs a consuming repository can use to configure Renovate runs. I was surprised by how quickly the POC pipeline came together; Renovate is relatively easy to setup, especially considering how many different configurations it supports.</p>
<p>I also added a <a href="https://github.com/redjax/PipelineTemplates/blob/main/config/renovate/default.json">default Renovate configuration</a> that consuming repositories can use, if they do not provide their own. This configuration is my personal preferences for a &ldquo;standard&rdquo; Renovate run; it extends the actual Renovate <a href="https://docs.renovatebot.com/presets-default/">default configurations</a>, and supports my most-used languages and managers.</p>
<p>My default configuration enables the <a href="https://docs.renovatebot.com/key-concepts/dashboard/">dashboard issue</a>, allows automated PR merges for minor and patch bumps, but requires approval for major bumps, and supports some custom regular expressions to monitor my Gitlab pipelines and Dockerfile images. This centralized configuration file makes it really easy to enroll one of my repositories; I just have to create a <code>renovate.json</code> at the root of the repository with this:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;$schema&#34;</span><span class="p">:</span> <span class="s2">&#34;https://docs.renovatebot.com/renovate-schema.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;extends&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;github&gt;redjax/PipelineTemplates//config/renovate/default#main&#34;</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></td></tr></table>
</div>
</div><p>The centralized pipeline also allows repositories to provide their own <code>renovate.json</code> configuration. This feature gives me greater control over Renovate&rsquo;s behavior; for most repositories, the defaults are perfectly fine and you can &ldquo;set it and forget it.&rdquo; Some of my repositories have package manager files in subdirectories, or use the <code>customManagers</code> config block to provide Renovate with regular expressions of files to monitor. For example, <a href="https://github.com/redjax/Dockerfiles/blob/main/renovate.json">my Dockerfile repository&rsquo;s <code>renovate.json</code></a> is much different from most of my other repositories. The Dockerfiles repo consolidates my Docker images into subdirectories in the <code>dockerfiles/</code> directory, and uses a <a href="https://github.com/redjax/Dockerfiles/blob/main/.github/workflows/build-publish.yml">Github action to rebuild the container nightly and whenever an image has changed (i.e. a version bumps)</a>. Each template also has an <code>image.yml</code> &ldquo;manifest&rdquo; file that tracks versions for the build script to inject.</p>
<p>I had to provide instructions to Renovate for how to handle this repository, but the centralized pipeline automatically uses whatever Renovate config file I pass from a consuming repository in <code>config-file:</code>.</p>
<h2 id="the-calling-pipeline">The Calling Pipeline</h2>
<p>In each repository where I want to use my central Renovate pipeline, all I need to do is create a pipeline &ldquo;stub&rdquo; that calls the centralized template. I use the pipeline&rsquo;s <code>inputs</code> to change configurations between repositories. The pipeline stub can be very simple; if the repository doesn&rsquo;t provide a <code>renovate.json</code> configuration, all it really needs is triggers, a couple of repository-specific inputs, and access tokens added to the repository.</p>
<p>A simple pipeline that runs once nightly at midnight could be:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Run Renovate</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">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schedule</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">cron</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;0 0 * * *&#34;</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">permissions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">contents</span><span class="p">:</span><span class="w"> </span><span class="l">write</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">pull-requests</span><span class="p">:</span><span class="w"> </span><span class="l">write</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">issues</span><span class="p">:</span><span class="w"> </span><span class="l">write</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">actions</span><span class="p">:</span><span class="w"> </span><span class="l">write</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">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">renovate</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">redjax/pipelinetemplates/.github/workflows/renovate.yml@main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">mode</span><span class="p">:</span><span class="w"> </span><span class="l">run</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">log-level</span><span class="p">:</span><span class="w"> </span><span class="l">info</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">repository</span><span class="p">:</span><span class="w"> </span><span class="l">${{ github.repository }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">autodiscover</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">renovate-author-email</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;0000000+gitusername@users.noreply.github.com&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">secrets</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">renovate-token</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.RENOVATE_TOKEN }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">gh-api-token</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.GH_API_TOKEN }}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>Renovate will automatically detect languages and package managers it supports, create a dashboard issue, and start opening PRs to bump dependencies.</p>
<p>For an example of a more complex pipeline, the Dockerfiles repository is configured to run the pipeline every four times daily (every six hours). It will also trigger again after merging a <code>renovate/*</code> branch into the <code>main</code> branch. This extra trigger handles closing other PRs if they depended on another auto or manually merged PR, updating the Dashboard, and rescanning the repository after version bumps. It also has a manual trigger if I ever want to run it, maybe while testing changes on another branch, or to do a &ldquo;dry run&rdquo; to see what will happen the next time the pipeline runs. The Dockerfiles repository provides its own <code>renovate.json</code> and disabled &ldquo;autodiscover&rdquo; to force Renovate to use it.</p>
<p>This version uses <code>if</code> conditionals to change the way the pipeline runs depending on the trigger, and the PR events work to trigger the pipeline that rebuilds and publishes updated Dockerfiles.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Run Renovate</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">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schedule</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">cron</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;0 3 * * *&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">cron</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;0 9 * * *&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">cron</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;0 15 * * *&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">cron</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;0 21 * * *&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;renovate/*&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">workflow_dispatch</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">inputs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">mode</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Renovate mode&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">required</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">default</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;lookup&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">choice</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">options</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="l">extract</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="l">lookup</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="l">run</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">log-level</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Renovate log level&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">required</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">default</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;info&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">choice</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">options</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="l">info</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="l">debug</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="l">trace</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">permissions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">contents</span><span class="p">:</span><span class="w"> </span><span class="l">write</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">pull-requests</span><span class="p">:</span><span class="w"> </span><span class="l">write</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">issues</span><span class="p">:</span><span class="w"> </span><span class="l">write</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">actions</span><span class="p">:</span><span class="w"> </span><span class="l">write</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">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">renovate</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">redjax/pipelinetemplates/.github/workflows/renovate.yml@main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">mode</span><span class="p">:</span><span class="w"> </span><span class="p">&gt;-</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">        ${{ github.event_name == &#39;schedule&#39;
</span></span></span><span class="line"><span class="cl"><span class="sd">            &amp;&amp; &#39;run&#39;
</span></span></span><span class="line"><span class="cl"><span class="sd">            || inputs.mode || &#39;run&#39; }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># mode: run</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">log-level</span><span class="p">:</span><span class="w"> </span><span class="l">${{ inputs.log-level || &#39;info&#39; }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">repository</span><span class="p">:</span><span class="w"> </span><span class="l">${{ github.repository }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">config-file</span><span class="p">:</span><span class="w"> </span><span class="l">renovate.json</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c">## Set to &#39;ignored&#39; while testing renovate.json changes on a different base branch,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c">#  otherwise use &#39;optional&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">require-config</span><span class="p">:</span><span class="w"> </span><span class="l">optional</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">autodiscover</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">runner-image</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">renovate-author-email</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;0000000+gitusername@users.noreply.github.com&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">base-branches</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;main&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">use-base-branch-config</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">secrets</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">renovate-token</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.RENOVATE_TOKEN }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">gh-api-token</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.GH_API_TOKEN }}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h2 id="repository-secrets">Repository Secrets</h2>
<p>My Renovate pipeline requires consuming repositories to have two secrets set in their environment, <code>RENOVATE_TOKEN</code> and <code>GH_API_TOKEN</code>. On Github, you can use <a href="https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets">repository Action secrets</a>. On Gitlab you can use masked and hidden <a href="https://docs.gitlab.com/ci/variables/#define-a-cicd-variable-in-the-ui">CI/CD variables</a>. On Forgejo/Codeberg, use <a href="https://forgejo.org/docs/next/user/actions/basic-concepts/#secrets">repository secrets</a>.</p>
<ul>
<li><code>RENOVATE_TOKEN</code>: A token (i.e. a Github PAT or Gitlab PAT) with read/write access to the repository&rsquo;s contents, issues, and the ability to open and close pull requests.
<ul>
<li>On Github, the required token permissions are:
<ul>
<li>Code quality: <code>Read-only</code></li>
<li>Code scanning alerts: <code>Read-only</code></li>
<li>Commit statuses: <code>Read and write</code></li>
<li>Contents: <code>Read and write</code></li>
<li>Dependabot alerts: <code>Read-only</code>
<ul>
<li>I&rsquo;m not sure why enabling this helps, but the tools were fighting each other until I added this</li>
</ul>
</li>
<li>Issues: <code>Read and write</code></li>
<li>Pull requests: <code>Read and write</code>
<ul>
<li>You also need to enable &ldquo;Allow pull requests&rdquo; in the repository&rsquo;s &ldquo;General&rdquo; settings</li>
</ul>
</li>
<li>Repository security advisories: <code>Read and write</code></li>
<li>Secret scanning alerts: <code>Read-only</code></li>
<li>Workflows: <code>Read and write</code>
<ul>
<li>Allows Renovate workflow runs to make changes</li>
</ul>
</li>
</ul>
</li>
<li>On Gitlab, use a &ldquo;legacy&rdquo; token and give it <code>api</code> access</li>
<li>On Forgejo, the token needs:
<ul>
<li><code>read:organization</code></li>
<li><code>write:issue</code></li>
<li><code>write:repository</code></li>
<li><code>read:user</code></li>
</ul>
</li>
</ul>
</li>
<li><code>GH_API_TOKEN</code>: An optional Github PAT (classic) with <code>public_repo</code> scope.
<ul>
<li>While the token is optional, you should provide it regardless of the Git platform to allow pipelines to read the Github API for versions, tags, and releases, without getting rate-limited.</li>
<li>Most pipelines interact with Github in some way, i.e. to download a tool release asset.</li>
<li>Even if the repository is on Gitlab or Forgejo/Codeberg, it can and will use this token when making requests to Github&rsquo;s API, and authenticated requests to Github have a much higher threshold for rate limiting.</li>
</ul>
</li>
</ul>
<h2 id="future-plans">Future Plans</h2>
<p>What started out as a test and practice exercise became a small shift in my development practices. I now see Renovate as a core part of my Git repository hygeine regimen, and I will set it up early and use it often throughout my existing and future repositories. For a little bit of effort adding the secrets to my repository and creating a Renovate config and pipeline file, I get a bot that monitors my dependencies, automatically bumps them to keep me up to date with security and new features, and most importantly, lets me spend my time on other things.</p>
<p>Right now, I occasionally have to go back to each of my repositorys to manually merge major version bumps. I can see this becoming the next growing pain I solve, maybe by adding Ntfy or Gotify notifications, or sending an email from the repository when manual intervention is required.</p>
<p>I am also currently running Renovate inside each CI/CD platform; it&rsquo;s similar to a &ldquo;pull&rdquo; operation, where each repository triggers on a pull request or schedule, and runs Renovate on that platform&rsquo;s runner. I might end up centralizing this either by <a href="https://github.com/mend/renovate-ce-ee">selfhosting the community edition of the Renovate server</a>, or running the <a href="https://github.com/renovatebot/renovate">Renovate CLI</a> in a Docker container on one of my machines. This way, the different Git platforms would not need to trigger their own Renovate actions; the central server could monitor them akin to Dependabot, or I could schedule the CLI to run against all of my repositories. The processing would happen on my local machine at that point, instead of relying on a runner&rsquo;s uptime or availability.</p>
<p>I have already created Renovate pipelines for other platforms, i.e. <a href="https://github.com/redjax/PipelineTemplates/blob/main/.gitlab/maint/renovate.yml">Gitlab</a> and <a href="https://github.com/redjax/PipelineTemplates/blob/main/.forgejo/workflows/renovate.yml">Forgejo</a>. I&rsquo;m using the Gitlab version in my <a href="https://gitlab.com/redjax/ansible-roles"><code>ansible-roles</code></a> and <a href="https://gitlab.com/redjax/ansible-playbooks"><code>ansible-playbooks</code></a> repositories, and in a number of repositories in my personal Forgejo instance (not accessible from the Internet). It was relatively easy to translate the Github workflow to the other platforms. I would like to create versions for other CI platforms like <a href="https://concourse-ci.org">Concourse CI</a> and <a href="https://crowci.dev">Crow CI</a>. I have more or less settled on Forgejo Actions for my self-hosted CI platform, but I dabble in Concourse, Crow, Woodpecker, and briefly tried to adopt Jenkins. I can see a Renovate pipeline being a good proof-of-concept pipeline to build for learning a new platform, and the immediate usefulness makes it an appealing starting point too.</p>
<p>I recommend Renovate to anyone who wants to automate the chore of dependency management, keep their code secure and up to date, wants more control over the process, or who has considered giving the tool a try but hasn&rsquo;t taken the plunge yet. It&rsquo;s easier than you think it will be, and runs well unattended once the initial setup is done.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
