DEV Community

Cover image for Building a GitHub Action for Recurring Project Items
Akira Hayashi (rin)
Akira Hayashi (rin)

Posted on • Originally published at rindrics.com

Building a GitHub Action for Recurring Project Items

Quick notes on building an automation tool.

What I Built

GitHub Action "recurring-backlog-item-creator"

The YAML config tells the whole story:

defaults:
  project_id: "PVT_kwHOAOKHl84BHgin"
  target_repo: "Rindrics/recurring-backlog-item-creator"
issues:
  - name: "Wash My Cat"
    template_file: ".github/ISSUE_TEMPLATE/wash_my_cat.md"
    creation_months: [1, 3, 5, 7, 9]
    title_suffix: "- {{YearMonth}}"
    fields:
      Priority: "P1"
      Status: "Ready"
  - name: "Buy New Shoes"
    template_file: ".github/ISSUE_TEMPLATE/buy_shoes.md"
    title_prefix: "[{{Year}}]"
    title_suffix: "- ({{Month}})"
    creation_months: [3, 11, 12]
    fields:
      Priority: "P2"
      Status: "Backlog"
    project_id: "PVT_XXXXX"  # you can override the default project_id
    target_repo: "Rindrics/other-repo"  # you can override the default target_repo
Enter fullscreen mode Exit fullscreen mode

The link below will also helpful to understand this action:

Background and Reflection

Creating issues periodically from templates is a common use case.
However, GitHub's existing features become cumbersome when you need:

  • Different creation intervals for each issue
  • Dynamic prefixes/suffixes like [yyyy-MM] in titles
  • Adding issues to projects while setting custom field values

For these requirements, a config file like this solves the problem.

In this action, the core functionality became filtering and validation of the config file
because GitHub GraphQL API enables easy issue creation and project registration.

So I built a tool focused on filtering and validation, implemented in Go.

What Went Well

Validation ensures the action fails if you specify non-existent fields or values in the target project.
This makes it safe to use with confidence.

The config file being self-documenting is also a subtle advantage --- you can see what it does at a glance.

Also, tagpr - thank you as always!

What Could Be Better

I initially organized the code by role within a single main package, thinking it wouldn't grow much.
Even at this scale, changes scattered across multiple files made it somewhat difficult to work with.

To improve cohesion, I only know approaches like port-adapter architecture, which feels like overkill for a tool of this size.
I still don't have a good intuition for the right balance.

The downsides of a single-package structure were minimal.
The simplicity seemed to outweigh any drawbacks.

Where I Got Stuck

Accessing user GitHub projects requires a PAT...!

Until I realized this, I was using a GitHub App token with Project.write repository permission.
This permission likely belongs to the deprecated projects (classic) feature1, and I burned about 3 hours on this...

Future Plans

At v1.0, the filter condition is "month" only, but it could be extended to support "year," "day," and "day of week."

 - name: "Wash My Cat"
    template_file: ".github/ISSUE_TEMPLATE/wash_my_cat.md"
    creation_months: [1, 3, 5, 7, 9, 11]
    creation_day: [10, 20, 30]
    creation_day_of_week: ["Mon"]
Enter fullscreen mode Exit fullscreen mode

With this config, issues would be created on odd-numbered months, on days ending in 0, if they fall on Monday.
For such granular conditions, you'd probably set the cron to run daily.


  1. Probably. Reading here and here suggests so. 

Top comments (0)