← Back to michaelbastos.com
Automating Weekly Releases with GitHub Actions

Automating Weekly Releases with GitHub Actions

7 min read
GitHub ActionsCI/CDAutomationRelease ManagementDevOps

Set up a workflow that tags and publishes releases every week, regardless of your stack.

Published on

Why automate weekly releases?

Manual release processes are fragile, time-consuming, and easy to postpone. By letting a bot cut a release every Sunday at 00:00 UTC you guarantee predictable delivery cadences, faster feedback loops, and happier consumers.

Understanding the workflow file

name: Weekly Release

on:
  schedule:
    - cron: '0 0 * * 0'
  workflow_dispatch:

permissions:
  contents: write

jobs:
  create-release:
    runs-on: ubuntu-latest
    steps:
      - name: Create weekly release
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const { repo, owner } = context.repo;
            let lastReleaseDate = new Date(0);
            try {
              const latestRelease = await github.rest.repos.getLatestRelease({
                owner,
                repo
              });
              lastReleaseDate = new Date(latestRelease.data.created_at);
            } catch (error) {
              core.info('No previous release found');
            }
            const lastWeek = new Date();
            lastWeek.setDate(lastWeek.getDate() - 7);
            const sinceDate = lastReleaseDate > lastWeek ? lastReleaseDate : lastWeek;
            const commits = await github.paginate(
              github.rest.repos.listCommits,
              {
                owner,
                repo,
                since: sinceDate.toISOString(),
                sha: 'main'
              }
            );
            if (commits.length === 0) {
              core.info('No new commits since last release');
              return;
            }
            const tag = `${new Date().toISOString().slice(0, 10)}`;
            await github.rest.repos.createRelease({
              owner,
              repo,
              tag_name: tag,
              name: `Release ${tag}`,
              target_commitish: 'main',
              generate_release_notes: true
            });

The heavy lifting is done by actions/github-script: it gives you a fully-authenticated Octokit instance so you can call the REST API directly.

Step-by-step implementation

  1. Create .github/workflows/weekly-release.yml with the snippet above (or copy from the gist).
  2. Ensure GITHUB_TOKEN has contents: write—the default token is fine, but the explicit permission block avoids future least-privilege surprises.
  3. Push to main. The cron starts on the next Sunday; you can run it instantly via the Run workflow button exposed by workflow_dispatch.
  4. Verify the release. A tag like 2025-07-13 will appear under Releases with autogenerated notes.

Adapting to any language or framework

GitHub Releases are repository-level. Whether you build with Go, Python, Java, or a monorepo of micro-frontends, the same job works. To attach compiled artifacts:

  - uses: actions/upload-artifact@v4
    with:
      name: linux-binary
      path: dist/mytool

Follow the release step with upload-release-asset or a marketplace action that wraps it. You can also drive package registries:

  • Publish an NPM package with npm publish.
  • Upload a Python wheel to PyPI via pypa/gh-action-pypi-publish@v1.
  • Push an OCI image to GitHub Packages using docker/login-action and docker/build-push-action. The weekly trigger stays identical; only the build matrix differs.

Benefits at a glance

  • Consistency: Stakeholders know a fresh build lands every week.
  • Reduced merge pain: Shorter release cycles mean smaller diffs and easier rollbacks.
  • Automated changelog: generate_release_notes: true collates PR titles and commit messages.
  • Language-agnostic: Works for any project hosted on GitHub.
  • On-demand control: workflow_dispatch lets you cut an interim hot-fix without waiting.

Best practices

  • Adopt semantic versioning alongside the date tag if downstream tooling expects v1.2.3.
  • Guard main with required checks so every auto-release is green.
  • Rotate the token to a fine-grained PAT if you need to push to sibling repos.
  • Combine with an environment to require manual approval for production assets.

A 30-line workflow removes an entire class of "Who is on release duty?" conversations. Set it and forget it, your CI will ship on time, every time.