Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: PR Checks

on:
pull_request:
branches: [main]
types: [opened, edited, synchronize, reopened]

jobs:
pr-title:
name: Conventional PR title
runs-on: ubuntu-latest
permissions:
pull-requests: read
steps:
- name: Validate PR title
uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
feat
fix
perf
revert
refactor
docs
build
ci
deps
chore
test
style
requireScope: false
subjectPattern: ^(?![A-Z]).+$
subjectPatternError: |
The subject "{subject}" of pull request "{title}" should start with
a lowercase character so it reads cleanly in release notes.
76 changes: 76 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: Release

on:
push:
branches: [main]

permissions:
contents: write
pull-requests: write
issues: write

concurrency:
group: release-please
cancel-in-progress: false

jobs:
release-please:
name: Maintain release PR
runs-on: ubuntu-latest
steps:
- name: Run release-please
id: release
uses: googleapis/release-please-action@v5
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }}

- name: Checkout released tag
if: ${{ steps.release.outputs.release_created == 'true' }}
uses: actions/checkout@v4
with:
ref: ${{ steps.release.outputs.tag_name }}
fetch-depth: 0

- name: Set up Go
if: ${{ steps.release.outputs.release_created == 'true' }}
uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Validate released version
if: ${{ steps.release.outputs.release_created == 'true' }}
env:
VERSION: ${{ steps.release.outputs.version }}
run: |
set -euo pipefail

actual_version="$(go run -buildvcs=false . --version)"
if [[ "${actual_version}" != "${VERSION}" ]]; then
echo "Version mismatch: release is ${VERSION}, but fasder reports ${actual_version}." >&2
exit 1
fi

- name: Run tests
if: ${{ steps.release.outputs.release_created == 'true' }}
run: go test -buildvcs=false ./...

- name: Upload source archive
if: ${{ steps.release.outputs.release_created == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ steps.release.outputs.tag_name }}
VERSION: ${{ steps.release.outputs.version }}
run: |
set -euo pipefail

archive="fasder-${VERSION}.tar.gz"
git archive \
--format=tar.gz \
--prefix="fasder-${VERSION}/" \
-o "${archive}" \
"refs/tags/${TAG_NAME}"

sha256sum "${archive}"
gh release upload "${TAG_NAME}" "${archive}" --clobber
3 changes: 3 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "0.1.7"
}
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Changelog

## 0.1.7 (2026-09-07)

Release notes before this point were maintained manually. Future entries are
managed by release-please.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,35 @@ Download and install `go`: https://go.dev/doc/install

`go build` will output a `fasder` binary in the current directory.

### Releases

Releases are managed with
[release-please](https://github.com/googleapis/release-please).

Every push to `main` updates a standing `chore: release X.Y.Z` pull request
from conventional commit titles. Merging that release PR updates
`CHANGELOG.md`, bumps the version in `main.go`, tags the merge commit, creates
the GitHub release, and uploads the `fasder-X.Y.Z.tar.gz` source archive used
by the Homebrew tap.

Use conventional PR titles so release-please can classify each change:

| Prefix | Effect |
| --- | --- |
| `fix:` | Patch release |
| `feat:` | Minor release |
| `feat!:` or `BREAKING CHANGE:` | Major release |
| `docs:`, `ci:`, `build:`, `refactor:`, `chore:` | Changelog entry, no version bump |

After the source release is published, update the Homebrew formula in
`wyne/homebrew-tap` and publish bottles from the tap PR with the `pr-pull`
label.

For checked release PRs, configure a `RELEASE_PLEASE_TOKEN` repository secret
with contents, pull request, and issues write access. Without that secret, the
workflow falls back to `GITHUB_TOKEN`; the release PR can still be maintained,
but GitHub may not run the usual PR checks on bot-created commits.

### Benchmarks

Compare Fasder against the original shell script implementation:
Expand Down
4 changes: 3 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
// Global variable to hold the logger
var Logger *log.Logger

const appVersion = "0.1.7" // x-release-please-version

func main() {
logger.InitLog()

Expand Down Expand Up @@ -47,7 +49,7 @@ func main() {
// Commands

if *version {
println("0.1.7")
println(appVersion)
return
}

Expand Down
38 changes: 38 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"packages": {
".": {
"release-type": "go",
"package-name": "fasder",
"changelog-path": "CHANGELOG.md",
"include-component-in-tag": false,
"include-v-in-tag": false,
"bump-minor-pre-major": false,
"draft": false,
"prerelease": false,
"pull-request-title-pattern": "chore: release ${version}",
"pull-request-header": "Merging this PR bumps the fasder source version, updates the changelog, tags the merge commit, publishes the GitHub release, and uploads the source archive used by the Homebrew tap.",
"extra-files": [
{
"type": "generic",
"path": "main.go"
}
],
"changelog-sections": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance" },
{ "type": "revert", "section": "Reverts" },
{ "type": "refactor", "section": "Refactors" },
{ "type": "docs", "section": "Documentation" },
{ "type": "build", "section": "Infrastructure" },
{ "type": "ci", "section": "Infrastructure" },
{ "type": "deps", "section": "Dependencies" },
{ "type": "chore", "section": "Miscellaneous" },
{ "type": "test", "section": "Tests", "hidden": true },
{ "type": "style", "section": "Styling", "hidden": true }
]
}
},
"last-release-sha": "66c3da663310625c71ab69af9fd7d6098ab7c05d"
}
15 changes: 8 additions & 7 deletions release.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/bin/bash
set -euo pipefail

# Check if version is provided
if [ -z "$1" ]; then
if [[ "$#" -ne 1 ]]; then
echo "Usage: $0 <version>"
exit 1
fi
Expand All @@ -10,28 +11,28 @@ fi
input_version="$1"

# Get the version from local code
fasder_version=$(go run . -v 2>&1)
fasder_version="$(go run -buildvcs=false . -v 2>&1)"

# Check if the go_version variable is empty
if [ -z "$fasder_version" ]; then
# Check if the fasder_version variable is empty
if [[ -z "${fasder_version}" ]]; then
echo "'go run . -v' did not return any output. Please ensure the command runs correctly."
exit 1
fi

# Compare the versions
if [ "$fasder_version" != "$input_version" ]; then
if [[ "${fasder_version}" != "${input_version}" ]]; then
echo "Version mismatch: fasder version is '$fasder_version', but expected '$input_version'. Exiting."
exit 1
fi

# Check if the Git tag exists
if ! git rev-parse "$input_version" >/dev/null 2>&1; then
if ! git rev-parse --verify --quiet "refs/tags/${input_version}^{commit}" >/dev/null; then
echo "Git tag '$input_version' does not exist. Please create the tag before proceeding."
exit 1
fi

# Run the git archive command to create the tar.gz
git archive --prefix=fasder-$input_version/ -o fasder-$input_version.tar.gz main
git archive --prefix="fasder-${input_version}/" -o "fasder-${input_version}.tar.gz" "refs/tags/${input_version}"

# Success message
echo "Created fasder-$input_version.tar.gz successfully."
Loading