Skip to content

Commit 25c042b

Browse files
ci: add cross-platform E2E tests, SBOMs, Cosign, and GHCR Docker release
Signed-off-by: night-slayer18 <samanuaia257@gmail.com>
1 parent 801b948 commit 25c042b

File tree

4 files changed

+154
-1
lines changed

4 files changed

+154
-1
lines changed

.github/workflows/release.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ jobs:
1414
release:
1515
name: GoReleaser
1616
runs-on: ubuntu-latest
17+
permissions:
18+
contents: write
19+
packages: write
20+
id-token: write
1721
steps:
1822
- name: Checkout
1923
uses: actions/checkout@v4
@@ -26,6 +30,25 @@ jobs:
2630
go-version-file: go.mod
2731
cache-dependency-path: go.sum
2832

33+
- name: Install syft
34+
uses: anchore/sbom-action/download-syft@v0.20.10
35+
36+
- name: Set up QEMU
37+
uses: docker/setup-qemu-action@v3
38+
39+
- name: Set up Docker Buildx
40+
uses: docker/setup-buildx-action@v3
41+
42+
- name: Install cosign
43+
uses: sigstore/cosign-installer@v3.4.0
44+
45+
- name: Login to ghcr.io registry
46+
uses: docker/login-action@v3
47+
with:
48+
registry: ghcr.io
49+
username: ${{ github.actor }}
50+
password: ${{ secrets.GITHUB_TOKEN }}
51+
2952
- name: Run GoReleaser
3053
uses: goreleaser/goreleaser-action@v6
3154
with:

.goreleaser.yml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ nfpms:
5959
- archlinux
6060
bindir: /usr/bin
6161

62-
brews:
62+
homebrews:
6363
- repository:
6464
owner: OpenSyntaxHQ
6565
name: homebrew-tweak
@@ -72,3 +72,29 @@ brews:
7272
bin.install "tweak"
7373
test: |
7474
system "#{bin}/tweak --version"
75+
76+
dockers_v2:
77+
- image_templates:
78+
- "ghcr.io/opensyntaxhq/tweak:{{ .Version }}"
79+
- "ghcr.io/opensyntaxhq/tweak:latest"
80+
build_flag_templates:
81+
- "--pull"
82+
- "--label=org.opencontainers.image.created={{.Date}}"
83+
- "--label=org.opencontainers.image.title={{.ProjectName}}"
84+
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
85+
- "--label=org.opencontainers.image.version={{.Version}}"
86+
87+
sboms:
88+
- artifacts: archive
89+
90+
signs:
91+
- cmd: cosign
92+
env:
93+
- COSIGN_EXPERIMENTAL=1
94+
args:
95+
- "sign-blob"
96+
- "--yes"
97+
- "--output-signature=${signature}"
98+
- "--output-certificate=${certificate}"
99+
- "${artifact}"
100+
artifacts: checksum

Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM scratch
2+
ENTRYPOINT ["/tweak"]
3+
COPY tweak /

tests/e2e_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package tests
2+
3+
import (
4+
"bytes"
5+
"os"
6+
"os/exec"
7+
"path/filepath"
8+
"runtime"
9+
"strings"
10+
"testing"
11+
)
12+
13+
func TestE2E(t *testing.T) {
14+
binaryName := "tweak_e2e"
15+
if runtime.GOOS == "windows" {
16+
binaryName += ".exe"
17+
}
18+
19+
buildCmd := exec.Command("go", "build", "-o", binaryName, "../main.go")
20+
if err := buildCmd.Run(); err != nil {
21+
t.Fatalf("Failed to build binary for E2E tests: %v", err)
22+
}
23+
defer os.Remove(binaryName)
24+
25+
binaryPath, err := filepath.Abs(binaryName)
26+
if err != nil {
27+
t.Fatalf("Failed to get absolute path for binary: %v", err)
28+
}
29+
30+
tests := []struct {
31+
name string
32+
args []string
33+
stdin string
34+
expectedOutput string
35+
expectError bool
36+
}{
37+
{
38+
name: "Base64 Encoding from Args",
39+
args: []string{"base64-encode", "hello world"},
40+
expectedOutput: "aGVsbG8gd29ybGQ=",
41+
},
42+
{
43+
name: "Base64 Decoding from Stdin (Piping)",
44+
args: []string{"base64-decode"},
45+
stdin: "aGVsbG8gd29ybGQ=",
46+
expectedOutput: "hello world",
47+
},
48+
{
49+
name: "MD5 Hash (Arg with spaces)",
50+
args: []string{"md5", "tweak test"},
51+
expectedOutput: "4b284490e3437e4d4a48c09edb0040a0",
52+
},
53+
{
54+
name: "Uppercase transform",
55+
args: []string{"upper", "make me loud"},
56+
expectedOutput: "MAKE ME LOUD",
57+
},
58+
{
59+
name: "Invalid Command Error",
60+
args: []string{"fake-command-123"},
61+
expectError: true,
62+
},
63+
}
64+
65+
for _, tt := range tests {
66+
t.Run(tt.name, func(t *testing.T) {
67+
cmd := exec.Command(binaryPath, tt.args...)
68+
69+
// Set up stdin if provided (simulates bash/CMD piping: echo | tweak)
70+
if tt.stdin != "" {
71+
cmd.Stdin = strings.NewReader(tt.stdin)
72+
}
73+
74+
var stdout bytes.Buffer
75+
var stderr bytes.Buffer
76+
cmd.Stdout = &stdout
77+
cmd.Stderr = &stderr
78+
79+
err := cmd.Run()
80+
81+
if tt.expectError {
82+
if err == nil {
83+
t.Fatalf("Expected error but command succeeded. output: %s", stdout.String())
84+
}
85+
return
86+
}
87+
88+
if err != nil {
89+
t.Fatalf("Command failed: %v\nStderr: %s", err, stderr.String())
90+
}
91+
92+
// Clean up output (CRLF to LF for cross-platform comparison)
93+
got := strings.TrimSpace(stdout.String())
94+
got = strings.ReplaceAll(got, "\r\n", "\n")
95+
96+
if got != tt.expectedOutput {
97+
t.Errorf("\nGot: %q\nExpected: %q", got, tt.expectedOutput)
98+
}
99+
})
100+
}
101+
}

0 commit comments

Comments
 (0)