Skip to content

Commit deda7e6

Browse files
committed
build: automatically build branch for offical-images release
For various products, we go through several weeks of testing before we officially release. Therefore, we may cut a release, have packages available in a non-official capacity, then later decide to release in an official capacity.
1 parent 2f72e6b commit deda7e6

File tree

8 files changed

+362
-0
lines changed

8 files changed

+362
-0
lines changed

.circleci/config.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
---
12
version: 2.1
23

4+
master_filter: &master_filter
5+
filters:
6+
tags:
7+
ignore: /.*/
8+
branches:
9+
only: /^master$/
10+
311
workflows:
412
version: 2
513
ci:
@@ -9,6 +17,8 @@ workflows:
917
matrix:
1018
parameters:
1119
version: ["2.0", "2.1", "2.2"]
20+
- publish_docker_images:
21+
<<: *master_filter
1222

1323
jobs:
1424
build:
@@ -33,3 +43,34 @@ jobs:
3343
- store_artifacts:
3444
path: influxdb/test/logs
3545
destination: container-logs
46+
47+
publish_docker_images:
48+
docker:
49+
- image: 'cimg/python:3.6'
50+
steps:
51+
- checkout
52+
- run:
53+
name: Install Prerequisite Packages
54+
command: |
55+
sudo bash -s \<<EOF
56+
#!/bin/bash
57+
set -o errexit \
58+
-o nounset \
59+
-o pipefail
60+
61+
export DEBIAN_FRONTEND=noninteractive
62+
apt-get update
63+
apt-get install --yes git
64+
EOF
65+
66+
python3 -m pip install -r \
67+
.circleci/scripts/update_manifest_file/requirements.txt
68+
- run:
69+
name: Get Release Information
70+
command: |
71+
.circleci/scripts/get-release-info
72+
- run:
73+
name: Do Enterprise Release
74+
command: |
75+
.circleci/scripts/get-enterprise-version
76+
.circleci/scripts/do-enterprise-release

.circleci/scripts/create-draft-pr

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
set -o errexit \
3+
-o nounset \
4+
-o pipefail
5+
6+
# ${1} -> ENDPOINT
7+
# ${2} -> HEAD
8+
# ${3} -> TITLE
9+
10+
read -d '' -r DATA <<EOF || true
11+
{
12+
"title": "${3}",
13+
"head": "${2}",
14+
"base": "master",
15+
"draft": true
16+
}
17+
EOF
18+
19+
curl \
20+
-X POST \
21+
-H "Accept: application/vnd.github.v3+json" \
22+
-H "Authorization: Bearer ${GITHUB_MACHINE_TOKEN}" \
23+
"${1}" -d "${DATA}"
24+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/bash
2+
set -o errexit \
3+
-o nounset \
4+
-o pipefail
5+
6+
if [[ ${PRODUCT} != 'influxdb' ]] || ( \
7+
[[ ${SUBPRODUCT} != 'meta' ]] && \
8+
[[ ${SUBPRODUCT} != 'data' ]] \
9+
)
10+
then
11+
printf 'Release is not Enterprise skipping...\n'; exit 0
12+
fi
13+
14+
git clone [email protected]:/docker-library/official-images
15+
16+
python3 .circleci/scripts/update_manifest_file official-images/library/influxdb
17+
18+
pushd official-images
19+
20+
# CircleCI preloads the ssh-agent with the secret key required to clone
21+
# the repository. Unfortunately, this secret key does not have the
22+
# required permissions to `push`. This flushes the ssh-agent of
23+
# keys so that the `${SSH_MACHINE_SECKEY}` is always used.
24+
ssh-add -D && base64 -d <<<"${SSH_MACHINE_SECKEY}" | ssh-add -
25+
26+
git config user.name "${GITHUB_MACHINE_NAME}"
27+
git config user.email "${GITHUB_MACHINE_EMAIL}"
28+
29+
# We always branch from 'origin/master' to use the most up-to-date
30+
# source and avoid merge conflicts.
31+
git checkout -b "CI_release_${VERSION}" "origin/master"
32+
33+
git add . && git commit -m "feat: release Enterprise ${VERSION}"
34+
35+
# If this workflow is executed multiple times, it's possible that a branch
36+
# named `CI_release_${VERSION}` already exists. If this is the
37+
# case, we overwrite it with our commits.
38+
git remote add influxdata [email protected]:/influxdata/official-images
39+
git push -f --set-upstream influxdata "CI_release_${VERSION}"
40+
41+
popd
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/bash
2+
set -o errexit \
3+
-o nounset \
4+
-o pipefail
5+
6+
if [[ ${PRODUCT} != 'influxdb' ]] || ( \
7+
[[ ${SUBPRODUCT} != 'meta' ]] && \
8+
[[ ${SUBPRODUCT} != 'data' ]] \
9+
)
10+
then
11+
printf 'Release is not Enterprise skipping...\n'; exit 0
12+
fi
13+
14+
read -d '' -r PROGRAM <<'EOF' || true
15+
use strict;
16+
17+
for my $line ( <STDIN> )
18+
{
19+
if ( $line =~
20+
/
21+
^ENV\s+INFLUXDB_VERSION\s+ # prelude
22+
23+
(([[:digit:]]+) # major cg: 2
24+
(?:\.([[:digit:]]+))? # minor? cg: 3
25+
(?:\.([[:digit:]]+))? # patch? cg: 4
26+
(?:\-?(rc[[:digit:]]+))?) # rc? cg: 5
27+
-c # interlude
28+
([[:digit:]]+) # repeat major cg: 6
29+
(?:\.([[:digit:]]+))? # repeat minor? cg: 7
30+
(?:\.([[:digit:]]+))? # repeat patch? cg: 8
31+
(?:\-?(rc[[:digit:]]+))? # repeat rc? cg: 9
32+
/x )
33+
{
34+
# I tried using capture-group back-references within the regular
35+
# expression. However, it couldn't handle optional capture-
36+
# groups. So, instead, we check for equality here.
37+
if (( $2 eq $6 ) && ( $3 eq $7 ) &&
38+
( $4 eq $8 ) && ( $5 eq $9 ))
39+
{
40+
printf("$1\n"); exit 0
41+
}
42+
}
43+
}
44+
45+
exit 1
46+
EOF
47+
48+
shopt -s failglob
49+
shopt -s globstar
50+
# `failglob` ensures that the glob-pattern has at least once match. This
51+
# prevents bash from emitting the un-modified glob-pattern. `globstar`
52+
# then ensures that matches are found within subdirectories.
53+
VERSION=$(
54+
cat influxdb/${VERSION_MAJOR}.${VERSION_MINOR}/**/Dockerfile | \
55+
perl -e "${PROGRAM}"
56+
)
57+
58+
cat <<EOF >>"${BASH_ENV}"
59+
export VERSION=${VERSION}
60+
EOF

.circleci/scripts/get-release-info

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/bin/bash
2+
set -o errexit \
3+
-o nounset \
4+
-o pipefail
5+
6+
function is_whitelisted()
7+
{
8+
read -d '' -r PROGRAM <<'EOF' || true
9+
use strict;
10+
11+
# Specifies the whitelist for each product / version / sub-product.
12+
# The sub-product is an optional string that contains a path. This
13+
# must be the top-level path from the version directory:
14+
#
15+
# influxdb/1.9/Dockerfile # -empty- sub-product
16+
# influxdb/1.9/data/Dockerfile # data sub-product
17+
# influxdb/1.9/data/alpine/Dockerfile # data sub-product
18+
my %whitelist = (
19+
'influxdb' => [
20+
[ 1, 9, 'data' ],
21+
[ 1, 9, 'meta' ],
22+
],
23+
);
24+
25+
for my $line ( <STDIN> )
26+
{
27+
chomp ( $line );
28+
29+
if ( $line !~
30+
/
31+
^(.*?)\/ # product
32+
([[:digit:]]+)\. # major version
33+
([[:digit:]]+) # minor version
34+
(?:\/(.*?))? # sub-product
35+
\/Dockerfile$ # dockerfile
36+
/x )
37+
{
38+
next;
39+
}
40+
41+
my $prod = $1;
42+
my $major = $2;
43+
my $minor = $3;
44+
my $subp = $4; $subp =~ s/\/alpine//;
45+
46+
foreach my $element ( @{ $whitelist{$prod} } )
47+
{
48+
if ( @{ $element }[0] eq $major &&
49+
@{ $element }[1] eq $minor &&
50+
@{ $element }[2] eq $subp )
51+
{
52+
printf ( <<EOM
53+
export PRODUCT=$prod
54+
export VERSION_MAJOR=$major
55+
export VERSION_MINOR=$minor
56+
export SUBPRODUCT=$subp
57+
EOM
58+
);
59+
60+
exit 0;
61+
}
62+
}
63+
}
64+
65+
printf ( <<EOM
66+
export PRODUCT=
67+
export VERSION_MAJOR=
68+
export VERSION_MINOR=
69+
export SUBPRODUCT=
70+
EOM
71+
);
72+
EOF
73+
# Analyses the paths that have changed between `HEAD~1` and `HEAD`
74+
# for whitelisted products and versions. This prevents circleci
75+
# from creating PRs in `official-images` for products that do
76+
# not officially use this release workflow.
77+
git diff --name-only HEAD~1..HEAD | perl -e "${PROGRAM}" 1>>"${BASH_ENV}"
78+
}
79+
80+
is_whitelisted
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from debian.deb822 import Deb822
2+
from debian.deb822 import Deb822Dict
3+
import argparse
4+
import os
5+
import re
6+
import sys
7+
8+
9+
def reg_major(major: int) -> str:
10+
"""
11+
reg_major
12+
13+
Generates a partial-regular expression that matches the
14+
supplied `major` version.
15+
"""
16+
# This forces `major` to be an integer by using the integer format
17+
# specifier. This sanitization is important so that regex cannot
18+
# be accidentally inserted into `re.sub`. If `major` is not an
19+
# integer, this aborts the program.
20+
return r"(" + "{0:d}".format(major) + r")"
21+
22+
23+
def reg_minor(minor: int) -> str:
24+
"""
25+
reg_minor
26+
27+
Generates a partial-regular expression that matches the
28+
supplied `minor` version.
29+
"""
30+
# This forces `minor` to be an integer by using the integer format
31+
# specifier. This sanitization is important so that regex cannot
32+
# be accidentally inserted into `re.sub`. If `minor` is not an
33+
# integer, this aborts the program.
34+
return r"(?:\.(" + "{0:d}".format(minor) + r"))"
35+
36+
37+
def reg_patch() -> str:
38+
"""
39+
reg_patch
40+
41+
Generates a partial-regular expression that matches any patch
42+
version.
43+
"""
44+
return r"(?:\.(\d+))"
45+
46+
47+
def paragraph_cb(index, paragraph):
48+
"""
49+
paragraph_cb
50+
"""
51+
52+
def paragraph_repo_cb(paragraph):
53+
# This callback is executed for the 'repository' paragraph. This
54+
# is currently defined as the first paragraph. This paragraph
55+
# usually has the keys 'Maintainers', 'GitRepo', and
56+
# 'GitCommit'.
57+
58+
def item_cb(key, value):
59+
if key == "GitCommit":
60+
return os.environ.get("CIRCLE_SHA1")
61+
else:
62+
return value
63+
64+
return {k: item_cb(k, v) for (k, v) in paragraph.items()}
65+
66+
def paragraph_rele_cb(paragraph):
67+
# This callback is executed for every 'release' paragraph. This
68+
# is currently defined as every paragraph following the first.
69+
# This paragraph usually has the keys 'Tags', 'Architectures',
70+
# and 'Directory'.
71+
72+
def item_cb(key, value):
73+
# If this has encountered a 'Tags:' key-value pair, update all
74+
# matching 'Major.Minor.Patch' versions. `major` and `minor`
75+
# must match `VERSION_MAJOR` and `VERSION_MINOR`. `patch`
76+
# can be any integer.
77+
if key == "Tags":
78+
# fmt: off
79+
return re.sub(
80+
reg_major(int(os.environ.get("VERSION_MAJOR"))) +
81+
reg_minor(int(os.environ.get("VERSION_MINOR"))) +
82+
reg_patch(),
83+
os.environ.get("VERSION"),
84+
value,
85+
)
86+
# fmt: on
87+
else:
88+
return value
89+
90+
return {k: item_cb(k, v) for (k, v) in paragraph.items()}
91+
92+
# fmt: off
93+
return (
94+
paragraph_repo_cb(paragraph) if index == 0 else
95+
paragraph_rele_cb(paragraph)
96+
)
97+
# fmt: on
98+
99+
with open(sys.argv[1], "rb") as content:
100+
# fmt: off
101+
document = [
102+
paragraph_cb(index, parser) for index, parser in
103+
enumerate(Deb822.iter_paragraphs(content))
104+
]
105+
# fmt: on
106+
107+
with open(sys.argv[1], "w") as output:
108+
for paragraph in document:
109+
# The `Deb822` constructor requires a `Sequence`-like object. Since
110+
# each `paragraph` within the `document` is a `Dict` (which does
111+
# not implement the `Sequence` methods), this constructs a
112+
# `Deb822dict` instance as an intermediate.
113+
output.write("{0:s}\n".format(Deb822(Deb822Dict(paragraph)).dump()))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
python-debian==0.1.43
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
chardet==4.0.0
2+
python-debian==0.1.43

0 commit comments

Comments
 (0)