Skip to content

Commit c74be66

Browse files
authored
Merge pull request #2 from infosiftr/downstream-github-actions
Add initial scripts for image maintainers to use to auto-generate appropriate GitHub Actions
2 parents eb76b2e + b22f02e commit c74be66

File tree

3 files changed

+259
-0
lines changed

3 files changed

+259
-0
lines changed

scripts/github-actions/example-ci.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: GitHub CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
schedule:
7+
- cron: 0 0 * * 0
8+
9+
defaults:
10+
run:
11+
shell: 'bash -Eeuo pipefail -x {0}'
12+
13+
jobs:
14+
15+
generate-jobs:
16+
name: Generate Jobs
17+
runs-on: ubuntu-latest
18+
outputs:
19+
strategy: ${{ steps.generate-jobs.outputs.strategy }}
20+
steps:
21+
- uses: actions/checkout@v1
22+
- id: generate-jobs
23+
name: Generate Jobs
24+
run: |
25+
git clone --depth 1 https://github.com/docker-library/bashbrew.git -b master ~/bashbrew
26+
strategy="$(~/bashbrew/scripts/github-actions/generate.sh)"
27+
jq . <<<"$strategy" # sanity check / debugging aid
28+
echo "::set-output name=strategy::$strategy"
29+
30+
test:
31+
needs: generate-jobs
32+
strategy: ${{ fromJson(needs.generate-jobs.outputs.strategy) }}
33+
name: ${{ matrix.name }}
34+
runs-on: ${{ matrix.os }}
35+
steps:
36+
- uses: actions/checkout@v1
37+
- name: Prepare Environment
38+
run: ${{ matrix.runs.prepare }}
39+
- name: Pull Dependencies
40+
run: ${{ matrix.runs.pull }}
41+
- name: Build ${{ matrix.name }}
42+
run: ${{ matrix.runs.build }}
43+
- name: History ${{ matrix.name }}
44+
run: ${{ matrix.runs.history }}
45+
- name: Test ${{ matrix.name }}
46+
run: ${{ matrix.runs.test }}
47+
- name: '"docker images"'
48+
run: ${{ matrix.runs.images }}

scripts/github-actions/generate.sh

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
#!/usr/bin/env bash
2+
set -Eeuo pipefail
3+
4+
image="${GITHUB_REPOSITORY##*/}" # "python", "golang", etc
5+
6+
[ -n "${GENERATE_STACKBREW_LIBRARY:-}" ] || [ -x ./generate-stackbrew-library.sh ] # sanity check
7+
8+
tmp="$(mktemp -d)"
9+
trap "$(printf 'rm -rf %q' "$tmp")" EXIT
10+
11+
if ! command -v bashbrew &> /dev/null; then
12+
dir="$(readlink -f "$BASH_SOURCE")"
13+
dir="$(dirname "$dir")"
14+
dir="$(cd "$dir/../.." && pwd -P)"
15+
if [ ! -x "$dir/bin/bashbrew" ]; then
16+
echo >&2 'Building bashbrew ...'
17+
"$dir/bashbrew.sh" --version > /dev/null
18+
"$dir/bin/bashbrew" --version >&2
19+
fi
20+
export PATH="$dir/bin:$PATH"
21+
bashbrew --version > /dev/null
22+
fi
23+
24+
mkdir "$tmp/library"
25+
export BASHBREW_LIBRARY="$tmp/library"
26+
27+
eval "${GENERATE_STACKBREW_LIBRARY:-./generate-stackbrew-library.sh}" > "$BASHBREW_LIBRARY/$image"
28+
29+
tags="$(bashbrew list --build-order --uniq "$image")"
30+
31+
# see https://github.com/docker-library/python/commit/6b513483afccbfe23520b1f788978913e025120a for the ideal of what this would be (minimal YAML in all 30+ repos, shared shell script that outputs fully dynamic steps list), if GitHub Actions were to support a fully dynamic steps list
32+
33+
order=()
34+
declare -A metas=()
35+
for tag in $tags; do
36+
echo >&2 "Processing $tag ..."
37+
bashbrewImage="${tag##*/}" # account for BASHBREW_NAMESPACE being set
38+
meta="$(
39+
bashbrew cat --format '
40+
{{- $e := .TagEntry -}}
41+
{{- "{" -}}
42+
"name": {{- json ($e.Tags | first) -}},
43+
"tags": {{- json ($.Tags namespace false $e) -}},
44+
"directory": {{- json $e.Directory -}},
45+
"file": {{- json $e.File -}},
46+
"constraints": {{- json $e.Constraints -}},
47+
"froms": {{- json ($.DockerFroms $e) -}}
48+
{{- "}" -}}
49+
' "$bashbrewImage" | jq -c '
50+
{
51+
name: .name,
52+
os: (
53+
if (.constraints | contains(["windowsservercore-1809"])) or (.constraints | contains(["nanoserver-1809"])) then
54+
"windows-2019"
55+
elif .constraints | contains(["windowsservercore-ltsc2016"]) then
56+
"windows-2016"
57+
elif .constraints == [] or .constraints == ["!aufs"] then
58+
"ubuntu-latest"
59+
else
60+
# use an intentionally invalid value so that GitHub chokes and we notice something is wrong
61+
"invalid-or-unknown"
62+
end
63+
),
64+
meta: { entries: [ . ] },
65+
runs: {
66+
build: (
67+
[
68+
"docker build"
69+
]
70+
+ (
71+
.tags
72+
| map(
73+
"--tag " + (. | @sh)
74+
)
75+
)
76+
+ if .file != "Dockerfile" then
77+
[ "--file", (.file | @sh) ]
78+
else
79+
[]
80+
end
81+
+ [
82+
(.directory | @sh)
83+
]
84+
| join(" ")
85+
),
86+
history: ("docker history " + (.tags[0] | @sh)),
87+
test: ("~/oi/test/run.sh " + (.tags[0] | @sh)),
88+
},
89+
}
90+
'
91+
)"
92+
93+
parent="$(bashbrew parents "$bashbrewImage" | tail -1)" # if there ever exists an image with TWO parents in the same repo, this will break :)
94+
if [ -n "$parent" ]; then
95+
parentBashbrewImage="${parent##*/}" # account for BASHBREW_NAMESPACE being set
96+
parent="$(bashbrew list --uniq "$parentBashbrewImage")" # normalize
97+
parentMeta="${metas["$parent"]}"
98+
parentMeta="$(jq -c --argjson meta "$meta" '
99+
. + {
100+
name: (.name + ", " + $meta.name),
101+
os: (if .os == $meta.os then .os else "invalid-os-chain--" + .os + "+" + $meta.os end),
102+
meta: { entries: (.meta.entries + $meta.meta.entries) },
103+
runs: (
104+
.runs
105+
| to_entries
106+
| map(
107+
.value += "\n" + $meta.runs[.key]
108+
)
109+
| from_entries
110+
),
111+
}
112+
' <<<"$parentMeta")"
113+
metas["$parent"]="$parentMeta"
114+
else
115+
metas["$tag"]="$meta"
116+
order+=( "$tag" )
117+
fi
118+
done
119+
120+
strategy="$(
121+
for tag in "${order[@]}"; do
122+
jq -c '
123+
.meta += {
124+
froms: (
125+
[ .meta.entries[].froms[] ]
126+
- [ .meta.entries[].tags[] ]
127+
),
128+
dockerfiles: [
129+
.meta.entries[]
130+
| .directory + "/" + .file
131+
],
132+
}
133+
| .runs += {
134+
prepare: ([
135+
(
136+
if .os | startswith("windows-") then
137+
"# enable symlinks on Windows (https://git-scm.com/docs/git-config#Documentation/git-config.txt-coresymlinks)",
138+
"git config --global core.symlinks true",
139+
"# ... make sure they are *real* symlinks (https://github.com/git-for-windows/git/pull/156)",
140+
"export MSYS=winsymlinks:nativestrict",
141+
"# make sure line endings get checked out as-is",
142+
"git config --global core.autocrlf false"
143+
else
144+
empty
145+
end
146+
),
147+
"git clone --depth 1 https://github.com/docker-library/official-images.git -b master ~/oi",
148+
"# create a dummy empty image/layer so we can --filter since= later to get a meanginful image list",
149+
"{ echo FROM " + (
150+
if (.os | startswith("windows-")) then
151+
"mcr.microsoft.com/windows/servercore:ltsc" + (.os | ltrimstr("windows-"))
152+
else
153+
"busybox:latest"
154+
end
155+
) + "; echo RUN :; } | docker build --no-cache --tag image-list-marker -",
156+
(
157+
if .os | startswith("windows-") | not then
158+
(
159+
"# PGP Happy Eyeballs",
160+
"git clone --depth 1 https://github.com/tianon/pgp-happy-eyeballs.git ~/phe",
161+
"~/phe/hack-my-builds.sh",
162+
"rm -rf ~/phe"
163+
)
164+
else
165+
empty
166+
end
167+
)
168+
] | join("\n")),
169+
pull: ([ .meta.froms[] | select(. != "scratch") | "docker pull " + @sh ] | join("\n")),
170+
# build
171+
# history
172+
# test
173+
images: "docker image ls --filter since=image-list-marker",
174+
}
175+
' <<<"${metas["$tag"]}"
176+
done | jq -cs '
177+
{
178+
"fail-fast": false,
179+
matrix: { include: . },
180+
}
181+
'
182+
)"
183+
184+
if [ -t 1 ]; then
185+
jq <<<"$strategy"
186+
else
187+
cat <<<"$strategy"
188+
fi

scripts/github-actions/munge-i386.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env bash
2+
set -Eeuo pipefail
3+
4+
jq --arg dpkgSmokeTest '[ "$(dpkg --print-architecture)" = "amd64" ]' '
5+
.matrix.include += [
6+
.matrix.include[]
7+
| select(.name | test(" (.+)") | not) # ignore any existing munged builds
8+
| select(.os | startswith("windows-") | not)
9+
| .name += " (i386)"
10+
| .runs.pull = ([
11+
"# pull i386 variants of base images for multi-architecture testing",
12+
$dpkgSmokeTest,
13+
(
14+
.meta.froms[]
15+
| ("i386/" + . | @sh) as $i386
16+
| (
17+
"docker pull " + $i386,
18+
"docker tag " + $i386 + " " + @sh
19+
)
20+
)
21+
] | join("\n"))
22+
]
23+
' "$@"

0 commit comments

Comments
 (0)