Automating Weekly Releases with GitHub Actions
7 min readSet up a workflow that tags and publishes releases every week, regardless of your stack.
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
- Create
.github/workflows/weekly-release.ymlwith the snippet above (or copy from the gist). - Ensure
GITHUB_TOKENhascontents: write—the default token is fine, but the explicit permission block avoids future least-privilege surprises. - Push to
main. The cron starts on the next Sunday; you can run it instantly via the Run workflow button exposed byworkflow_dispatch. - Verify the release. A tag like
2025-07-13will 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-actionanddocker/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: truecollates PR titles and commit messages. - Language-agnostic: Works for any project hosted on GitHub.
- On-demand control:
workflow_dispatchlets 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
mainwith 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.