Skip to content

Commit 36779aa

Browse files
committed
using a go script to test update
1 parent f97fdf1 commit 36779aa

File tree

5 files changed

+312
-90
lines changed

5 files changed

+312
-90
lines changed

.github/workflows/test-update.yml

Lines changed: 4 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,11 @@ on:
1010
permissions:
1111
contents: read
1212

13+
1314
jobs:
1415
build-and-update:
1516
runs-on: ubuntu-22.04
1617

17-
env:
18-
TAG_VERSION: "v0.6.7"
19-
ARCH: amd64
20-
APPCLI_REPO: arduino/arduino-app-cli
21-
ROUTER_REPO: arduino/arduino-router
22-
23-
APPCLI_TAG: ""
24-
APPCLI_REGEX: "amd64\\.deb$"
25-
26-
ROUTER_TAG: ""
27-
ROUTER_REGEX: "amd64\\.deb$"
28-
2918
steps:
3019
- name: Checkout
3120
uses: actions/checkout@v4
@@ -35,81 +24,8 @@ jobs:
3524
with:
3625
go-version-file: go.mod
3726

38-
- name: Build deb
39-
run: |
40-
go tool task build-deb VERSION=${TAG_VERSION} ARCH=${ARCH}
41-
42-
- name: Fetch .debs dynamically into build/stable
27+
- name: Run dep package update test
4328
env:
44-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
45-
run: |
46-
set -euo pipefail
47-
mkdir -p build/stable
48-
49-
fetch_deb () {
50-
local repo="$1" tag="${2:-}" regex="$3"
51-
52-
echo "==> Resolving release for ${repo} (tag='${tag:-<latest>}')"
53-
if [ -n "${tag}" ]; then
54-
url="https://api.github.com/repos/${repo}/releases/tags/${tag}"
55-
else
56-
url="https://api.github.com/repos/${repo}/releases/latest"
57-
fi
58-
59-
rel="$(curl -sfL -H "Authorization: token ${GH_TOKEN}" -H "Accept: application/vnd.github+json" "${url}")"
60-
61-
name="$(echo "$rel" | jq -r --arg re "${regex}" '.assets[] | select(.name | test($re)) | .name' | head -n1)"
62-
dl="$(echo "$rel" | jq -r --arg re "${regex}" '.assets[] | select(.name | test($re)) | .browser_download_url' | head -n1)"
63-
64-
if [ -z "${name}" ] || [ "${name}" = "null" ] || [ -z "${dl}" ] || [ "${dl}" = "null" ]; then
65-
echo "!! No asset found in ${repo} matching regex: ${regex}"
66-
echo " Available assets:"
67-
echo "$rel" | jq -r '.assets[].name'
68-
exit 1
69-
fi
70-
71-
echo "Found: ${name}"
72-
echo "Downloading: ${dl}"
73-
74-
curl -sfL -H "Authorization: token ${GH_TOKEN}" \
75-
-o "build/stable/${name}" \
76-
"${dl}"
77-
78-
ls -lh "build/stable/${name}"
79-
}
80-
81-
fetch_deb "${APPCLI_REPO}" "${APPCLI_TAG}" "${APPCLI_REGEX}"
82-
fetch_deb "${ROUTER_REPO}" "${ROUTER_TAG}" "${ROUTER_REGEX}"
83-
84-
echo "✅ Downloaded files:"
85-
ls -lh build/stable/
86-
ls -lh build/
87-
88-
- name: Build Docker image (no cache)
89-
run: |
90-
docker build -t mock-apt-repo -f test.Dockerfile .
91-
92-
- name: Run mock-apt-repo container
93-
run: |
94-
docker run --rm -d \
95-
--privileged \
96-
--cgroupns=host \
97-
-v /sys/fs/cgroup:/sys/fs/cgroup:rw \
98-
-v /var/run/docker.sock:/var/run/docker.sock \
99-
-e DOCKER_HOST=unix:///var/run/docker.sock \
100-
--name apt-test-update \
101-
mock-apt-repo
102-
103-
- name: Run arduino-app-cli current version
104-
run: |
105-
docker exec --user arduino apt-test-update arduino-app-cli version
106-
107-
- name: Run arduino-app-cli with auto-yes (as arduino)
108-
run: |
109-
mkdir -p artifacts
110-
docker exec apt-test-update sh -lc 'su - arduino -c "yes | arduino-app-cli system update"' \
111-
| tee artifacts/arduino-system-update.log
112-
113-
- name: Run arduino-app-cli version updated
29+
GH_TOKEN: ${{ secrets.ARDUINOBOT_TOKEN }}
11430
run: |
115-
docker exec --user arduino apt-test-update arduino-app-cli version<
31+
go test -v ./internal/testtools/deb_test.go --arch amd64

Taskfile.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,10 @@ tasks:
105105
deps:
106106
- build-deb:clone-examples
107107
cmds:
108-
- docker build --build-arg BINARY_NAME=arduino-app-cli --build-arg DEB_NAME=arduino-app-cli --build-arg VERSION={{ .VERSION }} --build-arg ARCH={{ .ARCH }} --build-arg RELEASE={{ .RELEASE }} --output=./build -f debian/Dockerfile .
108+
- docker build --build-arg BINARY_NAME=arduino-app-cli --build-arg DEB_NAME=arduino-app-cli --build-arg VERSION={{ .VERSION }} --build-arg ARCH={{ .ARCH }} --build-arg RELEASE={{ .RELEASE }} --output={{ .OUTPUT }} -f debian/Dockerfile .
109109
vars:
110110
ARCH: '{{.ARCH | default "arm64"}}'
111+
OUTéPUT: '{{.OUTPUT | default "./build"}}'
111112

112113
build-deb:clone-examples:
113114
desc: "Clones the examples repo directly into the debian structure"

internal/testtools/deb_test.go

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
package testtools
2+
3+
import (
4+
"bytes"
5+
"flag"
6+
"fmt"
7+
"io"
8+
"log"
9+
"os"
10+
"os/exec"
11+
"path/filepath"
12+
"strconv"
13+
"strings"
14+
"testing"
15+
16+
"github.com/stretchr/testify/require"
17+
)
18+
19+
var arch = flag.String("arch", "amd64", "target architecture")
20+
21+
func TestStableToUnstable(t *testing.T) {
22+
fmt.Printf("***** ARCH %s *****", *arch)
23+
tagAppCli := FetchDebPackage(t, "arduino-app-cli", "latest", *arch)
24+
FetchDebPackage(t, "arduino-router", "latest", *arch)
25+
majorTag := majorTag(t, tagAppCli)
26+
_ = minorTag(t, tagAppCli)
27+
28+
fmt.Printf("Updating from stable version %s to unstable version %s \n", tagAppCli, majorTag)
29+
fmt.Printf("Building local deb version %s \n", majorTag)
30+
buildDebVersion(t, majorTag, *arch)
31+
32+
fmt.Println("**** BUILD docker image *****")
33+
buildDockerImage(t, "test.Dockerfile", "test-apt-update")
34+
fmt.Println("**** RUN docker image *****")
35+
runDockerCommand(t, "test-apt-update")
36+
preUpdateVersion := runDockerSystemVersion(t, "apt-test-update")
37+
runDockerSystemUpdate(t, "apt-test-update")
38+
postUpdateVersion := runDockerSystemVersion(t, "apt-test-update")
39+
runDockerCleanUp(t, "apt-test-update")
40+
require.Equal(t, preUpdateVersion, "Arduino App CLI "+tagAppCli)
41+
require.Equal(t, postUpdateVersion, "Arduino App CLI "+majorTag)
42+
43+
}
44+
45+
// func TestUnstableToStable(t *testing.T) {
46+
// tagAppCli := FetchDebPackage(t, "arduino-app-cli", "latest", *arch)
47+
// FetchDebPackage(t, "arduino-router", "latest", *arch)
48+
// minorTag := minorTag(t, tagAppCli)
49+
// moveDeb(t, "build/stable", "build/", "arduino-app-cli", tagAppCli, *arch)
50+
51+
// fmt.Printf("Updating from unstable version %s to stable version %s \n", minorTag, tagAppCli)
52+
// fmt.Printf("Building local deb version %s \n", minorTag)
53+
// buildDebVersion(t, minorTag, *arch)
54+
// moveDeb(t, "build/", "build/stable", "arduino-app-cli", tagAppCli, *arch)
55+
56+
// fmt.Println("**** BUILD docker image *****")
57+
// buildDockerImage(t, "test.Dockerfile", "test-apt-update")
58+
// fmt.Println("**** RUN docker image *****")
59+
// runDockerCommand(t, "test-apt-update")
60+
// preUpdateVersion := runDockerSystemVersion(t, "apt-test-update")
61+
// runDockerSystemUpdate(t, "apt-test-update")
62+
// postUpdateVersion := runDockerSystemVersion(t, "apt-test-update")
63+
// runDockerCleanUp(t, "apt-test-update")
64+
// require.Equal(t, preUpdateVersion, "Arduino App CLI "+tagAppCli)
65+
// require.Equal(t, postUpdateVersion, "Arduino App CLI "+minorTag)
66+
67+
// }
68+
69+
func FetchDebPackage(t *testing.T, repo, version, arch string) string {
70+
t.Helper()
71+
72+
cmd := exec.Command(
73+
"gh", "release", "list",
74+
"--repo", "github.com/arduino/"+repo,
75+
"--exclude-pre-releases",
76+
"--limit", "1",
77+
)
78+
79+
output, err := cmd.CombinedOutput()
80+
if err != nil {
81+
log.Fatalf("command failed: %v\nOutput: %s", err, output)
82+
}
83+
84+
fmt.Println(string(output))
85+
86+
fields := strings.Fields(string(output))
87+
if len(fields) == 0 {
88+
log.Fatal("could not parse tag from gh release list output")
89+
}
90+
tag := fields[0]
91+
tagPath := strings.TrimPrefix(tag, "v")
92+
93+
debFile := fmt.Sprintf("build/stable/%s_%s-1_%s.deb", repo, tagPath, arch)
94+
fmt.Println(debFile)
95+
if _, err := os.Stat(debFile); err == nil {
96+
fmt.Printf("✅ %s already exists, skipping download.\n", debFile)
97+
return tag
98+
}
99+
fmt.Println("Detected tag:", tag)
100+
cmd2 := exec.Command(
101+
"gh", "release", "download",
102+
tag,
103+
"--repo", "github.com/arduino/"+repo,
104+
"--pattern", "*",
105+
"--dir", "./build/stable",
106+
)
107+
108+
out, err := cmd2.CombinedOutput()
109+
if err != nil {
110+
log.Fatalf("download failed: %v\nOutput: %s", err, out)
111+
}
112+
113+
return tag
114+
115+
}
116+
117+
func buildDebVersion(t *testing.T, tagVersion, arch string) {
118+
t.Helper()
119+
cwd, err := os.Getwd()
120+
if err != nil {
121+
panic(err)
122+
}
123+
outputDir := filepath.Join(cwd, "build")
124+
125+
cmd := exec.Command(
126+
"go", "tool", "task", "build-deb",
127+
fmt.Sprintf("VERSION=%s", tagVersion),
128+
fmt.Sprintf("ARCH=%s", arch),
129+
fmt.Sprintf("OUTPUT=%s", outputDir),
130+
)
131+
132+
if err := cmd.Run(); err != nil {
133+
log.Fatalf("failed to run build command: %v", err)
134+
}
135+
}
136+
137+
func majorTag(t *testing.T, tag string) string {
138+
t.Helper()
139+
140+
parts := strings.Split(tag, ".")
141+
last := parts[len(parts)-1]
142+
143+
// Remove potential prefix 'v' from the first part, but not from the patch
144+
lastNum, _ := strconv.Atoi(strings.TrimPrefix(last, "v"))
145+
lastNum++
146+
147+
parts[len(parts)-1] = strconv.Itoa(lastNum)
148+
newTag := strings.Join(parts, ".")
149+
150+
return newTag
151+
}
152+
153+
func minorTag(t *testing.T, tag string) string {
154+
t.Helper()
155+
156+
parts := strings.Split(tag, ".")
157+
last := parts[len(parts)-1]
158+
159+
lastNum, _ := strconv.Atoi(strings.TrimPrefix(last, "v"))
160+
if lastNum > 0 {
161+
lastNum--
162+
}
163+
164+
parts[len(parts)-1] = strconv.Itoa(lastNum)
165+
newTag := strings.Join(parts, ".")
166+
167+
if !strings.HasPrefix(newTag, "v") {
168+
newTag = "v" + newTag
169+
}
170+
return newTag
171+
}
172+
173+
func buildDockerImage(t *testing.T, dockerfile, name string) {
174+
t.Helper()
175+
176+
cmd := exec.Command("docker", "build", "-t", name, "-f", dockerfile, ".")
177+
out, err := cmd.CombinedOutput()
178+
if err != nil {
179+
t.Fatalf("docker build failed: %v\nOutput:\n%s", err, string(out))
180+
}
181+
182+
}
183+
184+
func runDockerCommand(t *testing.T, containerImageName string) {
185+
t.Helper()
186+
187+
cmd := exec.Command(
188+
"docker", "run", "--rm", "-d",
189+
"--privileged",
190+
"--cgroupns=host",
191+
"-v", "/sys/fs/cgroup:/sys/fs/cgroup:rw",
192+
"-v", "/var/run/docker.sock:/var/run/docker.sock",
193+
"-e", "DOCKER_HOST=unix:///var/run/docker.sock",
194+
"--name", "apt-test-update",
195+
containerImageName,
196+
)
197+
198+
if err := cmd.Run(); err != nil {
199+
t.Fatalf("failed to run container: %v", err)
200+
}
201+
202+
}
203+
204+
func runDockerSystemVersion(t *testing.T, containerName string) string {
205+
t.Helper()
206+
207+
cmd := exec.Command(
208+
"docker", "exec",
209+
"--user", "arduino",
210+
containerName,
211+
"arduino-app-cli", "version",
212+
)
213+
214+
output, err := cmd.CombinedOutput()
215+
if err != nil {
216+
log.Fatalf("command failed: %v\nOutput: %s", err, output)
217+
}
218+
219+
return string(output)
220+
221+
}
222+
223+
func runDockerSystemUpdate(t *testing.T, containerName string) {
224+
t.Helper()
225+
var buf bytes.Buffer
226+
227+
cmd := exec.Command(
228+
"docker", "exec",
229+
containerName,
230+
"sh", "-lc",
231+
`su - arduino -c "yes | arduino-app-cli system update"`,
232+
)
233+
234+
cmd.Stdout = io.MultiWriter(os.Stdout, &buf)
235+
236+
if err := cmd.Run(); err != nil {
237+
fmt.Fprintf(os.Stderr, "Error running system update: %v\n", err)
238+
os.Exit(1)
239+
}
240+
241+
}
242+
243+
func runDockerCleanUp(t *testing.T, containerName string) {
244+
t.Helper()
245+
246+
cleanupCmd := exec.Command("docker", "rm", "-f", containerName)
247+
248+
fmt.Println("🧹 Removing Docker container " + containerName)
249+
if err := cleanupCmd.Run(); err != nil {
250+
fmt.Printf("⚠️ Warning: could not remove container (might not exist): %v\n", err)
251+
}
252+
253+
}
254+
255+
func moveDeb(t *testing.T, startDir, targetDir, repo string, tagVersion string, arch string) {
256+
t.Helper()
257+
tagPath := strings.TrimPrefix(tagVersion, "v")
258+
259+
debFile := fmt.Sprintf("%s/%s_%s-1_%s.deb", startDir, repo, tagPath, arch)
260+
261+
moveCmd := exec.Command("cp", debFile, targetDir)
262+
263+
fmt.Printf("📦 Moving %s → %s\n", debFile, targetDir)
264+
if err := moveCmd.Run(); err != nil {
265+
panic(fmt.Errorf("failed to move deb file: %w", err))
266+
}
267+
}

0 commit comments

Comments
 (0)