def _VerifyPush(self, new_branch, rename_from=None, delete=False):
        """Verify that |new_branch| has been created.

    Args:
      new_branch: The new remote branch to create (or delete).
      rename_from: If set, |rename_from| is being renamed to |new_branch|.
      delete: If set, |new_branch| is being deleted.
    """
        # Pushes all operate on remote branch refs.
        new_branch = git.NormalizeRef(new_branch)

        # Calculate source and destination revisions.
        suffixes = ['', '-new-special-branch', '-old-special-branch']
        if delete:
            src_revs = [''] * len(suffixes)
        elif rename_from is not None:
            rename_from = git.NormalizeRef(rename_from)
            rename_from_tracking = git.NormalizeRemoteRef('cros', rename_from)
            src_revs = [
                '%s%s' % (rename_from_tracking, suffix) for suffix in suffixes
            ]
        else:
            src_revs = [
                CHROMITE_REVISION, SPECIAL_REVISION1, SPECIAL_REVISION2
            ]
        dest_revs = ['%s%s' % (new_branch, suffix) for suffix in suffixes]

        # Verify pushes happened correctly.
        for src_rev, dest_rev in zip(src_revs, dest_revs):
            cmd = ['push', '%s:%s' % (src_rev, dest_rev)]
            self.rc_mock.assertCommandContains(cmd)
            if rename_from is not None:
                cmd = ['push', ':%s' % (rename_from, )]
                self.rc_mock.assertCommandContains(cmd)
Exemplo n.º 2
0
    def RepairManifest(self, path, branches_by_path):
        """Reads the manifest at the given path and repairs it in memory.

    Because humans rarely read branched manifests, this function optimizes for
    code readability and explicitly sets revision on every project in the
    manifest, deleting any defaults.

    Args:
      path: Path to the manifest, relative to the manifest project root.
      branches_by_path: Dict mapping project paths to branch names.

    Returns:
      The repaired repo_manifest.Manifest object.
    """
        manifest = self._ReadManifest(path)

        # Delete the default revision if specified by original manifest.
        default = manifest.Default()
        if default.revision:
            del default.revision

        # Delete remote revisions if specified by original manifest.
        for remote in manifest.Remotes():
            if remote.revision:
                del remote.revision

        # Update all project revisions. Note we cannot call CanBranchProject and
        # related functions because they read the project remote, which may not
        # be defined in the current manifest file.
        for project in manifest.Projects():
            self._checkout.EnsureProject(project)
            path = project.Path()

            # If project path is in the dict, the project must've been branched
            if path in branches_by_path:
                project.revision = git.NormalizeRef(branches_by_path[path])

            # Otherwise, check if project is explicitly TOT.
            elif BranchMode(project) == constants.MANIFEST_ATTR_BRANCHING_TOT:
                project.revision = git.NormalizeRef('master')

            # If not, it's pinned.
            else:
                project.revision = self._checkout.GitRevision(project)

            if project.upstream:
                del project.upstream

        return manifest
Exemplo n.º 3
0
    def _IncrementVersionOnDiskForNewBranch(self, push_remote):
        """Bumps the version found in chromeos_version.sh on the new branch

    When a new branch is created, the branch component of the new branch's
    version needs to bumped.

    For example, say 'stabilize-link' is created from a the 4230.0.0 manifest.
    The new branch's version needs to be bumped to 4230.1.0.

    Args:
      push_remote: a git remote name where the new branch lives.
    """
        # This needs to happen before the source branch version bumping above
        # because we rely on the fact that since our current overlay checkout
        # is what we just pushed to the new branch, we don't need to do another
        # sync.  This also makes it easier to implement skip_remote_push
        # functionality (the new branch doesn't actually get created in
        # skip_remote_push mode).

        # Use local branch ref.
        branch_ref = git.NormalizeRef(self.branch_name)
        push_to = git.RemoteRef(push_remote, branch_ref)
        version_info = manifest_version.VersionInfo(
            version_string=self._run.options.force_version)
        incr_type, incr_target = self.DetermineBranchIncrParams(version_info)
        message = self.COMMIT_MESSAGE % {
            'target': incr_target,
            'branch': branch_ref,
        }
        self._IncrementVersionOnDisk(incr_type, push_to, message)
Exemplo n.º 4
0
    def _FixUpManifests(self, repo_manifest):
        """Points the checkouts at the new branch in the manifests.

    Within the branch, make sure all manifests with projects that are
    "branchable" are checked out to "refs/heads/<new_branch>".  Do this
    by updating all manifests in the known manifest projects.
    """
        assert not self._run.options.delete_branch, 'Cannot fix a deleted branch.'

        # Use local branch ref.
        branch_ref = git.NormalizeRef(self.branch_name)

        logging.debug('Fixing manifest projects for new branch.')
        for project in site_config.params.MANIFEST_PROJECTS:
            manifest_checkout = repo_manifest.FindCheckout(project)
            manifest_dir = manifest_checkout['local_path']
            push_remote = manifest_checkout['push_remote']

            # Checkout revision can be either a sha1 or a branch ref.
            src_ref = manifest_checkout['revision']
            if not git.IsSHA1(src_ref):
                src_ref = git.NormalizeRemoteRef(push_remote, src_ref)

            git.CreateBranch(manifest_dir, manifest_version.PUSH_BRANCH,
                             src_ref)

            # We want to process default.xml and official.xml + their imports.
            pending_manifests = [
                constants.DEFAULT_MANIFEST, constants.OFFICIAL_MANIFEST
            ]
            processed_manifests = []

            while pending_manifests:
                # Canonicalize the manifest name (resolve dir and symlinks).
                manifest_path = os.path.join(manifest_dir,
                                             pending_manifests.pop())
                manifest_path = os.path.realpath(manifest_path)

                # Don't process a manifest more than once.
                if manifest_path in processed_manifests:
                    continue

                processed_manifests.append(manifest_path)

                if not os.path.exists(manifest_path):
                    logging.info('Manifest not found: %s', manifest_path)
                    continue

                logging.debug('Fixing manifest at %s.', manifest_path)
                included_manifests = self._UpdateManifest(manifest_path)
                pending_manifests += included_manifests

            git.RunGit(manifest_dir, ['add', '-A'], print_cmd=True)
            message = 'Fix up manifest after branching %s.' % branch_ref
            git.RunGit(manifest_dir, ['commit', '-m', message], print_cmd=True)
            push_to = git.RemoteRef(push_remote, branch_ref)
            git.GitPush(manifest_dir,
                        manifest_version.PUSH_BRANCH,
                        push_to,
                        skip=self.skip_remote_push)
Exemplo n.º 5
0
    def _UpdateManifest(self, manifest_path):
        """Rewrite |manifest_path| to point at the right branch.

    Args:
      manifest_path: The path to the manifest file.
    """
        src_manifest = git.ManifestCheckout.Cached(self._build_root,
                                                   manifest_path=manifest_path)
        doc = ElementTree.parse(manifest_path)
        root = doc.getroot()

        # Use the local branch ref.
        new_branch_name = self.rename_to if self.rename_to else self.branch_name
        new_branch_name = git.NormalizeRef(new_branch_name)

        logging.info('Updating manifest for %s', new_branch_name)

        default_nodes = root.findall('default')
        for node in default_nodes:
            node.attrib['revision'] = new_branch_name

        for node in root.findall('project'):
            path = node.attrib['path']
            checkout = src_manifest.FindCheckoutFromPath(path)

            if checkout.IsBranchableProject():
                # Point at the new branch.
                node.attrib.pop('revision', None)
                node.attrib.pop('upstream', None)
                suffix = self._GetBranchSuffix(src_manifest, checkout)
                if suffix:
                    node.attrib['revision'] = '%s%s' % (new_branch_name,
                                                        suffix)
                    logging.info('Pointing project %s at: %s',
                                 node.attrib['name'], node.attrib['revision'])
                elif not default_nodes:
                    # If there isn't a default node we have to add the revision directly.
                    node.attrib['revision'] = new_branch_name
            else:
                if checkout.IsPinnableProject():
                    git_repo = checkout.GetPath(absolute=True)
                    repo_head = git.GetGitRepoRevision(git_repo)
                    node.attrib['revision'] = repo_head
                    logging.info('Pinning project %s at: %s',
                                 node.attrib['name'], node.attrib['revision'])
                else:
                    logging.info('Updating project %s', node.attrib['name'])
                    # We can't branch this repository. Leave it alone.
                    node.attrib['revision'] = checkout['revision']
                    logging.info('Project %s UNPINNED using: %s',
                                 node.attrib['name'], node.attrib['revision'])

                # Can not use the default version of get() here since
                # 'upstream' can be a valid key with a None value.
                upstream = checkout.get('upstream')
                if upstream is not None:
                    node.attrib['upstream'] = upstream

        doc.write(manifest_path)
        return [node.attrib['name'] for node in root.findall('include')]
Exemplo n.º 6
0
    def BumpVersion(self, which, branch, message, dry_run=True, fetch=False):
        """Increment version in chromeos_version.sh and commit it.

    Args:
      which: Which version should be incremented. One of
          'chrome_branch', 'build', 'branch, 'patch'.
      branch: The branch to push to.
      message: The commit message for the version bump.
      dry_run: Whether to use git --dry-run.
      fetch: Whether to fetch and checkout to the given branch.
    """
        logging.notice(message)

        chromiumos_overlay = self.manifest.GetUniqueProject(
            'chromiumos/overlays/chromiumos-overlay')
        remote = chromiumos_overlay.Remote().GitName()
        ref = git.NormalizeRef(branch)

        if fetch:
            self.RunGit(chromiumos_overlay, ['fetch', remote, ref])
            self.RunGit(chromiumos_overlay,
                        ['checkout', '-B', branch, 'FETCH_HEAD'])

        new_version = self.ReadVersion(incr_type=which)
        new_version.IncrementVersion()
        remote_ref = git.RemoteRef(remote, ref)
        new_version.UpdateVersionFile(message,
                                      dry_run=dry_run,
                                      push_to=remote_ref)
Exemplo n.º 7
0
    def _IncrementVersionOnDiskForSourceBranch(self, overlay_dir, push_remote,
                                               source_branch):
        """Bumps the version found in chromeos_version.sh on the source branch

    The source branch refers to the branch that the manifest used for creating
    the new branch came from.  For release branches, we generally branch from a
    'master' branch manifest.

    To work around crbug.com/213075, for both non-release and release branches,
    we need to bump the Chrome OS version on the source branch if the manifest
    used for branch creation is the latest generated manifest for the source
    branch.

    When we are creating a release branch, the Chrome major version of the
    'master' (source) branch needs to be bumped.  For example, if we branch
    'release-R29-4230.B' from the 4230.0.0 manifest (which is from the 'master'
    branch), the 'master' branch's Chrome major version in chromeos_version.sh
    (which is 29) needs to be bumped to 30.

    Args:
      overlay_dir: Absolute path to the chromiumos overlay repo.
      push_remote: The remote to push to.
      source_branch: The branch that the manifest we are using comes from.
    """
        push_to = git.RemoteRef(push_remote, source_branch)
        self._FetchAndCheckoutTo(overlay_dir, push_to)

        # Use local branch ref.
        branch_ref = git.NormalizeRef(self.branch_name)
        tot_version_info = manifest_version.VersionInfo.from_repo(
            self._build_root)
        if (branch_ref.startswith('refs/heads/release-')
                or tot_version_info.VersionString()
                == self._run.options.force_version):
            incr_type, incr_target = self.DetermineSourceIncrParams(
                source_branch, branch_ref)
            message = self.COMMIT_MESSAGE % {
                'target': incr_target,
                'branch': branch_ref,
            }
            try:
                self._IncrementVersionOnDisk(incr_type, push_to, message)
            except cros_build_lib.RunCommandError:
                # There's a chance we are racing against the buildbots for this
                # increment.  We shouldn't quit the script because of this.  Instead, we
                # print a warning.
                self._FetchAndCheckoutTo(overlay_dir, push_to)
                new_version = manifest_version.VersionInfo.from_repo(
                    self._build_root)
                if new_version.VersionString(
                ) != tot_version_info.VersionString():
                    logging.warning(
                        'Version number for branch %s was bumped by another '
                        'bot.', push_to.ref)
                else:
                    raise
Exemplo n.º 8
0
    def _DeleteBranchesOnRemote(self, branches, dry_run=True):
        """Push deletions of this branch for all projects.

    Args:
      branches: List of ProjectBranches for which to push delete.
      dry_run: Whether or not to set --dry-run.
    """
        logging.notice('Deleting old branches on remote (%s --dry-run).',
                       'with' if dry_run else 'without')
        for project, branch in branches:
            branch = git.NormalizeRef(branch)
            cmd = ['push', project.Remote().GitName(), '--delete', branch]
            if dry_run:
                cmd.append('--dry-run')
            self.checkout.RunGit(project, cmd)
Exemplo n.º 9
0
  def _RunPush(self, checkout, src_ref, dest_ref, force=False):
    """Perform a git push for a checkout.

    Args:
      checkout: A dictionary of checkout manifest attributes.
      src_ref: The source local ref to push to the remote.
      dest_ref: The local remote ref that correspond to destination ref name.
      force: Whether to override non-fastforward checks.
    """
    # Convert local tracking ref to refs/heads/* on a remote:
    # refs/remotes/<remote name>/<branch> to refs/heads/<branch>.
    # If dest_ref is already refs/heads/<branch> it's a noop.
    dest_ref = git.NormalizeRef(git.StripRefs(dest_ref))
    push_to = git.RemoteRef(checkout['push_remote'], dest_ref)
    git.GitPush(checkout['local_path'], src_ref, push_to, force=force,
                skip=self.skip_remote_push)
Exemplo n.º 10
0
    def setUp(self):
        """Setup patchers for specified bot id."""
        # Mock out methods as needed.
        self.StartPatcher(parallel_unittest.ParallelMock())
        self.StartPatcher(git_unittest.ManifestCheckoutMock())
        self._CreateVersionFile()
        self.rc_mock = self.StartPatcher(cros_test_lib.RunCommandMock())
        self.rc_mock.SetDefaultCmdResult()

        # We have a versioned manifest (generated by ManifestVersionSyncStage) and
        # the regular, user-maintained manifests.
        manifests = {
            '.repo/manifest.xml': VERSIONED_MANIFEST_CONTENTS,
            'manifest/default.xml': MANIFEST_CONTENTS,
            'manifest-internal/official.xml': MANIFEST_CONTENTS,
        }
        for m_path, m_content in manifests.iteritems():
            full_path = os.path.join(self.build_root, m_path)
            osutils.SafeMakedirs(os.path.dirname(full_path))
            osutils.WriteFile(full_path, m_content)

        self.norm_name = git.NormalizeRef(self.RELEASE_BRANCH_NAME)
Exemplo n.º 11
0
    def _PushBranchesToRemote(self, branches, dry_run=True, force=False):
        """Push state of local git branches to remote.

    Args:
      branches: List of ProjectBranches to push.
      force: Whether or not to overwrite existing branches on the remote.
      dry_run: Whether or not to set --dry-run.
    """
        logging.notice('Pushing branches to remote (%s --dry-run).',
                       'with' if dry_run else 'without')
        for project, branch in branches:
            branch = git.NormalizeRef(branch)

            # The refspec should look like 'HEAD:refs/heads/branch'.
            refspec = 'HEAD:%s' % branch
            remote = project.Remote().GitName()

            cmd = ['push', remote, refspec]
            if dry_run:
                cmd.append('--dry-run')
            if force:
                cmd.append('--force')

            self.checkout.RunGit(project, cmd)