Skip to content

Something a foot

Completed 6,000 km distance for cycle riding this year, a very satisfying number as I wasnt able to do much cycling before May.

A new month means its time to update dependencies across all projects. Although antq has proven very good at reporting outdated dependencies for Clojure projects and GitHub actions, it is quite a niche tool and something extra to learn or maintain a config for.

When reviewing options for liquida/antq there was a link to ... GitHub workflow that generates a PR with all the dependency updates. This project is now in maintenance mode and recommends looking at the Renovate GitHub action.

So I decided to create a CI workflow using Renovate that generates a pull request to update Clojure library dependencies and GitHub actions.

Rather than write this myself, I felt it was a useful task to ask an LLM tool to tackle. I felt confident I knew how to write a clear question (prompt) for the LLM tool. It was also a small enough task that I wouldnt blow all my 'free' tokens. I also hoped that it was a simple enough task that I wouldnt have to keep refining the question to get the response I needed.

The reply should be simple enough that I can understand, as I already have plenty of experience writing GitHub workflows and configurations for the tools used by a workflow (e.g. Megalinter).

Unfortunately the resulting Renovate.json configuration doesnt like Clojure, so AI seems to have failed quite badly (or was too optimistic).

Taking my usual approach of an Internet search, I discovered the Mend App, which is described in more detail in the Mend for GitHub.com docs.

The Mend app kind of works but still seems to require some manual intervention (pressing buttons on developer.mend.io app) and only supports (or only configured for) maven dependencies and not git updates, e.g. seancorfield/deps-new.

The results of the discussion with the LLM are documented in this post and the results were also published to the web:

Create GitHub workflow with Renovate for Clojure projects

Large Language Model toolsλ︎

I am currently in the investigation and evaluation stages of so called 'Generaltive AI' tools, specifically non-deterministic Large Language Models.

The hypothesis is that low value time consuming tasks are valuable to delegate to an LLM. An LLM can take a few minutes to generate a reply, especially when asking it to create code or configuration.

The hypothesis continues that the reply from the LLM should be easy to understand and verify correctness. This requires either working being shown or reference content used to create the reply.

If the reply is clear enough to understand, then the reply form the LLM can be update to create a relevant solution.

The advantages of using an LLM is that to get a relevant reply a very clear question has to be written.

Clojure Surveyλ︎

I have been thinking about the AI questions and I think they are too simplistic to be meaningful. Whilst a full analysis of AI tool use would be valuable, this could easily be a survey in its own right.

Perhaps a few specific questions on use would add value to the Clojure community, in at least helping everyone understand what people are currently finding useful.

I have not adopted AI tools (LLM's) directly into my workflow as I am evaluating where they would be valuable. I also do not want my brain to become lazy and less able to learn new things quickly.

I do want to off-set lower value or commodity kind of tasks to an AI tool, so I can focus on higher value work and learning.

LLM workflow

- integrated into editor
- separate desktop / Website

LLM models used

- Anthropic Claude
- ChatGPT

GitHub workflowsλ︎

Practicalli has GitHub workflows to automate common tasks.

The liquidz/antq workflow is used to check for new versions at the start of every month, reporting when a newer version of a library is available. This worflow still required me to run liquidz/antq locally, commit changes and push to GitHub, for each of the many repositories Practicalli manages.

This can take many hours of my time. Using a workflow that generated the requisite pull requests should save some time.

Dependabot and Renovate are widely used tools to manage dependencies. Dependabot is quite simple and specific to the GitHub service. Renovate has more features and provides greater control over a repository.

I decided to try Renovate first, as a more generic solution should be more future-proof. I also wanted to create separate pull requests for GitHub actions verses Clojure library dependencies.

Creating a new GitHub workflow using Renovate would be quite an easy task to define, so I decided to ask Claude.ai Large Language Model to create the workflow.

A GitHub Workflow and Renovate configuration were returned by made by Claude.ai. Ironically the GitHub workflow was significantly older GitHub action versions, but they should be simple enough to correct.

LLM Prompt questionλ︎

Write a GitHub workflow using the Renovate tool to upgrade all dependencies in a Clojure project to their latest versions.

A pull request should be created with newer versions of Clojure project dependencies.

Assume the Clojure projects are defined with a deps.edn configuration file.

The GitHub workflow should be scheduled to run on the first day of every month, at 04:00.

The Renovate tool should also check for the latest versions of GitHub actions across all GitHub workflows in the project and include new action versions in a separate pull request.

LLM Responseλ︎

I'll create a GitHub workflow that uses Renovate to automatically update Clojure dependencies and GitHub Actions.Now I'll create the Renovate configuration file that handles Clojure dependencies and GitHub Actions:Perfect! I've created two files for you:

## 1. GitHub Workflow (`.github/workflows/renovate.yml`)
This workflow:
- Runs on the **1st of every month at 04:00 UTC** via cron schedule
- Includes a manual trigger option via `workflow_dispatch`
- Uses the official Renovate GitHub Action

## 2. Renovate Configuration (`.github/renovate.json`)
This configuration:
- **Clojure dependencies**: Groups all deps.edn dependency updates into a single PR named "Clojure dependencies"
- **GitHub Actions**: Groups all GitHub Actions updates into a separate PR named "GitHub Actions"
- Uses semantic commit messages (e.g., `chore(deps):` for Clojure, `ci(actions):` for GitHub Actions)
- Keeps PRs manageable with concurrent limits
- Doesn't automerge (requires manual review)

## Setup Requirements

1. **Create a GitHub token** for Renovate:
   - Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
   - Generate a token with `repo` scope
   - Add it to your repository secrets as `RENOVATE_TOKEN`

2. **Place the files** in your repository:
   - `.github/workflows/renovate.yml`
   - `.github/renovate.json`

3. **deps.edn support**: Renovate automatically detects and updates dependencies in `deps.edn` files using the format:
   ```clojure
   {:deps {org.clojure/clojure {:mvn/version "1.11.1"}}}
   ```

The workflow will create separate pull requests for Clojure dependencies and GitHub Actions, making it easy to review and merge updates independently!


!!! EXAMPLE "Renovate configuration"

    ```json title=".github/renovate.json"
    {
      "$schema": "https://docs.renovatebot.com/renovate-schema.json",
      "extends": [
        "config:recommended"
      ],
      "packageRules": [
        {
          "description": "Group all Clojure dependencies into one PR",
          "matchManagers": ["deps-edn"],
          "groupName": "Clojure dependencies",
          "semanticCommitType": "chore",
          "semanticCommitScope": "deps"
        },
        {
          "description": "Group all GitHub Actions into a separate PR",
          "matchManagers": ["github-actions"],
          "groupName": "GitHub Actions",
          "semanticCommitType": "ci",
          "semanticCommitScope": "actions"
        }
      ],
      "clojure": {
        "enabled": true
      },
      "schedule": [
        "at any time"
      ],
      "timezone": "UTC",
      "prConcurrentLimit": 10,
      "prHourlyLimit": 0,
      "automerge": false,
      "platformAutomerge": false,
      "rebaseWhen": "behind-base-branch"
    }
    ```


!!! EXAMPLE "GitHub Workflow configuration"

    ```yaml title=".github/workflows/renovate.yaml"
    name: Renovate Dependencies

    on:
      schedule:
        # Run on the first day of every month at 04:00 UTC
        - cron: '0 4 1 * *'
      workflow_dispatch: # Allow manual trigger

    jobs:
      renovate:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout repository
            uses: actions/checkout@v4

          - name: Run Renovate
            uses: renovatebot/github-action@v40.3.2
            with:
              configurationFile: .github/renovate.json
              token: ${{ secrets.RENOVATE_TOKEN }}
            env:
              LOG_LEVEL: info
    ```


### Review of LLM results

GitHub workflows are comprehensively documented, so my expectations from the LLM were quite high.  The renovate GitHub action is well known so there should be plenty of examples of use out in the Internet.

The setup requirements were accurate, although I took a slight detour and created a `RENOVATE_TOKEN` secret within the Practicalli Organisation.  Adding an Organisation secret avoids the need to add this token to each of the Practicalli repositories.

Ironically, the generated GitHub workflow to check for the newest library versions is not actually using the latest library versions.  The GitHub workflow file was update by checking the latest versions on the respective GitHub repository releases.

- [Checkout action](https://github.com/actions/checkout){target=_blank} is version v6.0.1, `actions/checkout@v6`
- [Renovate action](https://github.com/renovatebot/renovate) is version 42.34.1:  `renovatebot/github-action@v42`

### Practicalli workflows

```json
{
  "comment": "Renovate updates for Clojure library dependencies and GitHub actions",
  "author": "Practicalli Johnny",
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [ "config:recommended" ],
  "packageRules": [
    {
      "description": "Clojure dependency updates Pull Request",
      "matchManagers": ["deps-edn"],
      "groupName": "Clojure dependencies",
      "semanticCommitType": "chore",
      "semanticCommitScope": "deps"
    },
    {
      "description": "GitHub Action updates Pull Request",
      "matchManagers": ["github-actions"],
      "groupName": "GitHub Actions",
      "semanticCommitType": "ci",
      "semanticCommitScope": "actions"
    }
  ],
  "clojure": { "enabled": true },
  "schedule": [ "at any time" ],
  "timezone": "UTC",
  "prConcurrentLimit": 10,
  "prHourlyLimit": 0,
  "automerge": false,
  "platformAutomerge": false,
  "rebaseWhen": "behind-base-branch"
}
name: Renovate version updates

on:
  schedule:
    # Run on the first day of every month at 04:00 UTC
    - cron: '0 4 1 * *'
  workflow_dispatch: # Allow manual trigger

jobs:
  renovate:
    runs-on: ubuntu-latest
    steps:
      - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}"
      - run: echo "🐧 Job running on ${{ runner.os }} server"
      - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository"

      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          sparse-checkout: |
            .github
            deps.edn
      - run: echo "🐙 ${{ github.repository }} repository was cloned to the runner."

      - name: Run Renovate
        uses: renovatebot/github-action@v42
        with:
          configurationFile: .github/renovate.json
          token: ${{ secrets.RENOVATE_TOKEN }}
        env:
          LOG_LEVEL: info

      # Summary and status
      - run: echo "🎨 Renovate version update check completed"
      - run: echo "🍏 Job status is ${{ job.status }}."

Cyclingλ︎

A ride to the Archive Cafe near East Grinstead and a loop to Otford and back were the two rides this week (with a quick ride to the local bike shop and back in between).

With the Otford ride I completed 6,000 km in distance for 2025, a very pleasing achievement as I didnt do any longer distance cycling until May/June.

Volunteering for Devoxx London helped my cycle 45km a day for the second week in May. This gave me the confidence that I had recovered from the medication I had been on which had prevented me from exercising.

I did 13 rides over 50km distance between February and the end of May. Then 79 rides until the end of the year. So a big difference between the first and second half of the year.

I hope that I can keep reasonably illness free and fit enough throughout the winter season, so I can aim for 10,000 km distance for 2026.

I guess that is one new years resolution set 😄

Rear Gear Shifter issuesλ︎

My rear gears have been a little tricky for the last few weeks and it seems that the right shifter is starting to fail.

Finding an exact replacement is proving to be a little tricky. Shimano have stopped delivery of new parts until January next year, so it would be at least a month before I could get a new part.

Finding a shop with the exact part is also proving tricky and second hand parts are not very clear on if the shifter is for disc or rim brakes.

I had to do a little investigation to figure out the model numbers for the various shifter options, to ensure I would get a suitable shifter.

  • R7020 105 mechanical shifting with hydraulic disc brakes
  • R8000 Ultegra mechanical shifting with rim brakes
  • R8020 Ultegra mechanical shifting with hydraulic disc brakes
  • R8050 Ultegra electronic Di2 shifting with rim brakes

Typical prices for a new shifter seem to be around 140.00 GBP for a new part.

Buying shifter online:

Shifter pair:

Only a replacement lever:

Going Electric ?λ︎

Alternative approach would be to replace the groupset with an electronic version, preferably wireless. This would be more expense but would be the only major upgrade I was interested in doing to the bike.

It should be possible to mix and match Ltwoo components with either Shimano or SRAM. Ltwoo group set should be significantly cheaper (perhaps slightly heavier) but should give similar performance (according to Trace Velo review).

There would be a maintenance cost to replacing the existing system with a new groupset. However, the maintenance that I would ask the bike shop to do is to change the shifters and rework the hydraulic breaks.

NOTE: I found a replacement R8020 manual gear shifter for a reasonable price (106 GBP), so I will delay investing in electronic gearset for now.


Thank you.

🌐 Practical.li Website

Practical.li GitHub Org practicalli-johnny profile

@practicalli@clj.social @practical_li