2 Commits
Author SHA1 Message Date
kato 76bc3d8185 ci: add nodejs24 and nodejs24-bin to CI dependencies
Tests / Go and GTK tests (push) Successful in 1m38s
Release / Tests before release (push) Successful in 2m5s
Release / Build and publish release (push) Successful in 3m23s
2026-07-16 20:48:42 +03:00
kato 449626bffa docs: add CI/release documentation and ignore dist directory
Tests / Go and GTK tests (push) Failing after 1m8s
Add `/dist/` to `.gitignore` to exclude locally built distribution
artifacts. Document the Gitea Actions workflow, release tagging, and
branch protection setup in the README.
2026-07-16 19:40:21 +03:00
7 changed files with 324 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
name: Release
on:
push:
tags:
- 'v*'
permissions:
code: read
jobs:
test:
name: Tests before release
runs-on: ubuntu-latest
container: registry.fedoraproject.org/fedora:44
steps:
- name: Validate release tag
shell: bash
run: |
set -Eeuo pipefail
[[ "${GITHUB_REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
printf 'Tag must match vMAJOR.MINOR.BUG; got %s\n' "${GITHUB_REF_NAME}" >&2
exit 1
}
- name: Install system dependencies
run: >-
dnf install -y
bzip2 curl gcc gcc-c++ git gtk4-devel gtk4-layer-shell-devel
jq libX11-devel libXfixes-devel nodejs24 nodejs24-bin pkgconf-pkg-config
pulseaudio-utils ShellCheck tar gzip binutils
- name: Check out repository
uses: https://github.com/actions/checkout@v4
- name: Install the Go version from go.mod
shell: bash
run: |
set -Eeuo pipefail
go_version="$(awk '$1 == "go" { print $2 }' go.mod)"
curl --fail --location --silent --show-error \
"https://go.dev/dl/go${go_version}.linux-amd64.tar.gz" \
--output /tmp/go.tar.gz
rm -rf /usr/local/go
tar -C /usr/local -xzf /tmp/go.tar.gz
ln -sf /usr/local/go/bin/go /usr/local/bin/go
ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
go version
- name: Run tests and static checks
run: ./scripts/ci/test.sh
publish:
name: Build and publish release
needs: test
permissions:
code: read
releases: write
runs-on: ubuntu-latest
container: registry.fedoraproject.org/fedora:44
steps:
- name: Install system dependencies
run: >-
dnf install -y
bzip2 curl gcc gcc-c++ git gtk4-devel gtk4-layer-shell-devel
jq libX11-devel libXfixes-devel nodejs24 nodejs24-bin pkgconf-pkg-config
pulseaudio-utils ShellCheck tar gzip binutils
- name: Check out repository and tags
uses: https://github.com/actions/checkout@v4
with:
fetch-depth: 0
- name: Install the Go version from go.mod
shell: bash
run: |
set -Eeuo pipefail
go_version="$(awk '$1 == "go" { print $2 }' go.mod)"
curl --fail --location --silent --show-error \
"https://go.dev/dl/go${go_version}.linux-amd64.tar.gz" \
--output /tmp/go.tar.gz
rm -rf /usr/local/go
tar -C /usr/local -xzf /tmp/go.tar.gz
ln -sf /usr/local/go/bin/go /usr/local/bin/go
ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
go version
- name: Build portable release archive
run: ./scripts/ci/package-release.sh "${GITHUB_REF_NAME}"
- name: Generate release notes
shell: bash
run: |
set -Eeuo pipefail
previous_tag="$(git describe --tags --abbrev=0 "${GITHUB_REF_NAME}^" --match 'v[0-9]*' 2>/dev/null || true)"
{
printf 'Automated Captioneer release for `%s`.\n\n' "${GITHUB_REF_NAME}"
printf 'The Linux x86_64 archive contains both Captioneer commands and their Sherpa/ONNX native libraries. Models are downloaded separately with `scripts/download-models.sh`.\n'
if [[ -n "$previous_tag" ]]; then
printf '\nChanges since `%s`:\n\n' "$previous_tag"
git log --no-merges --pretty='- %s (`%h`)' "${previous_tag}..${GITHUB_REF_NAME}"
fi
} > dist/release-notes.md
- name: Publish Gitea release
env:
GITEA_API_URL: ${{ gitea.api_url }}
GITEA_REPOSITORY: ${{ gitea.repository }}
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
RELEASE_TAG: ${{ gitea.ref_name }}
RELEASE_NOTES: dist/release-notes.md
run: >-
./scripts/ci/publish-release.sh
"dist/captioneer-${GITHUB_REF_NAME}-linux-amd64.tar.gz"
"dist/captioneer-${GITHUB_REF_NAME}-linux-amd64.tar.gz.sha256"
+43
View File
@@ -0,0 +1,43 @@
name: Tests
on:
pull_request:
push:
branches:
- '**'
permissions:
code: read
jobs:
test:
name: Go and GTK tests
runs-on: ubuntu-latest
container: registry.fedoraproject.org/fedora:44
steps:
- name: Install system dependencies
run: >-
dnf install -y
bzip2 curl gcc gcc-c++ git gtk4-devel gtk4-layer-shell-devel
jq libX11-devel libXfixes-devel nodejs24 nodejs24-bin pkgconf-pkg-config
pulseaudio-utils ShellCheck tar gzip binutils
- name: Check out repository
uses: https://github.com/actions/checkout@v4
- name: Install the Go version from go.mod
shell: bash
run: |
set -Eeuo pipefail
go_version="$(awk '$1 == "go" { print $2 }' go.mod)"
curl --fail --location --silent --show-error \
"https://go.dev/dl/go${go_version}.linux-amd64.tar.gz" \
--output /tmp/go.tar.gz
rm -rf /usr/local/go
tar -C /usr/local -xzf /tmp/go.tar.gz
ln -sf /usr/local/go/bin/go /usr/local/bin/go
ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
go version
- name: Run tests and static checks
run: ./scripts/ci/test.sh
+1
View File
@@ -5,3 +5,4 @@ models/silero_vad_v5.onnx
# Locally built executable.
/captioneer
/build/
/dist/
+15
View File
@@ -201,6 +201,21 @@ distrobox enter --no-workdir captioneer-dev -- bash -lc '
Run this from the repository root. The build and run helpers resolve that path automatically.
## Gitea Actions and releases
The `Tests` workflow runs the normal and GTK-tagged Go tests, `go vet`, and ShellCheck for every pull request and branch push. To make it mandatory for pull requests, open the repository's **Settings → Branches**, edit the protection rule for `master`, enable required status checks, and select **Tests / Go and GTK tests** after its first run. Workflow files can report the check, but the branch-protection rule is what prevents merging when it fails.
Pushing a tag that exactly follows `vMAJOR.MINOR.BUG` runs the same test suite first, then builds and publishes a Gitea release:
```bash
git tag v1.3.519
git push origin v1.3.519
```
The release contains a checksummed Linux x86_64 archive with `captioneer`, `captioneer-desktop`, the required Sherpa/ONNX shared libraries, the model download script, the README, and the license. The desktop command still requires GTK4 and GTK4 Layer Shell runtime libraries on the destination system.
The release workflow uses Gitea's built-in `GITEA_TOKEN`; no personal token is required. In **Settings → Actions → General**, allow the workflow token `Read` access to code and `Write` access to releases. Gitea clamps workflow permissions to those repository settings, so a more restrictive maximum produces an actionable HTTP 403 during publishing.
## License
Captioneer is licensed under the [Apache License 2.0](LICENSE). Sherpa-Onnx is Apache-2.0 licensed, GTK4 is LGPL-2.1-or-later, and GTK4 Layer Shell is MIT licensed. Captioneer links to the system GTK libraries rather than copying their source into the project.
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
set -Eeuo pipefail
repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd -P)"
cd -- "$repo_root"
tag=${1:-}
if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
printf 'captioneer: release tag must match vMAJOR.MINOR.BUG, got %q\n' "$tag" >&2
exit 1
fi
platform=linux-amd64
archive_name="captioneer-${tag}-${platform}.tar.gz"
package_name="captioneer-${tag}-${platform}"
package_dir="dist/$package_name"
rm -rf -- "$package_dir"
rm -f -- "dist/$archive_name" "dist/$archive_name.sha256"
mkdir -p -- "$package_dir/lib" "$package_dir/scripts"
# The Sherpa Go module embeds an absolute build-machine RPATH. Add a portable
# fallback so the bundled native libraries resolve beside the extracted tools.
# shellcheck disable=SC2016 # $ORIGIN must remain literal for the ELF loader.
export CGO_LDFLAGS='-Wl,-rpath,$ORIGIN/lib'
go build -trimpath -o "$package_dir/captioneer" ./src/cmd/captioneer
go build -trimpath -tags gtk -o "$package_dir/captioneer-desktop" ./src/cmd/captioneer-desktop
sherpa_dir="$(go list -m -f '{{.Dir}}' github.com/k2-fsa/sherpa-onnx-go-linux)"
sherpa_lib_dir="$sherpa_dir/lib/x86_64-unknown-linux-gnu"
cp -- "$sherpa_lib_dir/libsherpa-onnx-c-api.so" "$package_dir/lib/"
cp -- "$sherpa_lib_dir/libonnxruntime.so" "$package_dir/lib/"
cp -- README.md LICENSE "$package_dir/"
cp -- scripts/download-models.sh "$package_dir/scripts/"
for executable in captioneer captioneer-desktop; do
# shellcheck disable=SC2016 # Verify the literal ELF-loader token.
if ! readelf -d "$package_dir/$executable" | grep -Fq '$ORIGIN/lib'; then
printf 'captioneer: %s is missing the portable native-library RPATH\n' "$executable" >&2
exit 1
fi
done
tar -C dist -czf "dist/$archive_name" "$package_name"
(
cd -- dist
sha256sum "$archive_name" > "$archive_name.sha256"
)
printf '%s\n' "$repo_root/dist/$archive_name"
printf '%s\n' "$repo_root/dist/$archive_name.sha256"
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env bash
set -Eeuo pipefail
: "${GITEA_API_URL:?GITEA_API_URL is required}"
: "${GITEA_REPOSITORY:?GITEA_REPOSITORY is required}"
: "${GITEA_TOKEN:?GITEA_TOKEN is required}"
: "${RELEASE_TAG:?RELEASE_TAG is required}"
: "${RELEASE_NOTES:?RELEASE_NOTES is required}"
if [[ ! "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
printf 'captioneer: release tag must match vMAJOR.MINOR.BUG, got %q\n' "$RELEASE_TAG" >&2
exit 1
fi
if (( $# == 0 )); then
printf 'captioneer: at least one release asset is required\n' >&2
exit 1
fi
for asset in "$@"; do
[[ -f "$asset" ]] || { printf 'captioneer: release asset not found: %s\n' "$asset" >&2; exit 1; }
done
api_base="${GITEA_API_URL%/}/repos/$GITEA_REPOSITORY"
authorization="Authorization: token $GITEA_TOKEN"
release_response="$(mktemp)"
trap 'rm -f -- "$release_response"' EXIT
status="$(curl --silent --show-error --output "$release_response" --write-out '%{http_code}' \
--header "$authorization" \
"$api_base/releases/tags/$RELEASE_TAG")"
release_payload="$(jq -n \
--arg tag "$RELEASE_TAG" \
--arg name "Captioneer $RELEASE_TAG" \
--rawfile body "$RELEASE_NOTES" \
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')"
case "$status" in
200)
release_id="$(jq -er '.id' "$release_response")"
curl --fail-with-body --silent --show-error \
--request PATCH \
--header "$authorization" \
--header 'Content-Type: application/json' \
--data "$release_payload" \
"$api_base/releases/$release_id" > "$release_response"
;;
404)
curl --fail-with-body --silent --show-error \
--request POST \
--header "$authorization" \
--header 'Content-Type: application/json' \
--data "$release_payload" \
"$api_base/releases" > "$release_response"
release_id="$(jq -er '.id' "$release_response")"
;;
*)
printf 'captioneer: Gitea release lookup failed with HTTP %s\n' "$status" >&2
cat "$release_response" >&2
exit 1
;;
esac
for asset in "$@"; do
asset_name="$(basename -- "$asset")"
while IFS= read -r attachment_id; do
[[ -n "$attachment_id" ]] || continue
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "$authorization" \
"$api_base/releases/$release_id/assets/$attachment_id" >/dev/null
done < <(jq -r --arg name "$asset_name" '.assets[]? | select(.name == $name) | .id' "$release_response")
curl --fail-with-body --silent --show-error \
--request POST \
--header "$authorization" \
--form "attachment=@$asset" \
"$api_base/releases/$release_id/assets?name=$asset_name" >/dev/null
printf 'Uploaded %s\n' "$asset_name"
done
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -Eeuo pipefail
repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd -P)"
cd -- "$repo_root"
go test ./...
go test -tags gtk ./...
go vet ./...
go vet -tags gtk ./...
shellcheck \
scripts/download-models.sh \
scripts/distrobox/common.sh \
scripts/distrobox/build.sh \
scripts/distrobox/run.sh \
scripts/ci/test.sh \
scripts/ci/package-release.sh \
scripts/ci/publish-release.sh