2
# -*- coding: utf-8 -*-
3
# Copyright (C) 2012 Canonical
8
# This program is free software; you can redistribute it and/or modify it under
9
# the terms of the GNU General Public License as published by the Free Software
10
# Foundation; version 3.
12
# This program is distributed in the hope that it will be useful, but WITHOUT
13
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17
# You should have received a copy of the GNU General Public License along with
18
# this program; if not, write to the Free Software Foundation, Inc.,
19
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27
from cupstream2distro import branchhandling, packagemanager, launchpadmanager
28
from cupstream2distro.tools import generate_xml_artefacts, get_packaging_diff_filename, save_project_config
29
from cupstream2distro.settings import PREPARE_ARTEFACTS_FILENAME_FORMAT, BOT_DEBFULLNAME
32
if __name__ == '__main__':
34
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
36
parser = argparse.ArgumentParser(description="Prepare package for a specific component to push to a ppa",
37
epilog="All options can be set by the corresponding long option name env variables as well")
39
parser.add_argument("-n", "--sourcename", help="Source package name")
40
parser.add_argument("-b", "--branch", help="Branch to use as the upstream source")
41
parser.add_argument("-s", "--series", help="Serie used to build the package")
42
parser.add_argument("-V", "--series-version", help="set series versions")
43
parser.add_argument("-p", "--ppa", help="PPA to publish this package to (for instance: 'ubuntu-unity/daily-build')")
44
parser.add_argument("-d", "--destppa", help="Consider this destppa instead of only the distro for finale destination", default='')
45
parser.add_argument("-f", "--force-rebuild", help="Force rebuilding even if there is nothing to release", action='store_true')
46
parser.add_argument("--condition-force-rebuild", help="Only force rebuild if the conditional file is present (* and other blobs are allowed)", nargs='*')
47
parser.add_argument("--skip-checks", help="Skip destination version and conditional checking and call force rebuild", action='store_true')
49
args = parser.parse_args()
51
source_package_name = args.sourcename
54
series_version = args.series_version
56
if not source_package_name:
57
source_package_name = os.getenv("sourcename")
59
branch = os.getenv("branch")
61
series = os.getenv("series")
62
if not series_version:
63
series = os.getenv("series_version")
65
ppa = os.getenv("ppa")
66
instance_info = "for source: {}, branch: {}, series: {}".format(source_package_name, branch, series)
69
if not source_package_name or not branch or not series or not ppa:
70
logging.error("Missing compulsory environment variables (sourcename, branch, series, ppa) {}".format(instance_info))
74
logging.info("Branching {} to {}".format(branch, source_package_name))
75
branchhandling.get_branch(branch, source_package_name)
76
os.chdir(source_package_name)
78
# Get changelog informations
79
logging.info("Get changelog info")
80
with open("debian/changelog") as changelog:
81
last_upstream_rev = packagemanager.get_latest_upstream_bzr_rev(changelog, args.destppa)
82
packaging_version_in_bzr = packagemanager.get_packaging_version()
84
if (source_package_name != packagemanager.get_packaging_sourcename()):
85
logging.error("Projectbranch doesn't specify the same source name than the packaging itself {}".format(instance_info))
88
# Check version in ppa
89
logging.info("Get previous version in ppa")
90
version_in_ppa = packagemanager.get_current_version_for_series(source_package_name, series, ppa)
91
if packagemanager.is_version1_higher_than_version2(version_in_ppa, packaging_version_in_bzr):
92
logging.info("A version in the ppa ({}) is higher than the proposed version in bzr ({}) (previous tests/builds failing?). Basing on that one.".format(version_in_ppa, packaging_version_in_bzr))
93
previous_packaging_version = version_in_ppa
95
previous_packaging_version = packaging_version_in_bzr
97
# Check version in distro
98
logging.info("Get version available in distro")
99
distro_version = packagemanager.get_current_version_for_series(source_package_name, series)
100
artefacts_file = os.path.abspath(os.path.join('..', PREPARE_ARTEFACTS_FILENAME_FORMAT.format(source_package_name)))
102
# if the target is the distro, we ensure we have all releases in trunk
104
dest_archive = launchpadmanager.get_ubuntu_archive()
105
previous_finaledest_version = distro_version
108
dest_archive = launchpadmanager.get_ppa(args.destppa)
109
previous_finaledest_version = packagemanager.get_current_version_for_series(source_package_name, series, args.destppa)
110
# TODO: if none, we should maybe take distro_version?
112
# ensure that the previous release (in distro or in dest ppa) ended up in the vcs
114
logging.info("Skip destination version and conditional checking requested. Will overwrite even if destination has a newer version or the (optional) condition isn't met.")
117
with open("debian/changelog") as changelog:
118
if not packagemanager.is_version_in_changelog(previous_finaledest_version, changelog):
119
message = ("A version ({}) is available at the destination for that component but is not in trunk which is still at {}. "
120
"Ignoring that component {}.".format(previous_finaledest_version, packaging_version_in_bzr, instance_info))
121
logging.info(message)
122
generate_xml_artefacts("Prepare", [message], artefacts_file)
125
if force_rebuild or args.force_rebuild:
126
logging.info("The rebuild of that component is forced.")
129
# if the version in the distro is higher than the previous packaging version (either the version in intermediate ppa or packaging bzr version
130
# We are going to force releasing, but basing on this version
131
if packagemanager.is_version1_higher_than_version2(distro_version, previous_packaging_version):
132
logging.info("The version in distro ({}) is higher than what is proposed in the bzr version for that branch ({}). Basing on the distro version.".format(distro_version, previous_packaging_version))
133
logging.info("Forcing release mode as the version in distro ({}) is higher than current destination ppa ({})".format(distro_version, previous_packaging_version))
134
previous_packaging_version = distro_version
137
# Check if we need to republish
138
tip_bzr_rev = branchhandling.get_tip_bzr_revision()
139
dest_source_package = None
140
logging.info("Check if we need to release a new package")
142
dest_source_package = packagemanager.get_source_package_from_dest(source_package_name, dest_archive, previous_finaledest_version, series)
143
# TODO: all paths, on all projects, should have the stack dir as root, and only chdir in the script, not the functions.
144
if dest_source_package:
145
dest_source_package = os.path.abspath(dest_source_package)
146
os.chdir(source_package_name)
148
if not packagemanager.is_new_content_relevant_since_old_published_source(dest_source_package):
149
if not force_rebuild:
150
logging.info("No new useful revision published since last daily push, no need to upload this component")
151
generate_xml_artefacts("Prepare", [], artefacts_file)
153
logging.info("No new useful revision published but force rebuilding is set")
154
if not args.skip_checks and args.condition_force_rebuild:
155
logging.info("Condition found without skip check, verifying that files exists")
157
for glob_filename in args.condition_force_rebuild:
159
for filename in glob.glob(os.path.join("..", glob_filename)):
160
if os.path.isfile(filename):
163
msg = "{} doesn't exist".format(glob_filename)
166
# exit 0 as the precondition isn't there
168
generate_xml_artefacts("Prepare", [], artefacts_file)
171
packaging_version = packagemanager.create_new_packaging_version(previous_packaging_version, destppa=args.destppa, series_version=series_version)
173
# Refresh symbol files
174
logging.info("Update symbol files version if needed")
175
packagemanager.refresh_symbol_files(packaging_version)
178
logging.info("Prepare changelog content")
179
log_content = branchhandling.return_log_diff(last_upstream_rev + 1)
180
alreadyfixed_bugs = set()
181
with open("debian/changelog") as f:
182
alreadyfixed_bugs = packagemanager.collect_bugs_in_changelog_until_latest_snapshot(f, source_package_name)
183
(authors_commits, bugs_set) = branchhandling.collect_author_commits(log_content, alreadyfixed_bugs)
185
authors_commits[BOT_DEBFULLNAME] = ["New rebuild forced"]
186
packagemanager.update_changelog(packaging_version, series, tip_bzr_rev, authors_commits, args.destppa)
188
logging.info("Sync launchpad with current proposed work")
189
branchhandling.commit_release(packaging_version, tip_bzr_rev)
190
launchpadmanager.open_bugs_for_source(bugs_set, source_package_name, series)
192
logging.info("Build source package")
193
packagemanager.build_source_package(series, previous_finaledest_version, args.destppa)
195
newdsc_path = "{}_{}.dsc".format(source_package_name, packaging_version.split(':')[-1])
197
# second diff step: in case the source package was created from nothing (like a diff between trunk and the source package, but none after newly .dsc created extraction)
198
if not force_rebuild and dest_source_package:
199
logging.info("Check that the newly created source package has relevant diff")
200
if not packagemanager.is_relevant_source_diff_from_previous_dest_version(newdsc_path, dest_source_package):
201
message = ("There was a diff between trunk and the source package in ubuntu triggering a source package build. However, after that one was created, we diffed again "
202
"between that source in ubuntu and the newly created source extracted and found nothing relevant. Not upload that one then. Please check that the relevant "
203
"diff in the package creation is justified by diffing manually trunk and the source in ubuntu.")
204
logging.info(message)
205
generate_xml_artefacts("Prepare", [message], artefacts_file)
208
# We don't do package diff detection for a feature ppa
210
# Prepare if a packaging change is part of the diff
211
# FIXME: should be done with debdiff between all and new package
212
logging.info("Generate a diff if meaningfull packaging changes")
213
diff_filepath = get_packaging_diff_filename(source_package_name, packaging_version)
215
if dest_source_package:
216
for file in os.listdir(os.path.dirname(dest_source_package)):
217
if file.endswith(".dsc"):
218
olddsc_path = os.path.join(os.path.dirname(dest_source_package), file)
219
packagemanager.generate_diff_between_dsc(diff_filepath, olddsc_path, newdsc_path)
221
logging.info("Upload to the ppa")
222
packagemanager.upload_package(source_package_name, packaging_version, ppa)
224
# Save infos for other jobs
225
save_project_config(source_package_name, branch, tip_bzr_rev, previous_finaledest_version, packaging_version)
228
os.chdir(source_package_name)
229
generate_xml_artefacts("Prepare", [], artefacts_file)
231
# TODO: clean the ppa (remove all old unpublished packages)