Skip to content

Commit e02b469

Browse files
committed
feat(release): add release automation and workflows
- Introduced release automation process in README.md. - Added GitHub Actions workflows for building binaries, creating draft releases, and publishing Docker images. - Implemented version management with bump2version. - Updated root command to include version information.
1 parent ee7b8e8 commit e02b469

8 files changed

Lines changed: 372 additions & 0 deletions

File tree

.bumpversion.cfg

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[bumpversion]
2+
current_version = 0.1.0
3+
commit = True
4+
tag = True
5+
6+
[bumpversion:file:internal/linktransfer/version.go]
7+
search = Version = "v{current_version}"
8+
replace = Version = "v{new_version}"

.github/workflows/build.yml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
name: Build Release Binaries
2+
3+
on:
4+
workflow_dispatch:
5+
release:
6+
types: [released]
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build:
13+
name: Build and Upload Release Assets
14+
runs-on: ubuntu-22.04
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
include:
19+
# Windows builds
20+
- os: windows
21+
arch: amd64
22+
extension: .exe
23+
- os: windows
24+
arch: arm64
25+
extension: .exe
26+
27+
# Linux builds
28+
- os: linux
29+
arch: amd64
30+
extension: ""
31+
- os: linux
32+
arch: arm64
33+
extension: ""
34+
- os: linux
35+
arch: 386
36+
extension: ""
37+
- os: linux
38+
arch: arm
39+
extension: ""
40+
- os: linux
41+
arch: ppc64le
42+
extension: ""
43+
- os: linux
44+
arch: s390x
45+
extension: ""
46+
- os: linux
47+
arch: riscv64
48+
extension: ""
49+
- os: linux
50+
arch: mips64
51+
extension: ""
52+
53+
# macOS builds
54+
- os: darwin
55+
arch: amd64
56+
extension: ""
57+
- os: darwin
58+
arch: arm64
59+
extension: ""
60+
61+
# FreeBSD builds
62+
- os: freebsd
63+
arch: amd64
64+
extension: ""
65+
- os: freebsd
66+
arch: arm64
67+
extension: ""
68+
69+
# OpenBSD builds
70+
- os: openbsd
71+
arch: amd64
72+
extension: ""
73+
74+
steps:
75+
- uses: actions/checkout@v3
76+
77+
- name: Set up Go
78+
uses: actions/setup-go@v4
79+
with:
80+
go-version: '1.24'
81+
82+
- name: Build Binary
83+
env:
84+
GOOS: ${{ matrix.os }}
85+
GOARCH: ${{ matrix.arch }}
86+
CGO_ENABLED: 0
87+
run: |
88+
go build -trimpath -ldflags="-s -w" -o "linktransfer-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.extension }}" cmd/lt/main.go
89+
90+
- name: Upload Release Asset
91+
uses: softprops/action-gh-release@v1
92+
with:
93+
files: linktransfer-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.extension }}

.github/workflows/ci.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: CI
2+
3+
"on":
4+
workflow_dispatch:
5+
push:
6+
paths-ignore:
7+
- "*.md"
8+
merge_group:
9+
types: [checks_requested]
10+
pull_request:
11+
types: [review_requested]
12+
paths-ignore:
13+
- "*.md"
14+
15+
jobs:
16+
tests:
17+
name: Run Tests
18+
runs-on: ${{ matrix.os }}
19+
strategy:
20+
matrix:
21+
include:
22+
- os: ubuntu-latest
23+
go-version: '1.24'
24+
- os: ubuntu-latest
25+
go-version: '1.24'
26+
- os: macos-latest
27+
go-version: '1.24'
28+
- os: windows-latest
29+
go-version: '1.24'
30+
fail-fast: false
31+
32+
steps:
33+
- uses: actions/checkout@v4
34+
35+
- name: Setup Go
36+
uses: actions/setup-go@v4
37+
with:
38+
go-version: ${{ matrix.go-version }}
39+
40+
- name: Install dependencies
41+
run: go mod download
42+
43+
- name: Run tests
44+
run: go test -v -race -coverprofile="coverage.txt" -covermode=atomic -coverpkg="./internal/linktransfer" "./internal/linktransfer/..."
45+
46+
- name: Upload coverage to Codecov
47+
uses: codecov/codecov-action@v4
48+
if: ${{ !startsWith(github.head_ref, 'dependabot/') && !startsWith(github.ref, 'refs/heads/dependabot/') }}
49+
with:
50+
token: ${{ secrets.CODECOV_TOKEN }}
51+
file: ./coverage.txt
52+
fail_ci_if_error: true

.github/workflows/create-draft.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Create Draft Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
create-draft:
13+
name: Create Draft Release
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Get tag info
23+
id: tag_info
24+
run: |
25+
TAG_NAME=${GITHUB_REF#refs/tags/}
26+
echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
27+
echo "version=${TAG_NAME#v}" >> $GITHUB_OUTPUT
28+
29+
- name: Generate changelog
30+
id: changelog
31+
run: |
32+
# Get the previous tag
33+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
34+
35+
if [ -n "$PREV_TAG" ]; then
36+
echo "Getting changes since $PREV_TAG"
37+
CHANGELOG=$(git log --pretty=format:"- %s (%h)" $PREV_TAG..HEAD)
38+
else
39+
echo "Getting all commits"
40+
CHANGELOG=$(git log --pretty=format:"- %s (%h)")
41+
fi
42+
43+
# Save changelog to file
44+
cat << EOF > changelog.md
45+
## What's Changed
46+
47+
$CHANGELOG
48+
EOF
49+
50+
# Output for use in release
51+
{
52+
echo 'CHANGELOG<<EOF'
53+
cat changelog.md
54+
echo EOF
55+
} >> $GITHUB_OUTPUT
56+
57+
- name: Create Draft Release
58+
uses: softprops/action-gh-release@v1
59+
with:
60+
tag_name: ${{ steps.tag_info.outputs.tag_name }}
61+
name: Release ${{ steps.tag_info.outputs.tag_name }}
62+
body: ${{ steps.changelog.outputs.CHANGELOG }}
63+
draft: true
64+
prerelease: false
65+
generate_release_notes: true

.github/workflows/docker.yml

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
name: Docker Image Publish
2+
3+
on:
4+
workflow_dispatch:
5+
release:
6+
types: [released]
7+
8+
env:
9+
REGISTRY_IMAGE: jackzzs/linktransfer
10+
11+
permissions:
12+
contents: read
13+
packages: write
14+
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.ref }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
docker-build:
21+
runs-on: ubuntu-latest
22+
strategy:
23+
fail-fast: false
24+
matrix:
25+
platform:
26+
- linux/amd64
27+
- linux/arm64
28+
steps:
29+
- name: Prepare
30+
run: |
31+
platform=${{ matrix.platform }}
32+
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
33+
- name: Checkout
34+
uses: actions/checkout@v4
35+
- name: Set up QEMU
36+
uses: docker/setup-qemu-action@v3
37+
- name: Set up Docker Buildx
38+
uses: docker/setup-buildx-action@v3
39+
- name: Docker meta
40+
id: meta
41+
uses: docker/metadata-action@v5
42+
with:
43+
images: |
44+
${{ env.REGISTRY_IMAGE }}
45+
ghcr.io/${{ github.repository_owner }}/linktransfer
46+
- name: Build and cache by digest
47+
uses: docker/build-push-action@v5
48+
with:
49+
context: .
50+
platforms: ${{ matrix.platform }}
51+
labels: ${{ steps.meta.outputs.labels }}
52+
outputs: type=image,"name=${{ env.REGISTRY_IMAGE }}",push-by-digest=true,name-canonical=true,push=false
53+
cache-to: type=gha,mode=max
54+
- name: Login to Docker Hub
55+
uses: docker/login-action@v3
56+
with:
57+
username: ${{ secrets.DOCKERHUB_USERNAME }}
58+
password: ${{ secrets.DOCKERHUB_TOKEN }}
59+
- name: Login to GitHub Container Registry
60+
uses: docker/login-action@v3
61+
with:
62+
registry: ghcr.io
63+
username: ${{ github.repository_owner }}
64+
password: ${{ secrets.GITHUB_TOKEN }}
65+
- name: Push by digest
66+
id: build
67+
uses: docker/build-push-action@v5
68+
with:
69+
context: .
70+
platforms: ${{ matrix.platform }}
71+
labels: ${{ steps.meta.outputs.labels }}
72+
cache-from: type=gha
73+
outputs: type=image,"name=${{ env.REGISTRY_IMAGE }}",push-by-digest=true,name-canonical=true,push=true
74+
- name: Export digest
75+
run: |
76+
mkdir -p /tmp/digests
77+
digest="${{ steps.build.outputs.digest }}"
78+
touch "/tmp/digests/${digest#sha256:}"
79+
- name: Upload digest
80+
uses: actions/upload-artifact@v4
81+
with:
82+
name: digests-${{ env.PLATFORM_PAIR }}
83+
path: /tmp/digests/*
84+
if-no-files-found: error
85+
retention-days: 1
86+
87+
docker-merge:
88+
runs-on: ubuntu-latest
89+
needs:
90+
- docker-build
91+
steps:
92+
- name: Download digests
93+
uses: actions/download-artifact@v4
94+
with:
95+
pattern: digests-*
96+
path: /tmp/digests
97+
merge-multiple: true
98+
- name: Set up Docker Buildx
99+
uses: docker/setup-buildx-action@v3
100+
- name: Docker meta
101+
id: meta
102+
uses: docker/metadata-action@v5
103+
with:
104+
images: |
105+
${{ env.REGISTRY_IMAGE }}
106+
ghcr.io/${{ github.repository_owner }}/linktransfer
107+
- name: Login to Docker Hub
108+
uses: docker/login-action@v3
109+
with:
110+
username: ${{ secrets.DOCKERHUB_USERNAME }}
111+
password: ${{ secrets.DOCKERHUB_TOKEN }}
112+
- name: Login to GitHub Container Registry
113+
uses: docker/login-action@v3
114+
with:
115+
registry: ghcr.io
116+
username: ${{ github.repository_owner }}
117+
password: ${{ secrets.GITHUB_TOKEN }}
118+
- name: Create manifest list and push
119+
working-directory: /tmp/digests
120+
run: |
121+
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
122+
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
123+
- name: Inspect image
124+
run: |
125+
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,31 @@ go run ./cmd/linktransfer send --help
163163
go run ./cmd/linktransfer recv --help
164164
```
165165

166+
## Release Automation
167+
168+
This repository follows the same broad release flow as the in-tree linksocks reference:
169+
170+
1. Update the version in [internal/linktransfer/version.go](internal/linktransfer/version.go) with `bump2version`.
171+
2. Push the generated version commit and `v*` tag.
172+
3. GitHub Actions creates a draft release from that tag.
173+
4. Publishing the draft release triggers binary builds and Docker image publishing.
174+
175+
Example version bump:
176+
177+
```bash
178+
python -m pip install bump2version
179+
bump2version patch
180+
git push --follow-tags
181+
```
182+
183+
Release workflows live under [.github/workflows/build.yml](.github/workflows/build.yml), [.github/workflows/create-draft.yml](.github/workflows/create-draft.yml), and [.github/workflows/docker.yml](.github/workflows/docker.yml).
184+
185+
Docker publishing expects these repository settings:
186+
187+
- `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` secrets for Docker Hub pushes.
188+
- Optional `DOCKERHUB_IMAGE` repository variable if the Docker Hub image name should differ from `${{ github.repository_owner }}/linktransfer`.
189+
- `GITHUB_TOKEN` is used for pushes to `ghcr.io/<owner>/linktransfer`.
190+
166191
## Repository Layout
167192

168193
- `cmd/linktransfer`: source entrypoint for running from the repository.

internal/linktransfer/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ func newRootCmd(ctx context.Context) *cobra.Command {
6161
cmd := &cobra.Command{
6262
Use: "lt",
6363
Short: "Transfer files between computers via linksocks tunnels",
64+
Version: Version,
6465
SilenceUsage: true,
6566
SilenceErrors: true,
6667
}

internal/linktransfer/version.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package linktransfer
2+
3+
var Version = "v0.1.0"

0 commit comments

Comments
 (0)