Example #1
0
def refresh_timestamps(task):
    ''' It refreshes the timestamps of the task. '''
    # XXX split this function
    LOG.debug("Updating timestamps of task.")

    LOG.debug("Original task: (Limit 1024 char)")
    LOG.debug(str(json.dumps(task))[:1024])

    artifacts = task['payload'].get('artifacts', {})
    for artifact, definition in artifacts.iteritems():
        definition['expires'] = taskcluster_client.fromNow('%s days' % 365)

    # https://bugzilla.mozilla.org/show_bug.cgi?id=1190660
    # TC workers create public logs which are 365 days; if the task expiration
    # date is the same or less than that we won't have logs for the task
    task['expires'] = taskcluster_client.fromNow('%s days' % (365 + 1))
    now = datetime.datetime.utcnow()
    tomorrow = now + datetime.timedelta(hours=24)
    task['created'] = taskcluster_client.stringDate(now)
    task['deadline'] = taskcluster_client.stringDate(tomorrow)

    LOG.debug("Contents of new task: (Limit 1024 char)")
    LOG.debug(str(task)[:1024])

    return task
Example #2
0
def _recreate_task(task_id):
    one_year = 365
    queue = taskcluster_client.Queue()
    task = queue.task(task_id)

    LOG.debug("Original task: (Limit 1024 char)")
    LOG.debug(str(json.dumps(task))[:1024])

    # Start updating the task
    task["taskId"] = taskcluster_client.slugId()

    artifacts = task["payload"].get("artifacts", {})
    for artifact, definition in artifacts.iteritems():
        definition["expires"] = taskcluster_client.fromNow("%s days" % one_year)

    # https://bugzilla.mozilla.org/show_bug.cgi?id=1190660
    # TC workers create public logs which are 365 days; if the task expiration
    # date is the same or less than that we won't have logs for the task
    task["expires"] = taskcluster_client.fromNow("%s days" % (one_year + 1))
    now = datetime.datetime.utcnow()
    tomorrow = now + datetime.timedelta(hours=24)
    task["created"] = taskcluster_client.stringDate(now)
    task["deadline"] = taskcluster_client.stringDate(tomorrow)

    LOG.debug("Contents of new task: (Limit 1024 char)")
    LOG.debug(str(task)[:1024])

    return task
Example #3
0
    def _craft_default_task_definition(
        self,
        worker_type,
        provisioner_id,
        name,
        description,
        payload,
        dependencies=None,
        routes=None,
        scopes=None,
        treeherder=None,
    ):
        dependencies = [] if dependencies is None else dependencies
        scopes = [] if scopes is None else scopes
        routes = [] if routes is None else routes
        treeherder = {} if treeherder is None else treeherder

        created = datetime.datetime.now()
        deadline = taskcluster.fromNow('1 day')
        expires = taskcluster.fromNow(DEFAULT_EXPIRES_IN)

        if self.trust_level == 3:
            routes.append("tc-treeherder.v2.reference-browser.{}".format(
                self.commit))

        return {
            "provisionerId": provisioner_id,
            "workerType": worker_type,
            "taskGroupId": self.task_id,
            "schedulerId": self.scheduler_id,
            "created": taskcluster.stringDate(created),
            "deadline": taskcluster.stringDate(deadline),
            "expires": taskcluster.stringDate(expires),
            "retries": 5,
            "tags": {},
            "priority": self.tasks_priority,
            "dependencies": [self.task_id] + dependencies,
            "requires": "all-completed",
            "routes": routes,
            "scopes": scopes,
            "payload": payload,
            "extra": {
                "treeherder": treeherder,
            },
            "metadata": {
                "name": "Reference-Browser - {}".format(name),
                "description": description,
                "owner": self.owner,
                "source": self.source,
            },
        }
def generate_task(name,
                  description,
                  command,
                  dependencies=[],
                  artifacts={},
                  scopes=[],
                  routes=[]):
    created = datetime.datetime.now()
    expires = taskcluster.fromNow('1 month')
    deadline = taskcluster.fromNow('1 day')

    return {
        "workerType": "b-linux",
        "taskGroupId": TASK_ID,
        "expires": taskcluster.stringDate(expires),
        "retries": 5,
        "created": taskcluster.stringDate(created),
        "tags": {},
        "priority": "lowest",
        "schedulerId": "taskcluster-github",
        "deadline": taskcluster.stringDate(deadline),
        "dependencies": [TASK_ID] + dependencies,
        "routes": routes,
        "scopes": scopes,
        "requires": "all-completed",
        "payload": {
            "features": {
                "taskclusterProxy": True
            },
            "maxRunTime":
            7200,
            "image":
            "mozillamobile/focus-android:1.6",
            "command": [
                "/bin/bash", "--login", "-c",
                "git fetch %s %s && git config advice.detachedHead false && git checkout %s && %s"
                % (REPO_URL, BRANCH, COMMIT, command)
            ],
            "artifacts":
            artifacts,
            "deadline":
            taskcluster.stringDate(deadline)
        },
        "provisionerId": "mobile-3",
        "metadata": {
            "name": name,
            "description": description,
            "owner": OWNER,
            "source": SOURCE
        }
    }
Example #5
0
def create_fxaclient_task():
    created = datetime.datetime.now()
    expires = taskcluster.fromNow('1 year')
    deadline = taskcluster.fromNow('1 day')

    return {
        "workerType": 'github-worker',
        "taskGroupId": TASK_ID,
        "expires": taskcluster.stringDate(expires),
        "retries": 5,
        "created": taskcluster.stringDate(created),
        "tags": {},
        "priority": "lowest",
        "schedulerId": "taskcluster-github",
        "deadline": taskcluster.stringDate(deadline),
        "dependencies": [TASK_ID],
        "routes": [],
        "scopes": [],
        "requires": "all-completed",
        "payload": {
            "features": {},
            "maxRunTime":
            7200,
            "image":
            "mozillamobile/rust-component:buildtools-27.0.3-ndk-r15c-ndk-version-21-rust-stable-rust-beta",
            "command": [
                "/bin/bash", "--login", "-cx",
                "export TERM=dumb && git clone %s && cd application-services && git fetch %s %s && git config advice.detachedHead false && git checkout %s && ./scripts/taskcluster-android.sh"
                % (REPO_URL, REPO_URL, BRANCH, COMMIT)
            ],
            "artifacts": {
                "public/bin/mozilla/fxa_client_android.zip": {
                    "type":
                    "file",
                    "path":
                    "/build/application-services/fxa-client/fxa_client_android.zip",
                },
            },
            "deadline":
            taskcluster.stringDate(deadline)
        },
        "provisionerId": "aws-provisioner-v1",
        "metadata": {
            "name": "application-services - FxA client library",
            "description":
            "Building FxA client Rust library and native code dependencies",
            "owner": "*****@*****.**",
            "source": "https://github.com/mozilla/application-services"
        }
    }
Example #6
0
    def build_push_task(self,
                        signing_task_id,
                        name,
                        description,
                        apks=[],
                        scopes=[],
                        channel='internal',
                        commit=False):
        created = datetime.datetime.now()
        expires = taskcluster.fromNow('1 year')
        deadline = taskcluster.fromNow('1 day')

        return {
            "workerType": 'mobile-3-pushapk',
            "taskGroupId": self.task_id,
            "schedulerId": self.scheduler_id,
            "expires": taskcluster.stringDate(expires),
            "retries": 5,
            "created": taskcluster.stringDate(created),
            "tags": {},
            "priority": "lowest",
            "deadline": taskcluster.stringDate(deadline),
            "dependencies": [self.task_id, signing_task_id],
            "routes": [],
            "scopes": scopes,
            "requires": "all-completed",
            "payload": {
                "commit":
                commit,
                "channel":
                channel,
                "upstreamArtifacts": [{
                    "paths": apks,
                    "taskId": signing_task_id,
                    "taskType": "signing"
                }]
            },
            "provisionerId": "scriptworker-k8s",
            "metadata": {
                "name":
                name,
                "description":
                description,
                "owner":
                "*****@*****.**",
                "source":
                "https://github.com/mozilla-mobile/focus-android/tree/master/tools/taskcluster"
            }
        }
    def massager_task(self,
                      name,
                      description,
                      command,
                      dependencies=[],
                      scopes=[],
                      features={},
                      artifacts={},
                      upstreamZip=[]):
        created = datetime.datetime.now()
        expires = taskcluster.fromNow('1 year')
        deadline = taskcluster.fromNow('1 day')

        return {
            "workerType": "gecko-focus",
            "taskGroupId": self.task_id,
            "expires": taskcluster.stringDate(expires),
            "retries": 5,
            "created": taskcluster.stringDate(created),
            "tags": {},
            "priority": "lowest",
            "schedulerId": "taskcluster-github",
            "deadline": taskcluster.stringDate(deadline),
            "dependencies": [self.task_id] + dependencies,
            "routes": [],
            "scopes": scopes,
            "requires": "all-completed",
            "payload": {
                "maxRunTime": 3600,
                "features": features,
                "image": "mozillamobile/android-components:1.4",
                "command": [
                    "/bin/bash",
                    "--login",
                    "-cx",
                    command,
                ],
                "artifacts": artifacts,
                "upstreamZip": upstreamZip,
                "deadline": taskcluster.stringDate(deadline)
            },
            "provisionerId": "aws-provisioner-v1",
            "metadata": {
                "name": name,
                "description": description,
                "owner": self.owner,
                "source": self.source
            }
        }
Example #8
0
    def craft_assemble_release_task(self, architectures, channel, is_staging,
                                    version_name):
        artifacts = {
            'public/target.{}.apk'.format(arch): {
                "type":
                'file',
                "path":
                '/opt/fenix/app/build/outputs/apk/'
                '{arch}/{channel}/app-{arch}-{channel}-unsigned.apk'.format(
                    arch=arch, channel=channel),
                "expires":
                taskcluster.stringDate(
                    taskcluster.fromNow(DEFAULT_EXPIRES_IN)),
            }
            for arch in architectures
        }

        if is_staging:
            secret_index = 'garbage/staging/project/mobile/fenix'
        else:
            secret_index = 'project/mobile/fenix/{}'.format(channel)

        pre_gradle_commands = (
            'python automation/taskcluster/helper/get-secret.py -s {} -k {} -f {}'
            .format(secret_index, key, target_file) for key, target_file in (
                ('sentry_dsn', '.sentry_token'),
                ('leanplum', '.leanplum_token'),
                ('adjust', '.adjust_token'),
            ))

        capitalized_channel = upper_case_first_letter(channel)
        gradle_commands = (
            './gradlew --no-daemon -PversionName={} clean test assemble{}'.
            format(version_name, capitalized_channel), )

        command = ' && '.join(cmd for commands in (pre_gradle_commands,
                                                   gradle_commands)
                              for cmd in commands if cmd)

        routes = [] if is_staging else [
            "[email protected]"
        ]

        return self._craft_build_ish_task(
            name='Build {} task'.format(capitalized_channel),
            description='Build Fenix {} from source code'.format(
                capitalized_channel),
            command=command,
            scopes=["secrets:get:{}".format(secret_index)],
            artifacts=artifacts,
            routes=routes,
            treeherder={
                'jobKind': 'build',
                'machine': {
                    'platform': 'android-all',
                },
                'symbol': '{}-A'.format(channel),
                'tier': 1,
            },
        )
Example #9
0
    def _craft_shell_task(self, name, script, scopes, artifacts):
        single_command = ' && '.join([line.strip() for line in script.split('\n') if line.strip()])
        bash_command = [
            '/bin/bash',
            '--login',
            '-cx',
            f'export TERM=dumb && {single_command}'
        ]

        return {
            'taskGroupId': self.task_group_id,
            'provisionerId': 'aws-provisioner-v1',
            'schedulerId': 'taskcluster-github',
            'workerType': 'github-worker',
            'created': taskcluster.stringDate(datetime.datetime.now()),
            'deadline': taskcluster.stringDate(taskcluster.fromNow('1 day')),
            'scopes': scopes,
            'payload': {
                'maxRunTime': 3600,
                'image': 'mozillamobile/firefox-tv:2.3',
                'command': bash_command,
                'artifacts': artifacts,
                'features': {
                    'taskclusterProxy': True,
                }
            },
            'metadata': {
                'name': name,
                'description': '',
                'owner': self.owner,
                'source': f'{self.repo_url}/raw/{self.commit}/.taskcluster.yml',
            }
        }
Example #10
0
def generate_build_task(apks, is_staging):
    artifacts = {
        'public/{}'.format(os.path.basename(apk)): {
            "type": 'file',
            "path": apk,
            "expires": taskcluster.stringDate(taskcluster.fromNow('1 year')),
        }
        for apk in apks
    }

    checkout = ("export TERM=dumb && git fetch {} {} --tags && "
                "git config advice.detachedHead false && "
                "git checkout {}".format(GITHUB_HTTP_REPOSITORY, HEAD_BRANCH,
                                         HEAD_REV))
    sentry_secret = '{}project/mobile/fenix/sentry'.format(
        'garbage/staging/' if is_staging else '')

    return taskcluster.slugId(), BUILDER.build_task(
        name="(Fenix) Build task",
        description="Build Fenix from source code.",
        command=
        (checkout + ' && python automation/taskcluster/helper/get-secret.py'
         ' -s {} -k dsn -f .sentry_token'.format(sentry_secret) +
         ' && ./gradlew --no-daemon -PcrashReports=true clean test assembleRelease'
         ),
        features={
            "chainOfTrust": True,
            "taskclusterProxy": True
        },
        artifacts=artifacts,
        scopes=["secrets:get:{}".format(sentry_secret)])
Example #11
0
def generate_ui_test_task(dependencies):
    task_name = "(Focus for Android) UI tests"
    task_description = "Run UI tests for Focus for Android."
    build_dir = "assembleFocusDebug"
    build_dir_test = "assembleFocusDebugAndroidTest"

    return taskcluster.slugId(), generate_task(
        name=task_name,
        description=task_description,
        command=('echo "--" > .adjust_token'
                 ' && ./gradlew --no-daemon clean ' + build_dir + ' ' +
                 build_dir_test + ' '
                 ' && ./tools/taskcluster/google-firebase-testlab-login.sh'
                 ' && ./tools/taskcluster/execute-firebase-tests.sh'),
        dependencies=dependencies,
        scopes=['secrets:get:project/focus/firebase'],
        routes=['notify.irc-channel.#android-ci.on-any'],
        artifacts={
            "public": {
                "type": "directory",
                "path": "/opt/focus-android/test_artifacts",
                "expires":
                taskcluster.stringDate(taskcluster.fromNow('1 week'))
            }
        })
Example #12
0
def generate_build_task(apks):
    artifacts = {
        'public/{}'.format(os.path.basename(apk)): {
            "type": 'file',
            "path": "/build/reference-browser/{}".format(apk),
            "expires": taskcluster.stringDate(taskcluster.fromNow('1 year')),
        }
        for apk in apks
    }

    checkout = 'git clone {} && cd reference-browser && git checkout {}'.format(
        GITHUB_HTTP_REPOSITORY, HEAD_REV)

    return taskcluster.slugId(), BUILDER.build_task(
        name="(Reference Browser) Build task",
        description="Build Reference Browser from source code.",
        command=
        ('cd .. && ' + checkout +
         ' && python automation/taskcluster/helper/get-secret.py'
         ' -s project/mobile/reference-browser/sentry -k dsn -f .sentry_token'
         ' && ./gradlew --no-daemon -PcrashReportEnabled=true -Ptelemetry=true clean test assembleRelease'
         ),
        features={
            "chainOfTrust": True,
            "taskclusterProxy": True
        },
        artifacts=artifacts,
        scopes=["secrets:get:project/mobile/reference-browser/sentry"])
def generate_build_task(info):
    checkout = ("export TERM=dumb && git fetch {} {} && "
                "git config advice.detachedHead false && "
                "git checkout {} ".format(REPO_URL, BRANCH, HEAD_REV))
    artifacts = {
        info["artifact"]: {
            'type': 'file',
            'expires': taskcluster.stringDate(taskcluster.fromNow('1 year')),
            'path': info['path']
        }
    }
    module_name = ":{}".format(info['name'])

    return taskcluster.slugId(), BUILDER.build_task(
        name='Android Components - Module {}'.format(module_name),
        description='Building and testing module {}'.format(module_name),
        command=(checkout + ' && ./gradlew --no-daemon clean ' +
                 "-Psnapshot " + " ".join([
                     "{}:{}".format(module_name, gradle_task)
                     for gradle_task in ['assemble', 'test', 'lint']
                 ]) + " uploadArchives zipMavenArtifacts"),
        features={
            "chainOfTrust": True,
            "taskclusterProxy": True
        },
        worker_type='gecko-focus',
        scopes=[],
        artifacts=artifacts,
    )
Example #14
0
def generate_release_task(uiTestTaskId):
    return taskcluster.slugId(), generate_task(
        name="(Focus for Android) Preview release",
        description=
        "Build preview versions for testing Focus/Klar for Android.",
        command=(
            'echo "--" > .adjust_token'
            ' && ./gradlew clean assembleBeta'
            ' && python tools/taskcluster/sign-preview-builds.py'
            ' && touch /opt/focus-android/builds/`date +"%%Y-%%m-%%d-%%-H-%%M"`'
            ' && touch /opt/focus-android/builds/' + COMMIT),
        dependencies=[uiTestTaskId],
        scopes=[
            "secrets:get:project/focus/preview-key-store",
            "queue:route:index.project.focus.android.preview-builds"
        ],
        routes=["index.project.focus.android.preview-builds"],
        artifacts={
            "public": {
                "type": "directory",
                "path": "/opt/focus-android/builds",
                "expires":
                taskcluster.stringDate(taskcluster.fromNow('1 week'))
            }
        })
Example #15
0
def test_putUrl_upload(randbytes):
    """Test that upload works with a custom sync reader factory."""
    data = randbytes(10240)  # >8k to avoid using dataInline

    uploaded_data = b''

    class Server(httptest.Handler):
        def do_PUT(self):
            nonlocal uploaded_data
            uploaded_data = self.rfile.read(len(data))
            self.send_response(200)
            self.end_headers()

    def readerFactory():
        return io.BytesIO(data)

    with httptest.Server(Server) as ts:
        objectService = FakeObject(ts)
        upload.upload(
            projectId="taskcluster",
            expires=taskcluster.fromNow('1 hour'),
            contentType="text/plain",
            contentLength=len(data),
            name="some/object",
            readerFactory=readerFactory,
            objectService=objectService)

    assert uploaded_data == data
Example #16
0
async def test_file_upload_download(objectService, tmp_path):
    src = tmp_path / "src"
    dest = tmp_path / "dest"

    data = secrets.token_bytes(102400)
    with open(src, "wb") as f:
        f.write(data)

    name = f"taskcluster/test/client-py/{taskcluster.slugid.v4()}"
    with open(src, "rb") as file:
        await upload.uploadFromFile(
            projectId="taskcluster",
            name=name,
            contentType="text/plain",
            contentLength=len(data),
            expires=taskcluster.fromNow('1 hour'),
            file=file,
            objectService=objectService)

    with open(dest, "wb") as file:
        contentType = await download.downloadToFile(
            name=name,
            file=file,
            objectService=objectService)

    with open(dest, "rb") as f:
        got = f.read()

    assert got == data
    assert contentType == 'text/plain'
Example #17
0
 def craft_dependencies_task(self):
     # Output the dependencies to an artifact.  This is used by the
     # telemetry probe scraper to determine all of the metrics that
     # Fenix might send (both from itself and any of its dependent
     # libraries that use Glean).
     return self._craft_clean_gradle_task(
         name='dependencies',
         description='Write dependencies to a build artifact',
         gradle_task=
         'app:dependencies --configuration implementation > dependencies.txt',
         treeherder={
             'jobKind': 'test',
             'machine': {
                 'platform': 'lint',
             },
             'symbol': 'dependencies',
             'tier': 1,
         },
         routes=[
             'index.project.mobile.fenix.v2.branch.master.revision.{}'.
             format(self.commit)
         ],
         artifacts={
             'public/dependencies.txt': {
                 "type":
                 'file',
                 "path":
                 '/opt/fenix/dependencies.txt',
                 "expires":
                 taskcluster.stringDate(
                     taskcluster.fromNow(DEFAULT_EXPIRES_IN)),
             }
         },
     )
async def test_putUrl_upload_fails_retried_succeeds(randbytes):
    "When a putUrl upload's PUT fails with a 500, an exception is raised"
    data = randbytes(10240)  # >8k to avoid using dataInline
    attempts = 0

    class Server(httptest.Handler):
        def do_PUT(self):
            nonlocal attempts
            attempts += 1
            if attempts > 2:
                self.send_response(200)
                self.end_headers()
            else:
                self.send_response(500)
                self.end_headers()
                self.wfile.write(b'uhoh')

    with httptest.Server(Server) as ts:
        objectService = FakeObject(ts)
        await upload.upload_from_buf(
            projectId="taskcluster",
            expires=taskcluster.fromNow('1 hour'),
            contentType="text/plain",
            contentLength=len(data),
            name="some/object",
            data=data,
            objectService=objectService)

    assert attempts == 3
Example #19
0
    def craft_build_task(self, module_name, gradle_tasks, subtitle='', run_coverage=False,
                         is_snapshot=False, component=None, artifacts=None, timestamp=None):
        taskcluster_artifacts = {}
        # component is not None when this is a release build, in which case artifacts is defined too
        if component is not None:
            taskcluster_artifacts = {
                artifact['taskcluster_path']: {
                    'type': 'file',
                    'expires': taskcluster.stringDate(taskcluster.fromNow(DEFAULT_EXPIRES_IN)),
                    'path': artifact['build_fs_path'],
                } for artifact in artifacts
            }

        scopes = [
            "secrets:get:project/mobile/android-components/public-tokens"
        ] if run_coverage else []

        snapshot_flag = '-Psnapshot -Ptimestamp={} '.format(timestamp) if is_snapshot else ''
        coverage_flag = '-Pcoverage ' if run_coverage else ''
        gradle_command = (
            './gradlew --no-daemon clean ' + coverage_flag + snapshot_flag + gradle_tasks
        )

        post_gradle_command = 'automation/taskcluster/action/upload_coverage_report.sh' if run_coverage else ''

        command = ' && '.join(cmd for cmd in (gradle_command, post_gradle_command) if cmd)

        return self._craft_build_ish_task(
            name='Android Components - Module {} {}'.format(module_name, subtitle),
            description='Execute Gradle tasks for module {}'.format(module_name),
            command=command,
            scopes=scopes,
            artifacts=taskcluster_artifacts
        )
Example #20
0
def generate_build_task(apks, tag):
    artifacts = {}
    for apk in apks:
        artifact = {
            "type": 'file',
            "path": apk,
            "expires": taskcluster.stringDate(taskcluster.fromNow('1 year'))
        }
        artifacts["public/%s" % os.path.basename(apk)] = artifact

    checkout = "git fetch origin && git reset --hard origin/master" if tag is None else "git fetch origin && git checkout %s" % (tag)

    assemble_task = 'assembleNightly'

    if tag:
        # Non-tagged (nightly) builds should contain all languages
        checkout = checkout + ' && python tools/l10n/filter-release-translations.py'
        assemble_task = 'assembleRelease'


    return taskcluster.slugId(), BUILDER.build_task(
        name="(Focus for Android) Build task",
        description="Build Focus/Klar from source code.",
        command=(checkout +
                 ' && python tools/taskcluster/get-adjust-token.py'
                 ' && python tools/taskcluster/get-sentry-token.py'
                 ' && ./gradlew --no-daemon clean test ' + assemble_task),
        features = {
            "chainOfTrust": True
        },
        artifacts = artifacts,
        worker_type='gecko-focus',
        scopes=[
            "secrets:get:project/focus/tokens"
        ])
Example #21
0
    def craft_ui_tests_task(self):
        artifacts = {
            "public": {
                "type":
                "directory",
                "path":
                "/build/reference-browser/results",
                "expires":
                taskcluster.stringDate(taskcluster.fromNow(DEFAULT_EXPIRES_IN))
            }
        }

        env_vars = {
            "GOOGLE_PROJECT": "moz-reference-browser-230023",
            "GOOGLE_APPLICATION_CREDENTIALS": ".firebase_token.json"
        }

        gradle_commands = (
            './gradlew --no-daemon clean assembleDebug assembleAndroidTest', )

        test_commands = (
            'automation/taskcluster/androidTest/ui-test.sh arm -1', )

        command = ' && '.join(cmd
                              for commands in (gradle_commands, test_commands)
                              for cmd in commands if cmd)

        return self._craft_build_ish_task(
            name='UI tests',
            description='Execute Gradle tasks for UI tests',
            command=command,
            scopes=['secrets:get:project/mobile/reference-browser/firebase'],
            artifacts=artifacts,
            env_vars=env_vars,
        )
def generate_build_task(version, artifact_info, is_snapshot):
    checkout = ("export TERM=dumb && git fetch {} {} --tags && "
                "git config advice.detachedHead false && "
                "git checkout {}".format(REPO_URL, BRANCH, HEAD_REV))

    artifacts = {
        artifact_info['artifact']: {
            'type': 'file',
            'expires': taskcluster.stringDate(taskcluster.fromNow('1 year')),
            'path': artifact_info['path']
        }
    }

    snapshot_flag = '-Psnapshot ' if is_snapshot else ''
    module_name = _get_gradle_module_name(artifact_info['name'])
    gradle_tasks_for_this_module_only = ' '.join(
        '{}:{}{}'.format(module_name, gradle_task,
                         '' if is_snapshot else 'Release')
        for gradle_task in BUILD_GRADLE_TASK_NAMES)

    return taskcluster.slugId(), BUILDER.craft_build_ish_task(
        name='Android Components - Module {} ({})'.format(
            module_name, version),
        description='Building and testing module {}'.format(module_name),
        command=(checkout + ' && ./gradlew --no-daemon clean ' +
                 snapshot_flag + gradle_tasks_for_this_module_only +
                 ' uploadArchives zipMavenArtifacts'),
        features={
            'chainOfTrust': True,
        },
        scopes=[],
        artifacts=artifacts)
Example #23
0
def test_putUrl_upload_fails_retried(randbytes):
    "When a putUrl upload's PUT fails with a 500, an exception is raised"
    data = randbytes(10240)  # >8k to avoid using dataInline
    attempts = 0

    class Server(httptest.Handler):
        def do_PUT(self):
            nonlocal attempts
            attempts += 1
            self.rfile.read(len(data))
            self.send_response(500)
            self.end_headers()
            self.wfile.write(b'uhoh')

    with httptest.Server(Server) as ts:
        objectService = FakeObject(ts)
        with pytest.raises(aiohttp.ClientResponseError):
            upload.uploadFromBuf(
                projectId="taskcluster",
                expires=taskcluster.fromNow('1 hour'),
                contentType="text/plain",
                contentLength=len(data),
                name="some/object",
                data=data,
                objectService=objectService)

    assert attempts == 6  # one try plus five retries
    def craft_push_task(self,
                        signing_task_id,
                        name,
                        description,
                        is_staging,
                        apks=[],
                        scopes=[],
                        track='internal',
                        commit=False):
        created = datetime.datetime.now()
        expires = taskcluster.fromNow('1 year')
        deadline = taskcluster.fromNow('1 day')

        return {
            "workerType":
            'mobile-pushapk-dep-v1' if is_staging else 'mobile-pushapk-v1',
            "taskGroupId": self.task_id,
            "schedulerId": self.scheduler_id,
            "expires": taskcluster.stringDate(expires),
            "retries": 5,
            "created": taskcluster.stringDate(created),
            "tags": {},
            "priority": "lowest",
            "deadline": taskcluster.stringDate(deadline),
            "dependencies": [self.task_id, signing_task_id],
            "routes": [],
            "scopes": scopes,
            "requires": "all-completed",
            "payload": {
                "commit":
                commit,
                "google_play_track":
                track,
                "upstreamArtifacts": [{
                    "paths": apks,
                    "taskId": signing_task_id,
                    "taskType": "signing"
                }]
            },
            "provisionerId": "scriptworker-prov-v1",
            "metadata": {
                "name": name,
                "description": description,
                "owner": self.owner,
                "source": self.source
            }
        }
Example #25
0
    def build_task(self,
                   name,
                   description,
                   command,
                   dependencies=[],
                   artifacts={},
                   scopes=[],
                   routes=[],
                   features={},
                   worker_type='github-worker'):
        created = datetime.datetime.now()
        expires = taskcluster.fromNow('1 year')
        deadline = taskcluster.fromNow('1 day')

        features = features.copy()
        features.update({"taskclusterProxy": True})

        return {
            "workerType": worker_type,
            "taskGroupId": self.task_id,
            "expires": taskcluster.stringDate(expires),
            "retries": 5,
            "created": taskcluster.stringDate(created),
            "tags": {},
            "priority": "lowest",
            "schedulerId": "taskcluster-github",
            "deadline": taskcluster.stringDate(deadline),
            "dependencies": [self.task_id] + dependencies,
            "routes": routes,
            "scopes": scopes,
            "requires": "all-completed",
            "payload": {
                "features": features,
                "maxRunTime": 7200,
                "image": "mozillamobile/android-components:1.4",
                "command": ["/bin/bash", "--login", "-cx", command],
                "artifacts": artifacts,
                "deadline": taskcluster.stringDate(deadline)
            },
            "provisionerId": "aws-provisioner-v1",
            "metadata": {
                "name": name,
                "description": description,
                "owner": self.owner,
                "source": self.source
            }
        }
Example #26
0
    def beetmover_task(self,
                       name,
                       description,
                       version,
                       artifact_id,
                       dependencies=[],
                       upstreamArtifacts=[],
                       scopes=[],
                       worker_type='mobile-beetmover-v1',
                       is_snapshot=False):
        created = datetime.datetime.now()
        expires = taskcluster.fromNow('1 year')
        deadline = taskcluster.fromNow('1 day')

        return {
            "workerType": worker_type,
            "taskGroupId": self.task_id,
            "schedulerId": self.scheduler_id,
            "expires": taskcluster.stringDate(expires),
            "retries": 5,
            "created": taskcluster.stringDate(created),
            "tags": {},
            "priority": "lowest",
            "deadline": taskcluster.stringDate(deadline),
            "dependencies": [self.task_id] + dependencies,
            "routes": [],
            "scopes": scopes,
            "requires": "all-completed",
            "payload": {
                "maxRunTime": 600,
                "upstreamArtifacts": upstreamArtifacts,
                "releaseProperties": {
                    "appName":
                    "snapshot_components" if is_snapshot else "components",
                },
                "version":
                "{}-SNAPSHOT".format(version) if is_snapshot else version,
                "artifact_id": artifact_id
            },
            "provisionerId": "scriptworker-prov-v1",
            "metadata": {
                "name": name,
                "description": description,
                "owner": self.owner,
                "source": self.source
            }
        }
Example #27
0
    def craft_default_task_definition(self, worker_type, provisioner_id,
                                      dependencies, routes, scopes, name,
                                      description, payload, treeherder):
        created = datetime.datetime.now()
        deadline = taskcluster.fromNow('1 day')
        expires = taskcluster.fromNow(DEFAULT_EXPIRES_IN)

        return {
            "provisionerId":
            provisioner_id,
            "workerType":
            worker_type,
            "taskGroupId":
            self.task_id,
            "schedulerId":
            self.scheduler_id,
            "created":
            taskcluster.stringDate(created),
            "deadline":
            taskcluster.stringDate(deadline),
            "expires":
            taskcluster.stringDate(expires),
            "retries":
            5,
            "tags": {},
            "priority":
            self.tasks_priority,
            "dependencies": [self.task_id] + dependencies,
            "requires":
            "all-completed",
            "routes":
            ["tc-treeherder.v2.reference-browser.{}".format(self.commit)] +
            routes,
            "scopes":
            scopes,
            "payload":
            payload,
            "extra": {
                "treeherder": treeherder,
            },
            "metadata": {
                "name": name,
                "description": description,
                "owner": self.owner,
                "source": self.source,
            },
        }
Example #28
0
    def craft_assemble_release_task(self, architectures, is_staging=False):
        artifacts = {
            'public/target.{}.apk'.format(arch): {
                "type":
                'file',
                "path":
                '/opt/fenix/app/build/outputs/apk/'
                '{}Greenfield/release/app-{}-greenfield-release-unsigned.apk'.
                format(arch, arch),
                "expires":
                taskcluster.stringDate(
                    taskcluster.fromNow(DEFAULT_EXPIRES_IN)),
            }
            for arch in architectures
        }

        sentry_secret = '{}project/mobile/fenix/sentry'.format(
            'garbage/staging/' if is_staging else '')
        leanplum_secret = '{}project/mobile/fenix/leanplum'.format(
            'garbage/staging/' if is_staging else '')

        pre_gradle_commands = (
            'python automation/taskcluster/helper/get-secret.py -s {} -k {} -f {}'
            .format(secret, key, target_file) for secret, key, target_file in (
                (sentry_secret, 'dsn', '.sentry_token'),
                (leanplum_secret, 'production', '.leanplum_token'),
            ))

        gradle_commands = (
            './gradlew --no-daemon -PcrashReports=true -Ptelemetry=true clean test assembleRelease',
        )

        command = ' && '.join(cmd for commands in (pre_gradle_commands,
                                                   gradle_commands)
                              for cmd in commands if cmd)

        routes = [] if is_staging else [
            "[email protected]"
        ]

        return self._craft_build_ish_task(
            name='Build task',
            description='Build Fenix from source code',
            command=command,
            scopes=[
                "secrets:get:{}".format(secret)
                for secret in (sentry_secret, leanplum_secret)
            ],
            artifacts=artifacts,
            routes=routes,
            treeherder={
                'jobKind': 'build',
                'machine': {
                    'platform': 'android-all',
                },
                'symbol': 'NA',
                'tier': 1,
            },
        )
Example #29
0
def _craft_artifacts_from_variant(variant):
    return {
        'public/target.apk': {
            'type': 'file',
            'path': _craft_apk_full_path_from_variant(variant),
            'expires': taskcluster.stringDate(taskcluster.fromNow(DEFAULT_EXPIRES_IN)),
        }
    }
Example #30
0
def _craft_artifacts_from_variant(variant):
    return {
        DEFAULT_APK_ARTIFACT_LOCATION: {
            'type': 'file',
            'path': variant.apk_absolute_path(),
            'expires': taskcluster.stringDate(taskcluster.fromNow(DEFAULT_EXPIRES_IN)),
        }
    }
Example #31
0
def _craft_artifacts_from_variant(variant):
    return {
        apk.taskcluster_path: {
            'type': 'file',
            'path': apk.absolute_path(variant.build_type),
            'expires': taskcluster.stringDate(taskcluster.fromNow(DEFAULT_EXPIRES_IN)),
        } for apk in variant.apks
    }
Example #32
0
    def craft_signing_task(self,
                           build_task_id,
                           name,
                           description,
                           signing_format,
                           is_staging,
                           apks=[],
                           scopes=[],
                           routes=[]):
        created = datetime.datetime.now()
        expires = taskcluster.fromNow('1 year')
        deadline = taskcluster.fromNow('1 day')

        return {
            "workerType":
            'mobile-signing-dep-v1' if is_staging else 'mobile-signing-v1',
            "taskGroupId": self.task_id,
            "schedulerId": self.scheduler_id,
            "expires": taskcluster.stringDate(expires),
            "retries": 5,
            "created": taskcluster.stringDate(created),
            "tags": {},
            "priority": "lowest",
            "deadline": taskcluster.stringDate(deadline),
            "dependencies": [self.task_id, build_task_id],
            "routes": routes,
            "scopes": scopes,
            "requires": "all-completed",
            "payload": {
                "maxRunTime":
                3600,
                "upstreamArtifacts": [{
                    "paths": apks,
                    "formats": [signing_format],
                    "taskId": build_task_id,
                    "taskType": "build"
                }]
            },
            "provisionerId": "scriptworker-prov-v1",
            "metadata": {
                "name": name,
                "description": description,
                "owner": self.owner,
                "source": self.source
            }
        }
def create_task(name, description, command):
    created = datetime.datetime.now()
    expires = taskcluster.fromNow('1 year')
    deadline = taskcluster.fromNow('1 day')

    return {
        "workerType": 'github-worker',
        "taskGroupId": TASK_ID,
        "expires": taskcluster.stringDate(expires),
        "retries": 5,
        "created": taskcluster.stringDate(created),
        "tags": {},
        "priority": "lowest",
        "schedulerId": "taskcluster-github",
        "deadline": taskcluster.stringDate(deadline),
        "dependencies": [ TASK_ID ],
        "routes": [],
        "scopes": [],
        "requires": "all-completed",
        "payload": {
            "features": {},
            "maxRunTime": 7200,
            "image": "mozillamobile/mentat:1.1",
            "command": [
                "/bin/bash",
                "--login",
                "-cx",
                "export TERM=dumb && git fetch %s %s && git config advice.detachedHead false && git checkout %s && cd sdks/android/Mentat && ./gradlew --no-daemon clean %s" % (REPO_URL, BRANCH, COMMIT, command)
            ],
            "artifacts": {},
            "deadline": taskcluster.stringDate(deadline)
        },
        "provisionerId": "aws-provisioner-v1",
        "metadata": {
            "name": name,
            "description": description,
            "owner": "*****@*****.**",
            "source": "https://github.com/mozilla/mentat"
        }
    }
Example #34
0
def retrigger_task(task_id, dry_run=False):
    """ Given a task id (our uuid) we  query it and build
    a new task based on the old one which we schedule on TaskCluster.

    We don't call the rerun API since we can't rerun a task past
    its deadline, instead we create a new task with a new taskGroupId,
    expiration, creation and deadline values.

    task_id (int)  - ID that identifies a task on Taskcluster
    dry_run (bool) - Default to False. If True, it won't trigger
                     a task.

    returns - 0 for dry_run case, -1 for any failure or the task id (int)
              of a succesful retriggered task.

    http://docs.taskcluster.net/queue/api-docs/#createTask
    """
    one_year = 365
    new_task_id = 0

    try:
        queue = taskcluster_client.Queue()
        task = queue.task(task_id)

        LOG.debug("Original task: (Limit 1024 char)")
        LOG.debug(str(json.dumps(task))[:1024])
        new_task_id = taskcluster_client.slugId()

        artifacts = task['payload'].get('artifacts', {})
        for artifact, definition in artifacts.iteritems():
            definition['expires'] = taskcluster_client.fromNow('%s days' % one_year)

        # The task group will be identified by the ID of the only
        # task in the group
        task['taskGroupId'] = new_task_id
        # https://bugzilla.mozilla.org/show_bug.cgi?id=1190660
        # TC workers create public logs which are 365 days; if the task expiration
        # date is the same or less than that we won't have logs for the task
        task['expires'] = taskcluster_client.fromNow('%s days' % (one_year + 1))
        now = datetime.datetime.utcnow()
        tomorrow = now + datetime.timedelta(hours=24)
        task['created'] = taskcluster_client.stringDate(now)
        task['deadline'] = taskcluster_client.stringDate(tomorrow)

        LOG.debug("Contents of new task: (Limit 1024 char)")
        LOG.debug(str(task)[:1024])

        if not dry_run:
            LOG.info("Attempting to schedule new task with task_id: {}".format(new_task_id))
            result = queue.createTask(new_task_id, task)
            LOG.debug(json.dumps(result))
            LOG.info("{}/task-inspector/#{}".format(TASKCLUSTER_TOOLS_HOST, new_task_id))
        else:
            LOG.info("Dry-run mode: Nothing was retriggered.")

    except taskcluster_client.exceptions.TaskclusterRestFailure as e:
        traceback.print_exc()
        new_task_id = -1

    except taskcluster_client.exceptions.TaskclusterAuthFailure as e:
        # Hack until we fix it in the issue
        if str(e) == "Authorization Failed":
            LOG.error("The taskclaster client that you specified is lacking "
                      "the right set of scopes.")
            LOG.error("Run this same command with --debug and you will see "
                      "the missing scopes (the output comes from the "
                      "taskcluster python client)")
        elif str(e) == "Authentication Error":
            LOG.error("Make sure that you create permanent credentials and you "
                      "set these environment variables: TASKCLUSTER_CLIENT_ID & "
                      "TASKCLUSTER_ACCESS_TOKEN")
        new_task_id = -1

    return new_task_id
Example #35
0
 def from_now_json(self, offset):
     """
     Same as `taskcluster.fromNowJSON`, but uses the creation time of `self` for “now”.
     """
     return taskcluster.stringDate(taskcluster.fromNow(offset, dateObj=self.now))