Merge ~morphis/snappy-hwe-snaps/+git/build-scripts:feature/snap-release-job into ~snappy-hwe-team/snappy-hwe-snaps/+git/build-scripts:master
- Git
- lp:~morphis/snappy-hwe-snaps/+git/build-scripts
- feature/snap-release-job
- Merge into master
Status: | Merged |
---|---|
Approved by: | Jim Hodapp |
Approved revision: | 235cb09d6d273e61dfc95f6a104aa949d1279a47 |
Merged at revision: | d94715fe5278700bbcdf52230dd71390118bd093 |
Proposed branch: | ~morphis/snappy-hwe-snaps/+git/build-scripts:feature/snap-release-job |
Merge into: | ~snappy-hwe-team/snappy-hwe-snaps/+git/build-scripts:master |
Diff against target: |
238 lines (+194/-6) 4 files modified
jobs/generic-release-snap (+63/-0) scripts/se_utils/__init__.py (+22/-0) scripts/snap-build (+9/-6) scripts/trigger-lp-build.py (+100/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jim Hodapp (community) | Approve | ||
System Enablement Bot | continuous-integration | Approve | |
Review via email: mp+316129@code.launchpad.net |
Commit message
Description of the change
Add snap release job
Follows the described process in our guidelines at https:/
Corresponding jenkins job is https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:397b72c1e43
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:8bfa35fd224
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:888533c5f1d
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:888533c5f1d
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:8fe0b20174d
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:e3859b8acc3
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:07b35cdf7a5
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2f7e09d84ac
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Jim Hodapp (jhodapp) wrote : | # |
Just a few changes needed, see inline below.
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:2d0377908a5
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:235cb09d6d2
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | diff --git a/jobs/generic-release-snap b/jobs/generic-release-snap | |||
2 | 0 | new file mode 100755 | 0 | new file mode 100755 |
3 | index 0000000..4c05499 | |||
4 | --- /dev/null | |||
5 | +++ b/jobs/generic-release-snap | |||
6 | @@ -0,0 +1,63 @@ | |||
7 | 1 | #!/bin/sh | ||
8 | 2 | # | ||
9 | 3 | # Copyright (C) 2017 Canonical Ltd | ||
10 | 4 | # | ||
11 | 5 | # This program is free software: you can redistribute it and/or modify | ||
12 | 6 | # it under the terms of the GNU General Public License version 3 as | ||
13 | 7 | # published by the Free Software Foundation. | ||
14 | 8 | # | ||
15 | 9 | # This program is distributed in the hope that it will be useful, | ||
16 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | 12 | # GNU General Public License for more details. | ||
19 | 13 | # | ||
20 | 14 | # You should have received a copy of the GNU General Public License | ||
21 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
22 | 16 | |||
23 | 17 | set -ex | ||
24 | 18 | |||
25 | 19 | if [ -z "$VERSION" ]; then | ||
26 | 20 | echo "ERROR: No version specified" | ||
27 | 21 | exit 1 | ||
28 | 22 | fi | ||
29 | 23 | |||
30 | 24 | echo "Snap to be release: $SNAP_NAME" | ||
31 | 25 | echo "Version to be released: $VERSION" | ||
32 | 26 | |||
33 | 27 | GIT_USER=system-enablement-ci-bot | ||
34 | 28 | REPOSITORY_URL="git+ssh://$GIT_USER@git.launchpad.net/~snappy-hwe-team/snappy-hwe-snaps/+git/$SNAP_NAME" | ||
35 | 29 | |||
36 | 30 | if [ -e $SNAP_NAME ]; then | ||
37 | 31 | rm -rf $SNAP_NAME | ||
38 | 32 | fi | ||
39 | 33 | |||
40 | 34 | git clone -b master $REPOSITORY_URL $SNAP_NAME | ||
41 | 35 | cd $SNAP_NAME | ||
42 | 36 | |||
43 | 37 | if [ ! -e snapcraft.yaml ]; then | ||
44 | 38 | echo "ERROR: No top-level snapcraft.yaml file!" | ||
45 | 39 | exit 1 | ||
46 | 40 | fi | ||
47 | 41 | |||
48 | 42 | git config user.name "System Enablement CI Bot" | ||
49 | 43 | git config user.email "ce-system-enablement@lists.canonical.com" | ||
50 | 44 | |||
51 | 45 | sed -i -e "s/version:.*/version: $VERSION/g" snapcraft.yaml | ||
52 | 46 | git add snapcraft.yaml | ||
53 | 47 | git commit -m "Bump version to $VERSION" | ||
54 | 48 | |||
55 | 49 | git tag -a -m "$VERSION" $VERSION HEAD | ||
56 | 50 | if ! git branch -r | grep origin/stable ; then | ||
57 | 51 | git checkout -b stable origin/master | ||
58 | 52 | else | ||
59 | 53 | git checkout -b stable origin/stable | ||
60 | 54 | fi | ||
61 | 55 | git merge master | ||
62 | 56 | |||
63 | 57 | git push origin stable | ||
64 | 58 | git push origin master | ||
65 | 59 | git push origin $VERSION | ||
66 | 60 | |||
67 | 61 | |||
68 | 62 | |||
69 | 63 | exec $WORKSPACE/build-scripts/scripts/trigger-lp-build.py -s $SNAP_NAME -p | ||
70 | diff --git a/scripts/se_utils/__init__.py b/scripts/se_utils/__init__.py | |||
71 | index fcb95d7..280450c 100644 | |||
72 | --- a/scripts/se_utils/__init__.py | |||
73 | +++ b/scripts/se_utils/__init__.py | |||
74 | @@ -20,6 +20,7 @@ import sys | |||
75 | 20 | import time | 20 | import time |
76 | 21 | import logging | 21 | import logging |
77 | 22 | import os | 22 | import os |
78 | 23 | import yaml | ||
79 | 23 | from shutil import rmtree | 24 | from shutil import rmtree |
80 | 24 | from launchpadlib.credentials import RequestTokenAuthorizationEngine | 25 | from launchpadlib.credentials import RequestTokenAuthorizationEngine |
81 | 25 | from lazr.restfulclient.errors import HTTPError | 26 | from lazr.restfulclient.errors import HTTPError |
82 | @@ -98,3 +99,24 @@ def get_launchpad(launchpadlib_dir=None, credential_store_path=None, lp_app=None | |||
83 | 98 | authorization_engine=authorization_engine, | 99 | authorization_engine=authorization_engine, |
84 | 99 | launchpadlib_dir=lib_dir, | 100 | launchpadlib_dir=lib_dir, |
85 | 100 | version='devel') | 101 | version='devel') |
86 | 102 | |||
87 | 103 | # Load configuration for the current agent we're running on. All agents were | ||
88 | 104 | # provisioned when they were setup with a proper configuration. See | ||
89 | 105 | # https://wiki.canonical.com/InformationInfrastructure/Jenkaas/UserDocs for | ||
90 | 106 | # more details. | ||
91 | 107 | def load_config(): | ||
92 | 108 | files = [os.path.expanduser('~/.jlp/jlp.config'), 'jlp.config'] | ||
93 | 109 | for config_file in files: | ||
94 | 110 | try: | ||
95 | 111 | config = yaml.safe_load(open(config_file, 'r')) | ||
96 | 112 | return config | ||
97 | 113 | except IOError: | ||
98 | 114 | pass | ||
99 | 115 | print("ERROR: No config file found") | ||
100 | 116 | sys.exit(1) | ||
101 | 117 | |||
102 | 118 | # Return a configuration option from the agent configuration specified by the | ||
103 | 119 | # name argument. | ||
104 | 120 | def get_config_option(name): | ||
105 | 121 | config = load_config() | ||
106 | 122 | return config[name] | ||
107 | diff --git a/scripts/snap-build b/scripts/snap-build | |||
108 | index b597ab6..abe40b4 100755 | |||
109 | --- a/scripts/snap-build | |||
110 | +++ b/scripts/snap-build | |||
111 | @@ -79,12 +79,15 @@ cd /build/src | |||
112 | 79 | 79 | ||
113 | 80 | git config user.name "System Enablement CI Bot" | 80 | git config user.name "System Enablement CI Bot" |
114 | 81 | git config user.email "ce-system-enablement@lists.canonical.com" | 81 | git config user.email "ce-system-enablement@lists.canonical.com" |
121 | 82 | git remote add other $SOURCE_GIT_REPO | 82 | |
122 | 83 | git fetch other | 83 | if [ -n "$SOURCE_GIT_REPO" ]; then |
123 | 84 | git merge \ | 84 | git remote add other $SOURCE_GIT_REPO |
124 | 85 | --no-ff \ | 85 | git fetch other |
125 | 86 | -m "Merge remote tracking branch other/$SOURCE_GIT_REPO_BRANCH" \ | 86 | git merge \ |
126 | 87 | $REVISION | 87 | --no-ff \ |
127 | 88 | -m "Merge remote tracking branch other/$SOURCE_GIT_REPO_BRANCH" \ | ||
128 | 89 | $REVISION | ||
129 | 90 | fi | ||
130 | 88 | 91 | ||
131 | 89 | # Only attempt to build projects where we have a valid snapcraft project. | 92 | # Only attempt to build projects where we have a valid snapcraft project. |
132 | 90 | # For all others we just make sure we can merge source to target. | 93 | # For all others we just make sure we can merge source to target. |
133 | diff --git a/scripts/trigger-lp-build.py b/scripts/trigger-lp-build.py | |||
134 | 91 | new file mode 100755 | 94 | new file mode 100755 |
135 | index 0000000..842acd5 | |||
136 | --- /dev/null | |||
137 | +++ b/scripts/trigger-lp-build.py | |||
138 | @@ -0,0 +1,100 @@ | |||
139 | 1 | #! /usr/bin/python | ||
140 | 2 | |||
141 | 3 | import os | ||
142 | 4 | import sys | ||
143 | 5 | import time | ||
144 | 6 | import smtplib | ||
145 | 7 | |||
146 | 8 | from datetime import datetime | ||
147 | 9 | from os.path import basename | ||
148 | 10 | from launchpadlib.launchpad import Launchpad | ||
149 | 11 | |||
150 | 12 | from argparse import ArgumentParser | ||
151 | 13 | |||
152 | 14 | import se_utils | ||
153 | 15 | |||
154 | 16 | parser = ArgumentParser(description="Build a specific snap on launchpad") | ||
155 | 17 | parser.add_argument('-s', '--snap', required=True, | ||
156 | 18 | help="Name of the snap to build") | ||
157 | 19 | parser.add_argument('-p', '--publish', action='store_true', | ||
158 | 20 | help="Trigger a publish build instead of a daily (default)") | ||
159 | 21 | |||
160 | 22 | args = vars(parser.parse_args()) | ||
161 | 23 | |||
162 | 24 | arches = ['amd64', 'i386', 'armhf', 'arm64'] | ||
163 | 25 | series = 'xenial' | ||
164 | 26 | |||
165 | 27 | lp_app = se_utils.get_config_option("lp_app") | ||
166 | 28 | lp_env = se_utils.get_config_option("lp_env") | ||
167 | 29 | credential_store_path = se_utils.get_config_option('credential_store_path') | ||
168 | 30 | launchpad = se_utils.get_launchpad(None, credential_store_path, lp_app, lp_env) | ||
169 | 31 | |||
170 | 32 | team = launchpad.people['snappy-hwe-team'] | ||
171 | 33 | |||
172 | 34 | build_name = "%s-daily" % args["snap"] | ||
173 | 35 | if args["publish"] == True: | ||
174 | 36 | build_name = "%s-publish" % args["snap"] | ||
175 | 37 | |||
176 | 38 | snap = launchpad.snaps.getByName(name=build_name, owner=team) | ||
177 | 39 | ubuntu = launchpad.distributions['ubuntu'] | ||
178 | 40 | release = ubuntu.getSeries(name_or_version=series) | ||
179 | 41 | primary_archive = ubuntu.getArchive(name='primary') | ||
180 | 42 | |||
181 | 43 | # Add a big fat warning that we don't really care about fixing things when | ||
182 | 44 | # the job will be canceled after the following lines are printed out. | ||
183 | 45 | print("!!!!!!! POINT OF NO RETURN !!!!!!!") | ||
184 | 46 | print("DO NOT CANCEL THIS JOB AFTER THIS OR BAD THINGS WILL HAPPEN") | ||
185 | 47 | print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") | ||
186 | 48 | |||
187 | 49 | stamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | ||
188 | 50 | print("Trying to trigger builds at: {}".format(stamp)) | ||
189 | 51 | |||
190 | 52 | # We will now trigger a build for each whitelisted architecture, collect the | ||
191 | 53 | # build job url and the wait for all builds to finish and collect their results | ||
192 | 54 | # to vote for a successful or failed build. | ||
193 | 55 | triggered_builds = [] | ||
194 | 56 | for build_arch in arches: | ||
195 | 57 | arch = release.getDistroArchSeries(archtag=build_arch) | ||
196 | 58 | request = snap.requestBuild(archive=primary_archive, distro_arch_series=arch, pocket='Proposed') | ||
197 | 59 | build_id = str(request).rsplit('/', 1)[-1] | ||
198 | 60 | triggered_builds.append(build_id) | ||
199 | 61 | print("Arch: {} is building under: {}".format(build_arch, request)) | ||
200 | 62 | |||
201 | 63 | failures = [] | ||
202 | 64 | while len(triggered_builds): | ||
203 | 65 | for build in triggered_builds: | ||
204 | 66 | try: | ||
205 | 67 | response = snap.getBuildSummariesForSnapBuildIds(snap_build_ids=[build]) | ||
206 | 68 | except: | ||
207 | 69 | print("Could not get response for {} (was there an LP timeout?)".format(build)) | ||
208 | 70 | continue | ||
209 | 71 | status = response[build]['status'] | ||
210 | 72 | if status == "FULLYBUILT": | ||
211 | 73 | triggered_builds.remove(build) | ||
212 | 74 | continue | ||
213 | 75 | elif status == "FAILEDTOBUILD": | ||
214 | 76 | failures.append(build) | ||
215 | 77 | triggered_builds.remove(build) | ||
216 | 78 | continue | ||
217 | 79 | elif status == "CANCELLED": | ||
218 | 80 | triggered_builds.remove(build) | ||
219 | 81 | continue | ||
220 | 82 | time.sleep(60) | ||
221 | 83 | |||
222 | 84 | if len(failures): | ||
223 | 85 | for failure in failures: | ||
224 | 86 | try: | ||
225 | 87 | response = snap.getBuildSummariesForSnapBuildIds(snap_build_ids=[failure]) | ||
226 | 88 | except: | ||
227 | 89 | print ("Could not get failure data for {} (was there an LP timeout?)".format(build)) | ||
228 | 90 | continue | ||
229 | 91 | buildlog = response[build]['build_log_url'] | ||
230 | 92 | if buildlog != 'None': | ||
231 | 93 | print(buildlog) | ||
232 | 94 | arch = str(buildlog).split('_')[4] | ||
233 | 95 | print("{} snap {} build at {} failed for id: {} log: {}".format(args["snap"], arch, stamp, failure, buildlog)) | ||
234 | 96 | |||
235 | 97 | # Let the build fail as at least a single snap has failed to build | ||
236 | 98 | sys.exit(1) | ||
237 | 99 | |||
238 | 100 | print("Done!") |
PASSED: Continuous integration, rev:fd6c0ef79ff e8ff841e2a1c4bd 4b35da29ec1e93 /jenkins. canonical. com/system- enablement/ job/generic- build-snap/ 750/ /jenkins. canonical. com/system- enablement/ job/generic- run-snap- spread- tests/447 /jenkins. canonical. com/system- enablement/ job/generic- update- snap-mp/ 658/console
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- enablement/ job/generic- build-snap/ 750/rebuild
https:/