author | Dorel Luca <dluca@mozilla.com> |
Wed, 18 Apr 2018 11:14:20 +0300 | |
changeset 414229 | 3c4261ce506185df17964ad81f8e8a7f4ee6c885 |
parent 414228 | 6b80d13e112b4997fd4cf5407bbcafbbb543544c |
child 414230 | dbf2bfc0aea9754a44ae6e1c779b82ea84474dff |
push id | 33861 |
push user | ccoroiu@mozilla.com |
push date | Wed, 18 Apr 2018 10:50:38 +0000 |
treeherder | mozilla-central@4af4ae0aee55 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1447688 |
milestone | 61.0a1 |
backs out | f5f4089f457e85f1f485bd0411bd4cf1d30d487e |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/taskcluster/docker/beet-mover/Dockerfile @@ -0,0 +1,23 @@ +FROM ubuntu:xenial + +RUN apt-get -q update \ + && apt-get install --yes -q \ + mercurial \ + python-dev \ + python-pip \ + python-virtualenv \ + libffi-dev \ + liblzma-dev \ + libssl-dev \ + libyaml-dev \ + libmysqlclient-dev \ + clamav \ + clamav-freshclam \ + curl \ + wget \ + && apt-get clean + +COPY requirements.txt /tmp/ +RUN pip install -r /tmp/requirements.txt +# Freshclam may be flaky, retry if it fails +RUN for i in 1 2 3 4 5; do freshclam --verbose && break || sleep 15; done
new file mode 100644 --- /dev/null +++ b/taskcluster/docker/beet-mover/requirements.txt @@ -0,0 +1,2 @@ +sh +redo
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/en_us_build.yml.tmpl @@ -0,0 +1,87 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for the en-US locale" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + {{ locale }}: + + buildinfo: + artifact: {{ artifact_base_url }}/target.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.json + mozinfo: + artifact: {{ artifact_base_url }}/target.mozinfo.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.mozinfo.json + socorroinfo: + artifact: {{ artifact_base_url }}/target.txt + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.txt + jsshell: + artifact: {{ artifact_base_url }}/target.jsshell.zip + s3_key: {{ s3_prefix }}jsshell/jsshell-{{ platform }}.zip + mozharness_package: + artifact: {{ artifact_base_url }}/mozharness.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/mozharness.zip + xpi: + artifact: {{ artifact_base_url }}/target.langpack.xpi + s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi + symbols: + artifact: {{ artifact_base_url }}/target.crashreporter-symbols.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip + + {% if platform == "win32" %} + buildid_info: + artifact: {{ artifact_base_url }}/target_info.txt + s3_key: {{ s3_prefix }}win32_info.txt + mar_tools_mar: + artifact: {{ artifact_base_url }}/host/bin/mar.exe + s3_key: {{ s3_prefix }}mar-tools/win32/mar.exe + mar_tools_mbdiff: + artifact: {{ artifact_base_url }}/host/bin/mbsdiff.exe + s3_key: {{ s3_prefix }}mar-tools/win32/mbsdiff.exe + {% endif %} + + {% if platform == "win64" %} + buildid_info: + artifact: {{ artifact_base_url }}/target_info.txt + s3_key: {{ s3_prefix }}win64_info.txt + mar_tools_mar: + artifact: {{ artifact_base_url }}/host/bin/mar.exe + s3_key: {{ s3_prefix }}mar-tools/win64/mar.exe + mar_tools_mbdiff: + artifact: {{ artifact_base_url }}/host/bin/mbsdiff.exe + s3_key: {{ s3_prefix }}mar-tools/win64/mbsdiff.exe + {% endif %} + + {% if platform == "linux-i686" %} + buildid_info: + artifact: {{ artifact_base_url }}/target_info.txt + s3_key: {{ s3_prefix }}linux_info.txt + mar_tools_mar: + artifact: {{ artifact_base_url }}/host/bin/mar + s3_key: {{ s3_prefix }}mar-tools/linux/mar + mar_tools_mbdiff: + artifact: {{ artifact_base_url }}/host/bin/mbsdiff + s3_key: {{ s3_prefix }}mar-tools/linux/mbsdiff + {% endif %} + + {% if platform == "linux-x86_64" %} + buildid_info: + artifact: {{ artifact_base_url }}/target_info.txt + s3_key: {{ s3_prefix }}linux64_info.txt + mar_tools_mar: + artifact: {{ artifact_base_url }}/host/bin/mar + s3_key: {{ s3_prefix }}mar-tools/linux64/mar + mar_tools_mbdiff: + artifact: {{ artifact_base_url }}/host/bin/mbsdiff + s3_key: {{ s3_prefix }}mar-tools/linux64/mbsdiff + {% endif %} + + {% if platform == "mac" %} + buildid_info: + artifact: {{ artifact_base_url }}/target_info.txt + s3_key: {{ s3_prefix }}macosx64_info.txt + {% endif %} + +{% endfor %}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/en_us_repackage.yml.tmpl @@ -0,0 +1,16 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for the en-US locale" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + {{ locale }}: + {% if platform == "mac" %} + package: + artifact: {{ artifact_base_url }}/target.dmg + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox {{ version }}.dmg + {% endif %} + +{% endfor %}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/en_us_repackage_signing.yml.tmpl @@ -0,0 +1,35 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for the en-US locale" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + {{ locale }}: + {% if platform == "win32" %} + complete_mar: + artifact: {{ artifact_base_url }}/target.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + full_installer: + artifact: {{ artifact_base_url }}/target.installer.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + {% if "esr" not in version %} + stub_installer: + artifact: {{ artifact_base_url }}/target.stub-installer.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Installer.exe + {% endif %} + {% elif platform == "win64" %} + complete_mar: + artifact: {{ artifact_base_url }}/target.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + full_installer: + artifact: {{ artifact_base_url }}/target.installer.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + {% else %} + complete_mar: + artifact: {{ artifact_base_url }}/target.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + {% endif %} + +{% endfor %}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/en_us_signing.yml.tmpl @@ -0,0 +1,38 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for the en-US locale" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + {{ locale }}: + {% if platform == "win32" %} + package: + artifact: {{ artifact_base_url }}/target.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + {% endif %} + + {% if platform == "win64" %} + package: + artifact: {{ artifact_base_url }}/target.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + {% endif %} + + {% if platform == "linux-i686" %} + package: + artifact: {{ artifact_base_url }}/target.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + {% endif %} + + {% if platform == "linux-x86_64" %} + package: + artifact: {{ artifact_base_url }}/target.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + {% endif %} + + {% if platform == "mac" %} + # nothing to see here + {% endif %} + +{% endfor %}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/l10n_changesets.tmpl @@ -0,0 +1,11 @@ +--- +metadata: + name: "Beet Mover L10N Changesets" + description: "Maps artifact locations to s3 key names for L10N changesets" + owner: "release@mozilla.com" + +mapping: + all: + l10n_changesets: + artifact: {{ artifact_base_url }}/l10n_changesets.txt + s3_key: {{ s3_prefix }}l10n_changesets.txt
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/partials.yml.tmpl @@ -0,0 +1,16 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for partials" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + {{ locale }}: + partial_mar: + artifact: {{ artifact_base_url }}/firefox-{{ partial_version }}-{{ version }}.{{ locale }}.{{ platform }}.partial.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ partial_version }}-{{ version }}.partial.mar + partial_mar_sig: + artifact: {{ artifact_base_url }}/firefox-{{ partial_version }}-{{ version }}.{{ locale }}.{{ platform }}.partial.mar.asc + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ partial_version }}-{{ version }}.partial.mar.asc +{% endfor %}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/recompressed_completes.yml.tmpl @@ -0,0 +1,16 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for recompressed completes" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + {{ locale }}: + complete_mar: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.{{ locale }}.{{ platform }}.bz2.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.bz2.complete.mar + complete_mar_sig: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.{{ locale }}.{{ platform }}.bz2.complete.mar.asc + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.bz2.complete.mar.asc +{% endfor %}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/repacks.yml.tmpl @@ -0,0 +1,65 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for the non en-US locales" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + # common deliverables + {{ locale }}: + complete_mar: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + checksum: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums + checksum_sig: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums.asc + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums.asc + xpi: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi + s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi + + {% if platform == "win32" %} + full_installer: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + {% if "esr" not in version %} + stub_installer: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer-stub.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Installer.exe + {% endif %} + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + {% endif %} + + {% if platform == "win64" %} + full_installer: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + {% endif %} + + {% if platform == "linux-i686" %} + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + {% endif %} + + {% if platform == "linux-x86_64" %} + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + {% endif %} + + {% if platform == "mac" %} + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.dmg + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox {{ version }}.dmg + {% endif %} + +{% endfor %}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/snap.yml.tmpl @@ -0,0 +1,11 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for snap iamge" + owner: "release@mozilla.com" + +mapping: + all: + snap: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.snap + s3_key: {{ s3_prefix }}snap/firefox-{{ version }}.snap
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/snap_checksums.yml.tmpl @@ -0,0 +1,14 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for snap checksums" + owner: "release@mozilla.com" + +mapping: + all: + snap_checksum: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.snap.checksums + s3_key: {{ s3_prefix }}snap/firefox-{{ version }}.snap.checksums + snap_checksum_asc: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.snap.checksums.asc + s3_key: {{ s3_prefix }}snap/firefox-{{ version }}.snap.checksums.asc
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/source.yml.tmpl @@ -0,0 +1,14 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for source bundles" + owner: "release@mozilla.com" + +mapping: + all: + source_bundle: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.bundle + s3_key: {{ s3_prefix }}source/firefox-{{ version }}.bundle + source_tar: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.source.tar.xz + s3_key: {{ s3_prefix }}source/firefox-{{ version }}.source.tar.xz
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/source_checksums.yml.tmpl @@ -0,0 +1,14 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for source bundle checksums" + owner: "release@mozilla.com" + +mapping: + all: + source_checksum: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.source.checksums + s3_key: {{ s3_prefix }}source/firefox-{{ version }}.source.checksums + source_checksum_asc: + artifact: {{ artifact_base_url }}/firefox-{{ version }}.source.checksums.asc + s3_key: {{ s3_prefix }}source/firefox-{{ version }}.source.checksums.asc
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/beetmover/win32_to_win64_partials.yml.tmpl @@ -0,0 +1,16 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for partials" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + {{ locale }}: + partial_mar: + artifact: {{ artifact_base_url }}/firefox-{{ partial_version }}-{{ version }}.{{ locale }}.win32-to-win64.partial.mar + s3_key: {{ s3_prefix }}update/win32-to-win64/{{ locale }}/firefox-{{ partial_version }}-{{ version }}.partial.mar + partial_mar_sig: + artifact: {{ artifact_base_url }}/firefox-{{ partial_version }}-{{ version }}.{{ locale }}.win32-to-win64.partial.mar.asc + s3_key: {{ s3_prefix }}update/win32-to-win64/{{ locale }}/firefox-{{ partial_version }}-{{ version }}.partial.mar.asc +{% endfor %}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/releases/postrelease_fennec_beta.py @@ -0,0 +1,18 @@ +config = { + "log_name": "bump_beta", + "version_files": [{"file": "browser/config/version_display.txt"}], + "repo": { + "repo": "https://hg.mozilla.org/releases/mozilla-beta", + "branch": "default", + "dest": "mozilla-beta", + "vcs": "hg", + "clone_upstream_url": "https://hg.mozilla.org/mozilla-unified", + }, + "vcs_share_base": "/builds/hg-shared", + "push_dest": "ssh://hg.mozilla.org/releases/mozilla-beta", + "ignore_no_changes": True, + "ssh_user": "ffxbld", + "ssh_key": "~/.ssh/ffxbld_rsa", + "ship_it_root": "https://ship-it.mozilla.org", + "ship_it_username": "ship_it-ffxbld", +}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/releases/postrelease_fennec_release.py @@ -0,0 +1,22 @@ +config = { + "log_name": "bump_release", + "version_files": [ + {"file": "browser/config/version.txt"}, + {"file": "browser/config/version_display.txt"}, + {"file": "config/milestone.txt"}, + ], + "repo": { + "repo": "https://hg.mozilla.org/releases/mozilla-release", + "branch": "default", + "dest": "mozilla-release", + "vcs": "hg", + "clone_upstream_url": "https://hg.mozilla.org/mozilla-unified", + }, + "vcs_share_base": "/builds/hg-shared", + "push_dest": "ssh://hg.mozilla.org/releases/mozilla-release", + "ignore_no_changes": True, + "ssh_user": "ffxbld", + "ssh_key": "~/.ssh/ffxbld_rsa", + "ship_it_root": "https://ship-it.mozilla.org", + "ship_it_username": "ship_it-ffxbld", +}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/releases/postrelease_firefox_beta.py @@ -0,0 +1,18 @@ +config = { + "log_name": "bump_beta", + "version_files": [{"file": "browser/config/version_display.txt"}], + "repo": { + "repo": "https://hg.mozilla.org/releases/mozilla-beta", + "branch": "default", + "dest": "mozilla-beta", + "vcs": "hg", + "clone_upstream_url": "https://hg.mozilla.org/mozilla-unified", + }, + "vcs_share_base": "/builds/hg-shared", + "push_dest": "ssh://hg.mozilla.org/releases/mozilla-beta", + "ignore_no_changes": True, + "ssh_user": "ffxbld", + "ssh_key": "~/.ssh/ffxbld_rsa", + "ship_it_root": "https://ship-it.mozilla.org", + "ship_it_username": "ship_it-ffxbld", +}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/releases/postrelease_firefox_esr52.py @@ -0,0 +1,22 @@ +config = { + "log_name": "bump_esr52", + "version_files": [ + {"file": "browser/config/version.txt"}, + {"file": "browser/config/version_display.txt"}, + {"file": "config/milestone.txt"}, + ], + "repo": { + "repo": "https://hg.mozilla.org/releases/mozilla-esr52", + "branch": "default", + "dest": "mozilla-esr52", + "vcs": "hg", + "clone_upstream_url": "https://hg.mozilla.org/mozilla-unified", + }, + "vcs_share_base": "/builds/hg-shared", + "push_dest": "ssh://hg.mozilla.org/releases/mozilla-esr52", + "ignore_no_changes": True, + "ssh_user": "ffxbld", + "ssh_key": "~/.ssh/ffxbld_rsa", + "ship_it_root": "https://ship-it.mozilla.org", + "ship_it_username": "ship_it-ffxbld", +}
new file mode 100644 --- /dev/null +++ b/testing/mozharness/configs/releases/postrelease_firefox_release.py @@ -0,0 +1,22 @@ +config = { + "log_name": "bump_release", + "version_files": [ + {"file": "browser/config/version.txt"}, + {"file": "browser/config/version_display.txt"}, + {"file": "config/milestone.txt"}, + ], + "repo": { + "repo": "https://hg.mozilla.org/releases/mozilla-release", + "branch": "default", + "dest": "mozilla-release", + "vcs": "hg", + "clone_upstream_url": "https://hg.mozilla.org/mozilla-unified", + }, + "vcs_share_base": "/builds/hg-shared", + "push_dest": "ssh://hg.mozilla.org/releases/mozilla-release", + "ignore_no_changes": True, + "ssh_user": "ffxbld", + "ssh_key": "~/.ssh/ffxbld_rsa", + "ship_it_root": "https://ship-it.mozilla.org", + "ship_it_username": "ship_it-ffxbld", +}
new file mode 100755 --- /dev/null +++ b/testing/mozharness/scripts/release/beet_mover.py @@ -0,0 +1,378 @@ +#!/usr/bin/env python +# ***** BEGIN LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# ***** END LICENSE BLOCK ***** +"""beet_mover.py. + +downloads artifacts, scans them and uploads them to s3 +""" +import hashlib +import sys +import os +import pprint +import re +from os import listdir +from os.path import isfile, join +import sh +import redo + +sys.path.insert(1, os.path.dirname(os.path.dirname(sys.path[0]))) +from mozharness.base.log import FATAL +from mozharness.base.python import VirtualenvMixin +from mozharness.base.script import BaseScript +from mozharness.mozilla.aws import pop_aws_auth_from_env +import mozharness +import mimetypes + + +def get_hash(content, hash_type="md5"): + h = hashlib.new(hash_type) + h.update(content) + return h.hexdigest() + + +CONFIG_OPTIONS = [ + [["--template"], { + "dest": "template", + "help": "Specify jinja2 template file", + }], + [['--locale', ], { + "action": "extend", + "dest": "locales", + "type": "string", + "help": "Specify the locale(s) to upload."}], + [["--platform"], { + "dest": "platform", + "help": "Specify the platform of the build", + }], + [["--version"], { + "dest": "version", + "help": "full release version based on gecko and tag/stage identifier. e.g. '44.0b1'" + }], + [["--app-version"], { + "dest": "app_version", + "help": "numbered version based on gecko. e.g. '44.0'" + }], + [["--partial-version"], { + "dest": "partial_version", + "help": "the partial version the mar is based off of" + }], + [["--artifact-subdir"], { + "dest": "artifact_subdir", + "default": 'build', + "help": "subdir location for taskcluster artifacts after public/ base.", + }], + [["--build-num"], { + "dest": "build_num", + "help": "the release build identifier" + }], + [["--taskid"], { + "dest": "taskid", + "help": "taskcluster task id to download artifacts from", + }], + [["--bucket"], { + "dest": "bucket", + "help": "s3 bucket to move beets to.", + }], + [["--product"], { + "dest": "product", + "help": "product for which artifacts are beetmoved", + }], + [["--exclude"], { + "dest": "excludes", + "action": "append", + "help": "List of filename patterns to exclude. See script source for default", + }], + [["-s", "--scan-parallelization"], { + "dest": "scan_parallelization", + "default": 4, + "type": "int", + "help": "Number of concurrent file scans", + }], +] + +DEFAULT_EXCLUDES = [ + r"^.*tests.*$", + r"^.*crashreporter.*$", + r"^.*\.zip(\.asc)?$", + r"^.*\.log$", + r"^.*\.txt$", + r"^.*\.asc$", + r"^.*/partner-repacks.*$", + r"^.*.checksums(\.asc)?$", + r"^.*/logs/.*$", + r"^.*json$", + r"^.*/host.*$", + r"^.*/mar-tools/.*$", + r"^.*robocop.apk$", + r"^.*contrib.*" +] +CACHE_DIR = 'cache' + +MIME_MAP = { + '': 'text/plain', + '.asc': 'text/plain', + '.beet': 'text/plain', + '.bundle': 'application/octet-stream', + '.bz2': 'application/octet-stream', + '.checksums': 'text/plain', + '.dmg': 'application/x-iso9660-image', + '.mar': 'application/octet-stream', + '.xpi': 'application/x-xpinstall' +} + +HASH_FORMATS = ["sha512", "sha256"] + + +class BeetMover(BaseScript, VirtualenvMixin, object): + def __init__(self, aws_creds): + beetmover_kwargs = { + 'config_options': CONFIG_OPTIONS, + 'all_actions': [ + # 'clobber', + 'create-virtualenv', + 'activate-virtualenv', + 'generate-candidates-manifest', + 'refresh-antivirus', + 'verify-bits', # beets + 'download-bits', # beets + 'scan-bits', # beets + 'upload-bits', # beets + ], + 'require_config_file': False, + # Default configuration + 'config': { + # base index url where to find taskcluster artifact based on taskid + "artifact_base_url": \ + 'https://queue.taskcluster.net/v1/task/{taskid}/artifacts/public/{subdir}', + "virtualenv_modules": [ + "boto", + "PyYAML", + "Jinja2", + "redo", + "cryptography==2.0.3", + "mar", + ], + "virtualenv_path": "venv", + }, + } + # todo do excludes need to be configured via command line for specific builds? + super(BeetMover, self).__init__(**beetmover_kwargs) + + c = self.config + self.manifest = {} + # assigned in _post_create_virtualenv + self.virtualenv_imports = None + self.bucket = c['bucket'] + if not all(aws_creds): + self.fatal('credentials must be passed in env: ' + '"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"') + self.aws_key_id, self.aws_secret_key = aws_creds + # if excludes is set from command line, use it otherwise use defaults + self.excludes = self.config.get('excludes', DEFAULT_EXCLUDES) + dirs = self.query_abs_dirs() + self.dest_dir = os.path.join(dirs['abs_work_dir'], CACHE_DIR) + self.mime_fix() + + def activate_virtualenv(self): + """ + activates virtualenv and adds module imports to a instance wide namespace. + + creating and activating a virtualenv onto the currently executing python interpreter is a + bit black magic. Rather than having import statements added in various places within the + script, we import them here immediately after we activate the newly created virtualenv + """ + VirtualenvMixin.activate_virtualenv(self) + + import boto + import yaml + import jinja2 + self.virtualenv_imports = { + 'boto': boto, + 'yaml': yaml, + 'jinja2': jinja2, + } + self.log("activated virtualenv with the modules: {}".format(str(self.virtualenv_imports))) + + def _get_template_vars(self): + return { + "platform": self.config['platform'], + "locales": self.config.get('locales'), + "version": self.config['version'], + "app_version": self.config.get('app_version', ''), + "partial_version": self.config.get('partial_version', ''), + "build_num": self.config['build_num'], + # keep the trailing slash + "s3_prefix": 'pub/{prod}/candidates/{ver}-candidates/{n}/'.format( + prod=self.config['product'], ver=self.config['version'], + n=self.config['build_num'] + ), + "artifact_base_url": self.config['artifact_base_url'].format( + taskid=self.config['taskid'], subdir=self.config['artifact_subdir'] + ) + } + + def generate_candidates_manifest(self): + """ + generates and outputs a manifest that maps expected Taskcluster artifact names + to release deliverable names + """ + self.log('generating manifest from {}...'.format(self.config['template'])) + template_dir, template_file = os.path.split(os.path.abspath(self.config['template'])) + jinja2 = self.virtualenv_imports['jinja2'] + yaml = self.virtualenv_imports['yaml'] + + jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir), + undefined=jinja2.StrictUndefined) + template = jinja_env.get_template(template_file) + self.manifest = yaml.safe_load(template.render(**self._get_template_vars())) + + self.log("manifest generated:") + self.log(pprint.pformat(self.manifest['mapping'])) + + def verify_bits(self): + """ + inspects each artifact and verifies that they were created by trustworthy tasks + """ + # TODO + self.log('skipping verification. unimplemented...') + + def refresh_antivirus(self): + self.info("Refreshing clamav db...") + try: + redo.retry(lambda: + sh.freshclam("--stdout", "--verbose", _timeout=300, + _err_to_out=True)) + self.info("Done.") + except sh.ErrorReturnCode: + self.warning("Freshclam failed, skipping DB update") + + def download_bits(self): + """ + downloads list of artifacts to self.dest_dir dir based on a given manifest + """ + self.log('downloading and uploading artifacts to self_dest_dir...') + dirs = self.query_abs_dirs() + + for locale in self.manifest['mapping']: + for deliverable in self.manifest['mapping'][locale]: + self.log("downloading '{}' deliverable for '{}' locale".format(deliverable, + locale)) + source = self.manifest['mapping'][locale][deliverable]['artifact'] + self.retry( + self.download_file, + args=[source], + kwargs={'parent_dir': dirs['abs_work_dir']}, + error_level=FATAL) + self.log('Success!') + + def _strip_prefix(self, s3_key): + """Return file name relative to prefix""" + # "abc/def/hfg".split("abc/de")[-1] == "f/hfg" + return s3_key.split(self._get_template_vars()["s3_prefix"])[-1] + + def upload_bits(self): + """ + uploads list of artifacts to s3 candidates dir based on a given manifest + """ + self.log('uploading artifacts to s3...') + dirs = self.query_abs_dirs() + + # connect to s3 + boto = self.virtualenv_imports['boto'] + conn = boto.connect_s3(self.aws_key_id, self.aws_secret_key) + bucket = conn.get_bucket(self.bucket) + + for locale in self.manifest['mapping']: + for deliverable in self.manifest['mapping'][locale]: + self.log("uploading '{}' deliverable for '{}' locale".format(deliverable, locale)) + # we have already downloaded the files locally so we can use that version + source = self.manifest['mapping'][locale][deliverable]['artifact'] + s3_key = self.manifest['mapping'][locale][deliverable]['s3_key'] + downloaded_file = os.path.join(dirs['abs_work_dir'], + self.get_filename_from_url(source)) + # generate checksums for every uploaded file + beet_file_name = '{}.beet'.format(downloaded_file) + # upload checksums to a separate subdirectory + beet_dest = '{prefix}beetmover-checksums/{f}.beet'.format( + prefix=self._get_template_vars()["s3_prefix"], + f=self._strip_prefix(s3_key) + ) + beet_contents = '\n'.join([ + '{hash} {fmt} {size} {name}'.format( + hash=self.get_hash_for_file(downloaded_file, hash_type=fmt), + fmt=fmt, + size=os.path.getsize(downloaded_file), + name=self._strip_prefix(s3_key)) for fmt in HASH_FORMATS + ]) + self.write_to_file(beet_file_name, beet_contents) + self.upload_bit(source=downloaded_file, s3_key=s3_key, + bucket=bucket) + self.upload_bit(source=beet_file_name, s3_key=beet_dest, + bucket=bucket) + self.log('Success!') + + def upload_bit(self, source, s3_key, bucket): + boto = self.virtualenv_imports['boto'] + self.info('uploading to s3 with key: {}'.format(s3_key)) + key = boto.s3.key.Key(bucket) # create new key + key.key = s3_key # set key name + + self.info("Checking if `{}` already exists".format(s3_key)) + key = bucket.get_key(s3_key) + if not key: + self.info("Uploading to `{}`".format(s3_key)) + key = bucket.new_key(s3_key) + # set key value + mime_type, _ = mimetypes.guess_type(source) + self.retry(lambda: key.set_contents_from_filename( + source, headers={'Content-Type': mime_type}), error_level=FATAL), + else: + if not get_hash(key.get_contents_as_string()) == get_hash(open(source).read()): + # for now, let's halt. If necessary, we can revisit this and allow for overwrites + # to the same buildnum release with different bits + self.fatal("`{}` already exists with different checksum.".format(s3_key)) + self.log("`{}` has the same MD5 checksum, not uploading".format(s3_key)) + + def scan_bits(self): + + dirs = self.query_abs_dirs() + + filenames = [f for f in listdir(dirs['abs_work_dir']) + if isfile(join(dirs['abs_work_dir'], f))] + self.mkdir_p(self.dest_dir) + for file_name in filenames: + if self._matches_exclude(file_name): + self.info("Excluding {} from virus scan".format(file_name)) + else: + self.info('Copying {} to {}'.format(file_name, self.dest_dir)) + self.copyfile(os.path.join(dirs['abs_work_dir'], file_name), + os.path.join(self.dest_dir, file_name)) + self._scan_files() + self.info('Emptying {}'.format(self.dest_dir)) + self.rmtree(self.dest_dir) + + def _scan_files(self): + """Scan the files we've collected. We do the download and scan concurrently to make + it easier to have a coherent log afterwards. Uses the venv python.""" + external_tools_path = os.path.join(os.path.abspath(os.path.dirname( + os.path.dirname(mozharness.__file__))), 'external_tools') + self.run_command([self.query_python_path(), os.path.join(external_tools_path, + 'extract_and_run_command.py'), + '-j{}'.format(self.config['scan_parallelization']), + 'clamscan', '--no-summary', '--', self.dest_dir]) + + def _matches_exclude(self, keyname): + return any(re.search(exclude, keyname) for exclude in self.excludes) + + def mime_fix(self): + """ Add mimetypes for custom extensions """ + mimetypes.init() + map(lambda (ext, mime_type,): mimetypes.add_type(mime_type, ext), MIME_MAP.items()) + + +if __name__ == '__main__': + beet_mover = BeetMover(pop_aws_auth_from_env()) + beet_mover.run_and_exit()
new file mode 100644 --- /dev/null +++ b/testing/mozharness/scripts/release/postrelease_bouncer_aliases.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# lint_ignore=E501 +# ***** BEGIN LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# ***** END LICENSE BLOCK ***** +""" postrelease_bouncer_aliases.py + +A script to replace the old-fashion way of updating the bouncer aliaes through +tools script. +""" + +import os +import sys + +sys.path.insert(1, os.path.dirname(os.path.dirname(sys.path[0]))) + +from mozharness.base.python import VirtualenvMixin, virtualenv_config_options +from mozharness.base.script import BaseScript +from mozharness.mozilla.buildbot import BuildbotMixin + + +# PostReleaseBouncerAliases {{{1 +class PostReleaseBouncerAliases(BaseScript, VirtualenvMixin, BuildbotMixin): + config_options = virtualenv_config_options + + def __init__(self, require_config_file=True): + super(PostReleaseBouncerAliases, self).__init__( + config_options=self.config_options, + require_config_file=require_config_file, + config={ + "virtualenv_modules": [ + "redo", + "requests", + ], + "virtualenv_path": "venv", + 'credentials_file': 'oauth.txt', + 'buildbot_json_path': 'buildprops.json', + }, + all_actions=[ + "create-virtualenv", + "activate-virtualenv", + "update-bouncer-aliases", + ], + default_actions=[ + "create-virtualenv", + "activate-virtualenv", + "update-bouncer-aliases", + ], + ) + + def _pre_config_lock(self, rw_config): + super(PostReleaseBouncerAliases, self)._pre_config_lock(rw_config) + # override properties from buildbot properties here as defined by + # taskcluster properties + self.read_buildbot_config() + if not self.buildbot_config: + self.warning("Skipping buildbot properties overrides") + return + props = self.buildbot_config["properties"] + for prop in ['tuxedo_server_url', 'version']: + if props.get(prop): + self.info("Overriding %s with %s" % (prop, props[prop])) + self.config[prop] = props.get(prop) + else: + self.warning("%s could not be found within buildprops" % prop) + return + + def _update_bouncer_alias(self, tuxedo_server_url, auth, + related_product, alias): + from redo import retry + import requests + + url = "%s/create_update_alias" % tuxedo_server_url + data = {"alias": alias, "related_product": related_product} + self.log("Updating {} to point to {} using {}".format(alias, + related_product, + url)) + + # Wrap the real call to hide credentials from retry's logging + def do_update_bouncer_alias(): + r = requests.post(url, data=data, auth=auth, + verify=False, timeout=60) + r.raise_for_status() + + retry(do_update_bouncer_alias) + + def update_bouncer_aliases(self): + tuxedo_server_url = self.config['tuxedo_server_url'] + credentials_file = os.path.join(os.getcwd(), + self.config['credentials_file']) + credentials = {} + execfile(credentials_file, credentials) + auth = (credentials['tuxedoUsername'], credentials['tuxedoPassword']) + version = self.config['version'] + for product, info in self.config["products"].iteritems(): + if "alias" in info: + product_template = info["product-name"] + related_product = product_template % {"version": version} + self._update_bouncer_alias(tuxedo_server_url, auth, + related_product, info["alias"]) + + +# __main__ {{{1 +if __name__ == '__main__': + PostReleaseBouncerAliases().run_and_exit()
new file mode 100644 --- /dev/null +++ b/testing/mozharness/scripts/release/postrelease_mark_as_shipped.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# lint_ignore=E501 +# ***** BEGIN LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# ***** END LICENSE BLOCK ***** +""" postrelease_mark_as_shipped.py + +A script to automate the manual way of updating a release as shipped in Ship-it +following its successful ship-to-the-door opertion. +""" +import os +import sys +from datetime import datetime + +sys.path.insert(1, os.path.dirname(os.path.dirname(sys.path[0]))) + +from mozharness.base.python import VirtualenvMixin, virtualenv_config_options +from mozharness.base.script import BaseScript +from mozharness.mozilla.buildbot import BuildbotMixin + + +def build_release_name(product, version, buildno): + """Function to reconstruct the name of the release based on product, + version and buildnumber + """ + return "{}-{}-build{}".format(product.capitalize(), + str(version), str(buildno)) + + +class MarkReleaseAsShipped(BaseScript, VirtualenvMixin, BuildbotMixin): + config_options = virtualenv_config_options + + def __init__(self, require_config_file=True): + super(MarkReleaseAsShipped, self).__init__( + config_options=self.config_options, + require_config_file=require_config_file, + config={ + "virtualenv_modules": [ + "shipitapi", + ], + "virtualenv_path": "venv", + "credentials_file": "oauth.txt", + "buildbot_json_path": "buildprops.json", + "timeout": 60, + }, + all_actions=[ + "create-virtualenv", + "activate-virtualenv", + "mark-as-shipped", + ], + default_actions=[ + "create-virtualenv", + "activate-virtualenv", + "mark-as-shipped", + ], + ) + + def _pre_config_lock(self, rw_config): + super(MarkReleaseAsShipped, self)._pre_config_lock(rw_config) + # override properties from buildbot properties here as defined by + # taskcluster properties + self.read_buildbot_config() + if not self.buildbot_config: + self.warning("Skipping buildbot properties overrides") + return + props = self.buildbot_config['properties'] + mandatory_props = ['product', 'version', 'build_number'] + missing_props = [] + for prop in mandatory_props: + if prop in props: + self.info("Overriding %s with %s" % (prop, props[prop])) + self.config[prop] = props.get(prop) + else: + self.warning("%s could not be found within buildprops" % prop) + missing_props.append(prop) + + if missing_props: + raise Exception("%s not found in configs" % missing_props) + + self.config['name'] = build_release_name(self.config['product'], + self.config['version'], + self.config['build_number']) + + def mark_as_shipped(self): + """Method to make a simple call to Ship-it API to change a release + status to 'shipped' + """ + credentials_file = os.path.join(os.getcwd(), + self.config["credentials_file"]) + credentials = {} + execfile(credentials_file, credentials) + ship_it_credentials = credentials["ship_it_credentials"] + auth = (self.config["ship_it_username"], + ship_it_credentials.get(self.config["ship_it_username"])) + api_root = self.config['ship_it_root'] + + from shipitapi import Release + release_api = Release(auth, api_root=api_root, + timeout=self.config['timeout']) + shipped_at = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') + + self.info("Mark the release as shipped with %s timestamp" % shipped_at) + release_api.update(self.config['name'], + status='shipped', shippedAt=shipped_at) + + +if __name__ == '__main__': + MarkReleaseAsShipped().run_and_exit()
new file mode 100644 --- /dev/null +++ b/testing/mozharness/scripts/release/postrelease_version_bump.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python +# lint_ignore=E501 +# ***** BEGIN LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# ***** END LICENSE BLOCK ***** +""" postrelease_version_bump.py + +A script to increase in-tree version number after shipping a release. +""" + +from distutils.version import StrictVersion +import os +import sys + +sys.path.insert(1, os.path.dirname(os.path.dirname(sys.path[0]))) +from mozharness.base.vcs.vcsbase import MercurialScript +from mozharness.base.vcs.mercurial import MercurialVCS +from mozharness.mozilla.buildbot import BuildbotMixin +from mozharness.mozilla.repo_manipulation import MercurialRepoManipulationMixin + + +# PostReleaseVersionBump {{{1 +class PostReleaseVersionBump(MercurialScript, BuildbotMixin, + MercurialRepoManipulationMixin): + config_options = [ + [['--hg-user', ], { + "action": "store", + "dest": "hg_user", + "type": "string", + "default": "ffxbld <release@mozilla.com>", + "help": "Specify what user to use to commit to hg.", + }], + [['--next-version', ], { + "action": "store", + "dest": "next_version", + "type": "string", + "help": "Next version used in version bump", + }], + [['--ssh-user', ], { + "action": "store", + "dest": "ssh_user", + "type": "string", + "help": "SSH username with hg.mozilla.org permissions", + }], + [['--ssh-key', ], { + "action": "store", + "dest": "ssh_key", + "type": "string", + "help": "Path to SSH key.", + }], + [['--product', ], { + "action": "store", + "dest": "product", + "type": "string", + "help": "Product name", + }], + [['--version', ], { + "action": "store", + "dest": "version", + "type": "string", + "help": "Version", + }], + [['--build-number', ], { + "action": "store", + "dest": "build_number", + "type": "string", + "help": "Build number", + }], + [['--revision', ], { + "action": "store", + "dest": "revision", + "type": "string", + "help": "HG revision to tag", + }], + ] + + def __init__(self, require_config_file=True): + super(PostReleaseVersionBump, self).__init__( + config_options=self.config_options, + all_actions=[ + 'clobber', + 'clean-repos', + 'pull', + 'bump_postrelease', + 'commit-changes', + 'tag', + 'push', + ], + default_actions=[ + 'clean-repos', + 'pull', + 'bump_postrelease', + 'commit-changes', + 'tag', + 'push', + ], + config={ + 'buildbot_json_path': 'buildprops.json', + }, + require_config_file=require_config_file + ) + + def _pre_config_lock(self, rw_config): + super(PostReleaseVersionBump, self)._pre_config_lock(rw_config) + # override properties from buildbot properties here as defined by + # taskcluster properties + self.read_buildbot_config() + if not self.buildbot_config: + self.warning("Skipping buildbot properties overrides") + else: + props = self.buildbot_config["properties"] + for prop in ['next_version', 'product', 'version', 'build_number', + 'revision']: + if props.get(prop): + self.info("Overriding %s with %s" % (prop, props[prop])) + self.config[prop] = props.get(prop) + + if not self.config.get("next_version"): + self.fatal("Next version has to be set. Use --next-version or " + "pass `next_version' via buildbot properties.") + + def query_abs_dirs(self): + """ Allow for abs_from_dir and abs_to_dir + """ + if self.abs_dirs: + return self.abs_dirs + self.abs_dirs = super(PostReleaseVersionBump, self).query_abs_dirs() + self.abs_dirs["abs_gecko_dir"] = os.path.join( + self.abs_dirs['abs_work_dir'], self.config["repo"]["dest"]) + return self.abs_dirs + + def query_repos(self): + """Build a list of repos to clone.""" + return [self.config["repo"]] + + def query_commit_dirs(self): + return [self.query_abs_dirs()["abs_gecko_dir"]] + + def query_commit_message(self): + return "Automatic version bump. CLOSED TREE NO BUG a=release" + + def query_push_dirs(self): + return self.query_commit_dirs() + + def query_push_args(self, cwd): + # cwd is not used here + hg_ssh_opts = "ssh -l {user} -i {key}".format( + user=self.config["ssh_user"], + key=os.path.expanduser(self.config["ssh_key"]) + ) + return ["-e", hg_ssh_opts, "-r", "."] + + def pull(self): + dirs = self.query_abs_dirs() + # bug 1417697 - clone default first, then pull to get the revision. + # This to deal with relbranches, which don't show up in mozilla-unified. + super(PostReleaseVersionBump, self).pull( + repos=self.query_repos()) + vcs_obj = MercurialVCS(log_obj=self.log_obj, config=self.config) + vcs_obj.pull( + self.config['repo']['repo'], + dirs['abs_gecko_dir'], + update_dest=False, + revision=self.config['revision'] + ) + + def bump_postrelease(self, *args, **kwargs): + """Bump version""" + dirs = self.query_abs_dirs() + for f in self.config["version_files"]: + curr_version = ".".join(self.get_version(dirs['abs_gecko_dir'], f["file"])) + next_version = self.config['next_version'] + + if StrictVersion(next_version) < StrictVersion(curr_version): + self.warning("Version bumping skipped due to conflicting values") + continue + elif StrictVersion(next_version) == StrictVersion(curr_version): + self.info("Version bumping skipped due to unchanged values") + continue + else: + self.replace(os.path.join(dirs['abs_gecko_dir'], f["file"]), + curr_version, self.config["next_version"]) + + def check_tags(self, tag_names): + dirs = self.query_abs_dirs() + existing_tags = self.query_existing_tags(cwd=dirs['abs_gecko_dir']) + tags = [] + for tag in tag_names: + if tag in existing_tags: + if self.config['revision'] == existing_tags[tag]: + self.info( + "Tag {} already exists on revision {}. Skipping...".format( + tag, self.config['revision'] + ) + ) + continue + else: + self.warning( + "Tag {} exists on mismatched revision {}! Retagging...".format( + tag, existing_tags[tag] + ) + ) + tags.append(tag) + return tags + + def tag(self): + dirs = self.query_abs_dirs() + tags = ["{product}_{version}_BUILD{build_number}", + "{product}_{version}_RELEASE"] + tags = [t.format(product=self.config["product"].upper(), + version=self.config["version"].replace(".", "_"), + build_number=self.config["build_number"]) + for t in tags] + tags = self.check_tags(tags) + if not tags: + self.info("No unique tags to add; skipping tagging.") + return + message = "No bug - Tagging {revision} with {tags} a=release CLOSED TREE" + message = message.format( + revision=self.config["revision"], + tags=', '.join(tags)) + self.hg_tag(cwd=dirs["abs_gecko_dir"], tags=tags, + revision=self.config["revision"], message=message, + user=self.config["hg_user"], force=True) + + +# __main__ {{{1 +if __name__ == '__main__': + PostReleaseVersionBump().run_and_exit()