Skip to content

Commit 7fad810

Browse files
authored
ci: use GitHub actions (#765)
1 parent 81986bb commit 7fad810

File tree

8 files changed

+146
-56
lines changed

8 files changed

+146
-56
lines changed

.github/workflows/ci.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: ci
2+
3+
on: push
4+
5+
jobs:
6+
build-amd64:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Set up QEMU
10+
uses: docker/setup-qemu-action@v1
11+
- name: Set up Docker Buildx
12+
uses: docker/setup-buildx-action@v1
13+
- name: Login to DockerHub
14+
uses: docker/login-action@v1
15+
with:
16+
username: ${{ secrets.DOCKERHUB_USERNAME }}
17+
password: ${{ secrets.DOCKERHUB_TOKEN }}
18+
- name: Checkout
19+
uses: actions/checkout@v2
20+
with:
21+
fetch-depth: 0
22+
- name: Set up Python 3.9
23+
uses: actions/setup-python@v2
24+
with:
25+
python-version: '3.9'
26+
architecture: 'x64'
27+
- name: Show Python version
28+
run: python -c "import sys; print(sys.version)"
29+
- name: Build and push
30+
run: tools/push -p linux/amd64
31+
build-arm64:
32+
runs-on: ubuntu-latest
33+
steps:
34+
- name: Set up QEMU
35+
uses: docker/setup-qemu-action@v1
36+
- name: Set up Docker Buildx
37+
uses: docker/setup-buildx-action@v1
38+
- name: Login to DockerHub
39+
uses: docker/login-action@v1
40+
with:
41+
username: ${{ secrets.DOCKERHUB_USERNAME }}
42+
password: ${{ secrets.DOCKERHUB_TOKEN }}
43+
- name: Checkout
44+
uses: actions/checkout@v2
45+
with:
46+
fetch-depth: 0
47+
- name: Set up Python 3.9
48+
uses: actions/setup-python@v2
49+
with:
50+
python-version: '3.9'
51+
architecture: 'x64'
52+
- name: Show Python version
53+
run: python -c "import sys; print(sys.version)"
54+
- name: Build and push
55+
run: tools/push -p linux/arm64

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The following instructions are geared towards developers, intending to contribut
1111

1212
### Prerequisites
1313

14-
Python 3.8 (or higher)
14+
Python 3.7 (or higher)
1515

1616
### Initial setup
1717

tools/build

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
#!/bin/bash
22

3-
python $(dirname "$0")/helper.py build "$@"
3+
set -euo pipefail
4+
5+
cd "$(dirname "$0")" || exit 1
6+
7+
python3 helper.py build "$@"

tools/core/docker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING, Dict, Optional, List, Literal, Union
3+
from typing import TYPE_CHECKING, Dict, Optional, List, Union
44

55
import json
66
from urllib.request import urlopen, Request
@@ -17,7 +17,7 @@
1717
from http.client import HTTPResponse
1818

1919

20-
SupportedPlatform = Literal["linux/arm64", "linux/amd64", "linux/386", "linux/ppc64le", "linux/s390s", "linux/arm/v7", "linux/arm/v6"]
20+
# SupportedPlatform = Literal["linux/arm64", "linux/amd64", "linux/386", "linux/ppc64le", "linux/s390s", "linux/arm/v7", "linux/arm/v6"]
2121

2222

2323
class Platform:

tools/core/image.py

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -138,26 +138,29 @@ def repo(self) -> Optional[str]:
138138
return repo
139139

140140
def _run_command(self, cmd):
141+
on_travis = "TRAVIS_BRANCH" in os.environ
142+
if on_travis:
143+
self._run_command_on_travis(cmd)
144+
return
145+
print("\033[34m$ %s\033[0m" % cmd, flush=True)
146+
exit_code = os.system(cmd)
147+
if exit_code != 0:
148+
raise RuntimeError("Failed to build (exit_code=%s)" % exit_code)
149+
150+
def _run_command_on_travis(self, cmd):
141151
self._logger.info(cmd)
142152

143153
stop = threading.Event()
144154

145155
def f():
146156
nonlocal stop
147157
counter = 0
148-
on_travis = "TRAVIS_BRANCH" in os.environ
158+
149159
while not stop.is_set():
150160
counter = counter + 1
161+
print("Still building... ({})".format(counter), flush=True)
162+
stop.wait(10)
151163

152-
if on_travis:
153-
print("Still building... ({})".format(counter), flush=True)
154-
stop.wait(10)
155-
continue
156-
157-
print(".", end="", flush=True)
158-
stop.wait(1)
159-
if not on_travis:
160-
print()
161164
threading.Thread(target=f).start()
162165
try:
163166
output = execute(cmd)
@@ -183,8 +186,14 @@ def _buildx_build(self, args: List[str], build_dir: str, build_tag: str, platfor
183186
self._run_command(cmd)
184187

185188
def build(self, platform: Platform, no_cache: bool) -> None:
186-
self._logger.info("Build %s:%s (%s)", self.name, self.tag, platform.tag_suffix)
187-
print("Build %s:%s (%s)" % (self.name, self.tag, platform.tag_suffix))
189+
self._logger.info("Building %s:%s (%s)", self.name, self.tag, platform.tag_suffix)
190+
191+
print()
192+
print("=" * 80)
193+
print("Building %s:%s (%s)" % (self.name, self.tag, platform.tag_suffix))
194+
print("=" * 80)
195+
196+
sys.stdout.flush()
188197

189198
source_manager = self.prepare()
190199

@@ -257,18 +266,25 @@ def push(self, platform: Platform, no_cache: bool = False, dirty_push: bool = Fa
257266

258267
tag = self.get_build_tag(self.branch, platform)
259268

260-
print("Push {}".format(tag))
269+
print()
270+
print("=" * 80)
271+
print("Pushing {}".format(tag))
272+
print("=" * 80)
273+
274+
sys.stdout.flush()
261275

262276
cmd = "docker push {}".format(tag)
277+
print("\033[34m$ %s\033[0m" % cmd, flush=True)
263278
output = execute(cmd)
264-
self._logger.debug("$ %s\n%s", cmd, output)
279+
print("%s" % output.rstrip(), flush=True)
265280
last_line = output.splitlines()[-1]
266281
p = re.compile(r"^(.*): digest: (.*) size: (\d+)$")
267282
m = p.match(last_line)
268283
assert m
269284
assert m.group(1) in tag
270285

271286
new_manifest = "{}/{}@{}".format(self.group, self.name, m.group(2))
287+
print("New manifest: %s" % new_manifest, flush=True)
272288

273289
# append to manifest list
274290
os.environ["DOCKER_CLI_EXPERIMENTAL"] = "enabled"
@@ -284,22 +300,28 @@ def push(self, platform: Platform, no_cache: bool = False, dirty_push: bool = Fa
284300
tags.append("{}@{}".format(repo, m.digest))
285301
tags = " ".join(tags)
286302
cmd = f"docker manifest create {t0} {new_manifest}"
303+
287304
if len(tags) > 0:
288305
cmd += " " + tags
289-
output = execute(cmd)
290-
self._logger.debug("$ %s\n%s", cmd, output)
306+
print("\033[34m$ %s\033[0m" % cmd, flush=True)
307+
if os.system(cmd) != 0:
308+
raise Exception("Failed to create manifest")
291309

292310
cmd = f"docker manifest push -p {t0}"
293-
output = execute(cmd)
294-
self._logger.debug("$ %s\n%s", cmd, output)
311+
print("\033[34m$ %s\033[0m" % cmd, flush=True)
312+
if os.system(cmd) != 0:
313+
raise Exception("Failed to push manifest")
314+
295315
else:
296316
cmd = f"docker manifest create {t0} {new_manifest}"
297-
output = execute(cmd)
298-
self._logger.debug("$ %s\n%s", cmd, output)
317+
print("\033[34m$ %s\033[0m" % cmd, flush=True)
318+
if os.system(cmd) != 0:
319+
raise Exception("Failed to create manifest")
299320

300321
cmd = f"docker manifest push -p {t0}"
301-
output = execute(cmd)
302-
self._logger.debug("$ %s\n%s", cmd, output)
322+
print("\033[34m$ %s\033[0m" % cmd, flush=True)
323+
if os.system(cmd) != 0:
324+
raise Exception("Failed to push manifest")
303325

304326
def __repr__(self):
305327
return "<Image name=%r tag=%r branch=%r>" % (self.name, self.tag, self.branch)

tools/core/toolkit.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import sys
44
from datetime import datetime
55
from typing import Optional, List
6-
from subprocess import CalledProcessError
6+
from subprocess import CalledProcessError, check_output
7+
import re
78

89
from .docker import DockerTemplate, Platform, Platforms
910
from .git import GitTemplate
@@ -111,6 +112,22 @@ def _create_context(self, dry_run: bool, platforms: List[Platform]):
111112
current_platform=self.current_platform,
112113
)
113114

115+
def _get_modified_images(self) -> List[str]:
116+
cmd = "git diff --name-only $(git merge-base --fork-point origin/master)..HEAD images"
117+
print("\033[34m$ %s" % cmd, flush=True)
118+
output = check_output(cmd, shell=True)
119+
output = output.decode()
120+
print("%s" % output.rstrip(), flush=True)
121+
lines = output.splitlines()
122+
p = re.compile(r"^images/(.+)/.*$")
123+
images = set()
124+
for line in lines:
125+
m = p.match(line)
126+
assert m, "mismatch line (%r): %s" % (p, line)
127+
image = m.group(1)
128+
images.add(image)
129+
return list(images)
130+
114131
def build(self,
115132
images: List[str] = None,
116133
dry_run: bool = False,
@@ -125,12 +142,15 @@ def build(self,
125142

126143
ctx = self._create_context(dry_run, platforms)
127144

128-
if images:
129-
for i, name in enumerate(images):
130-
if i > 0:
131-
print()
132-
for p in platforms:
133-
Image(ctx, name).build(platform=p, no_cache=no_cache)
145+
if not images:
146+
images = self._get_modified_images()
147+
148+
for i, name in enumerate(images):
149+
if i > 0:
150+
print()
151+
for p in platforms:
152+
Image(ctx, name).build(platform=p, no_cache=no_cache)
153+
134154
except Exception as e:
135155
p = e
136156
while p:
@@ -156,12 +176,15 @@ def push(self,
156176

157177
ctx = self._create_context(dry_run, platforms)
158178

159-
if images:
160-
for i, name in enumerate(images):
161-
if i > 0:
162-
print()
163-
for p in platforms:
164-
Image(ctx, name).push(platform=p, no_cache=no_cache, dirty_push=dirty_push)
179+
if not images:
180+
images = self._get_modified_images()
181+
182+
for i, name in enumerate(images):
183+
if i > 0:
184+
print()
185+
for p in platforms:
186+
Image(ctx, name).push(platform=p, no_cache=no_cache, dirty_push=dirty_push)
187+
165188
except Exception as e:
166189
p = e
167190
while p:
@@ -172,7 +195,6 @@ def push(self,
172195
p = e.__cause__
173196
raise
174197

175-
176198
def test(self):
177199
os.chdir(self.project_dir)
178200
sys.exit(os.system("python3.8 -m pytest -s"))

tools/helper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ def main():
1313
build_parser = subparsers.add_parser("build", prog="build")
1414
build_parser.add_argument("--dry-run", action="store_true")
1515
build_parser.add_argument("--no-cache", action="store_true")
16-
build_parser.add_argument("--platform", action="append")
16+
build_parser.add_argument("--platform", "-p", action="append")
1717
build_parser.add_argument("images", type=str, nargs="*")
1818

1919
push_parser = subparsers.add_parser("push")
2020
push_parser.add_argument("--dirty-push", action="store_true")
2121
push_parser.add_argument("--dry-run", action="store_true")
2222
push_parser.add_argument("--no-cache", action="store_true")
23-
push_parser.add_argument("--platform", action="append")
23+
push_parser.add_argument("--platform", "-p", action="append")
2424
push_parser.add_argument("images", type=str, nargs="*")
2525

2626
subparsers.add_parser("test")

tools/push

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,6 @@
11
#!/bin/bash
22

3-
set -m
43
set -euo pipefail
5-
set -x
6-
7-
function print_running() {
8-
while true; do
9-
echo ">>> RUNNING <<<"
10-
sleep 3
11-
done
12-
}
13-
14-
if [[ $(uname -m) == "aarch64" ]]; then
15-
print_running &
16-
fi
174

185
cd "$(dirname "$0")" || exit 1
19-
python helper.py push "$@"
6+
python3 helper.py push "$@"

0 commit comments

Comments
 (0)