Stay in touch with the
Latest iOS dev beans

Get exclusive content, articles and tips submitted by the dev community delivered directly to your inbox. Swift, iOS, macOS, watchOS, SwiftUI, UIKit and more.
Curated by Tiago Henriques and published every week.

No spam, ever. Unsubscribe at any time.
By subscribing you consent to processing of your data
as described in the privacy policy.

Issue #51

โœ๏ธ Keeping My README Up-to-Date with a Swift CLI Tool and GitHub Actions ๐Ÿ‘Œ

CLI
CI/CD
GitHub Actions
June 30, 2025
Sponsored

Try out Xcode 26 in your GitHub Actions with Cirrus Runners

Enjoy the fastest Apple Silicon M4 Pro chips at a fixed monthly price โ€” fully managed so you can focus on shipping great code. Start your free 10-day trial and get 50% off your first three months with code WWDC50.

This message is brought to you by a sponsor who helps keep this content free for everyone. If you have a moment, check them out - your support means a lot!

Welcome to issue #51 of the iOS Coffee Break Newsletter ๐Ÿ“ฌ.

Running a newsletter is not an easy task ๐Ÿฅต! It takes a lot of time and effort, especially when you are juggling a full-time job. I am always on the lookout for ways to streamline my workflow, aiming to automate repetitive tasks that usually require my direct involvement.

One such task is keeping my newsletter repository current and ensuring that all references to it remain aligned. Recently, I set up an automated workflow that updates the README file in my newsletter repository every week. This is done using a Swift-based command-line tool and GitHub Actions.

This week, I would like to walk you through that process and what I learned from it! ๐Ÿ‘‡

The Plan

In this edition, my plan was to create a command-line tool that fetches the latest issues in my newsletter and updates the README.md file with that content. To make it fully automated, I also created a GitHub workflow that runs this tool on a regular schedule. Here is the high-level plan:

  • Develop a Swift command-line that:
    • Collects the most recent newsletter issues.
    • Updates a specified file (provided via the ArgumentParser) with the new data.
  • Set up a GitHub Actions workflow that:
    • Executes once per week.
    • Runs the CLI tool to fetch and insert the latest content.
    • Commits and pushes any updates to the repository if there are changes.

Building the Executable

The first step involves creating a Swift command-line executable.

I won't go into the details of how to build a Swift CLI here, but if you are curious, feel free to take a look at this guide.

import ArgumentParser
import Foundation
 
@main
struct feedparser: AsyncParsableCommand {
    @Argument(help: "The path of the destination README file.")
    var destination: String
 
    func run() async throws {
        let apiClient = APIClient()
 
        do {
            // fetch issues from the newsletter API
            let issues = try await apiClient.getIssues()
            let latestIssues = (issues.count < 10) ? issues : Array(issues.prefix(10))
            // generate content from latest issues
            let content = MarkdownGen.makeContent(from: latestIssues)
            // write to the README.md file
            try content.write(to: URL(fileURLWithPath: destination), atomically: true, encoding: .utf8)
            print("โœ… Successfully written to \(destination) file.")
        } catch let error {
            print("โŒ Error: \(error)")
        }
    }
}

Here is a quick overview of what the following code does:

  • The APIClient is responsible for retrieving newsletter issues, making use of Swift's async/await concurrency model.
  • Then, MarkdownGen.makeContent() is called to generate the markdown-formatted string that will be written to a file.
  • Finally, this content is written to a file - README.md in my case.

Setting Up the GitHub Workflow

Next, I needed to create the automation using GitHub Actions:

name: Fetch latest newsletter issues and update the README.md
 
on:
  push:
  schedule:
    - cron: "0 0 * * 2" # At 00:00 every Tuesday.
 
jobs:
  build:
    runs-on: macos-latest
 
    steps:
      - uses: actions/checkout@v4
      - run:  swift run feedparser README.md
      - run: |
          git config user.name henriquestiagoo
          git config user.email henriquestiago@ua.pt
          git add README.md
          git commit -m "[generated by github action workflow]: Update latest newsletter issues in `README.md` file" || echo "No changes to commit"
          git push origin main || echo "No changes to commit"

Here is a summary of the workflow setup:

  • I configured the workflow to trigger both on every push and once weekly using the push and schedule triggers.
  • The checkout action ensures the latest version of the code is pulled from the repository.
  • After that, the CLI tool is executed to fetch the latest issues and update the README.md file.
  • If there are any changes, the workflow commits those updates back to the repository.

Here is what the generated README.md looks like after the workflow has been executed:

Configuring Cirrus Runners

As a token of appreciation to Cirrus Labs for sponsoring this edition, I would like to demonstrate how you can run this workflow using the Cirrus Runners infrastructure. All it takes is updating the runs-on: property by replacing the GitHub runner with the appropriate Cirrus runner image.

name: Fetch latest newsletter issues and update the README.md
 
[...]
 
jobs:
  build:
    name: "Run on the fastest infrastructure!"
    #runs-on: macos-latest
    runs-on: ghcr.io/cirruslabs/macos-runner:sequoia
 
    [...]

To get started with Cirrus Runners, you need to install the Cirrus Runners GitHub App in your GitHub organization. For detailed instructions, refer to the Cirrus Runners setup guide.

And that's everything you need to do to move over to Cirrus Runners' infrastructure!

๐Ÿค Wrapping Up

Swift CLI tools paired with GitHub Actions make for a powerful automation setup, ideal for handling repetitive or manual tasks. In this case, I have combined them to ensure my newsletter's README file is always up-to-date with the content on the website - all of this without needing input from my side.

The project is fully open-source, so if you are interested, feel free to check out the repository.

Have any feedback, suggestions, or ideas to share? Feel free to reach out to me on Twitter.

tiagohenriques avatar

Thank you for reading this issue!

I truly appreciate your support. If you have been enjoying the content and want to stay in touch, feel free to connect with me on your favorite social platform: