Beispiel #1
0
    def Run(self, args):
        """Clone a GCP repository to the current directory.

    Args:
      args: argparse.Namespace, the arguments this command is run with.

    Returns:
      The path to the new git repository.
    """
        # Ensure that we're logged in.
        c_store.Load(use_google_auth=True)

        res = sourcerepo.ParseRepo(args.src)
        source_handler = sourcerepo.Source()

        repo = source_handler.GetRepo(res)
        if hasattr(repo, 'mirrorConfig') and repo.mirrorConfig:
            mirror_url = repo.mirrorConfig.url
            self.ActionIfMirror(project=res.projectsId,
                                repo=args.src,
                                mirror_url=mirror_url)
        # do the actual clone
        git_helper = git.Git(res.projectsId, args.src, uri=repo.url)
        path = git_helper.Clone(destination_path=args.dst or args.src,
                                dry_run=args.dry_run,
                                full_path=self.UseFullGcloudPath(args))
        if path and not args.dry_run:
            log.status.write('Project [{prj}] repository [{repo}] was cloned '
                             'to [{path}].\n'.format(prj=res.projectsId,
                                                     path=path,
                                                     repo=args.src))
Beispiel #2
0
  def testForcePushFilesToBranchNoCredHelper(self):
    self.git_version_mock.return_value = 'git version 1.7.9'
    self.StartObjectPatch(git, '_GetGcloudScript', return_value='gcloud')
    properties.VALUES.core.account.Set('fake-git-account')
    subprocess_mock = self.StartObjectPatch(subprocess, 'check_call')
    temp_path = '/tmp/path'
    self.StartObjectPatch(
        file_utils.TemporaryDirectory, '__enter__', return_value=temp_path)
    self.StartObjectPatch(file_utils, 'RmTree')
    abspath_mock = self.StartObjectPatch(os.path, 'abspath')
    abspath_mock.side_effect = (
        lambda p: p if p.startswith('/') else '/'.join(['/dir', p]))

    repo_url = 'https://source.developers.google.com/p/fake-project/r/fake-repo'
    repo = git.Git('fake-project', 'fake-repo')

    expected_calls = [mock.call(['git', 'init', temp_path])]

    def add_expected_call(*args):
      git_dir = '--git-dir=' + os.path.join(temp_path, '.git')
      work_tree = '--work-tree=/dir'
      expected_calls.append(mock.call(['git', git_dir, work_tree] + list(args)))

    add_expected_call('checkout', '-b', 'branch1')
    add_expected_call('add', '/dir/file1', '/dir/dir2/file2')
    add_expected_call('commit', '-m', 'source capture uploaded from gcloud')
    add_expected_call('remote', 'add', 'origin', repo_url)
    add_expected_call('push', '-f', 'origin', 'branch1')

    repo.ForcePushFilesToBranch(
        'branch1', '/dir', ['/dir/file1', '/dir/dir2/file2'])

    self.assertEqual(expected_calls, subprocess_mock.call_args_list)
    def Run(self, args):
        """Clone a GCP repository to the current directory.

    Args:
      args: argparse.Namespace, the arguments this command is run with.

    Raises:
      ToolException: on project initialization errors.

    Returns:
      The path to the new git repository.
    """
        # Ensure that we're logged in.
        c_store.Load()

        project_id = properties.VALUES.core.project.Get(required=True)
        project_repo = git.Git(project_id, args.src)
        path = project_repo.Clone(destination_path=args.dst or args.src,
                                  dry_run=args.dry_run)
        if path and not args.dry_run:
            log.status.write(
                'Project [{prj}] repository [{repo}] was cloned to '
                '[{path}].\n'.format(prj=project_id,
                                     path=path,
                                     repo=project_repo.GetName()))
Beispiel #4
0
 def testCloneRepoDirExistsGitNotFound(self):
   self.git_version_mock.side_effect = OSError(errno.ENOENT, 'not found')
   project_repo = git.Git('fake-project', 'fake-repo')
   repo_path = self.CreateTempDir('repo-path')
   with self.assertRaisesRegex(
       git.NoGitException,
       re.escape('Cannot find git. Please install git and try again.')):
     project_repo.Clone(destination_path=repo_path)
Beispiel #5
0
 def testCloneRemoteDoesntExist(self):
   project_repo = git.Git('fake-project', 'fake-repo')
   repo_path = self.CreateTempDir('repo-path')
   project_repo._uri = 'abcd'
   subprocess_mock = self.StartObjectPatch(subprocess, 'check_call')
   subprocess_mock.side_effect = subprocess.CalledProcessError(
       1, ('fatal: repository {0} does not exist'.format(project_repo._uri)))
   with self.assertRaisesRegex(
       git.CannotFetchRepositoryException,
       re.escape('fatal: repository abcd does not exist')):
     project_repo.Clone(destination_path=repo_path)
Beispiel #6
0
 def testCloneRepoOldGitVersion_NoCredentialHelper(self):
   self.git_version_mock.return_value = 'git version 1.7.9'
   self.StartObjectPatch(git, '_GetGcloudScript', return_value='gcloud')
   project_repo = git.Git('fake-project', 'fake-repo')
   path = project_repo.Clone(destination_path='repo-path', dry_run=True)
   repo_path = os.path.abspath('repo-path')
   self.assertEqual(repo_path, path)
   self.AssertOutputEquals(
       'git clone '
       'https://source.developers.google.com/p/fake-project/r/fake-repo {0}\n'
       .format(repo_path))
Beispiel #7
0
  def testForcePushFilesToBranchGitSubdirectory(self):
    repo = git.Git('fake-project', 'fake-repo')
    with self.assertRaisesRegex(
        git.CannotPushToRepositoryException,
        (r"Can't upload the file tree.*abc")):
      repo.ForcePushFilesToBranch('branch1', '/dir', ['/dir/.git/abc'])

    with self.assertRaisesRegex(
        git.CannotPushToRepositoryException,
        (r"Can't upload the file tree.*gitignore")):
      repo.ForcePushFilesToBranch('branch1', '/dir', ['/dir/sub/.gitignore'])
Beispiel #8
0
 def testCloneRepoDirExistsIsNotEmpty(self):
   self.StartObjectPatch(git, '_GetGcloudScript', return_value='gcloud')
   self.StartObjectPatch(os, 'listdir')
   listdir_mock = self.StartObjectPatch(os, 'listdir')
   listdir_mock.return_value = ('test.txt')
   project_repo = git.Git('fake-project', 'fake-repo')
   repo_path = self.CreateTempDir('repo-path')
   with self.assertRaisesRegex(
       git.CannotInitRepositoryException,
       re.escape('Directory path specified exists and is not empty')):
     project_repo.Clone(destination_path=repo_path)
Beispiel #9
0
    def Run(self, args):
        """Clone a GCP repository to the current directory.

    Args:
      args: argparse.Namespace, the arguments this command is run with.

    Raises:
      ToolException: on project initialization errors.
      RepoCreationError: on repo creation errors.

    Returns:
      The path to the new git repository.
    """
        # Ensure that we're logged in.
        c_store.Load()

        project_id = resolvers.FromProperty(properties.VALUES.core.project)
        res = resources.REGISTRY.Parse(args.src,
                                       params={'projectsId': project_id},
                                       collection='sourcerepo.projects.repos')
        source_handler = sourcerepo.Source()

        repo = source_handler.GetRepo(res)
        if not repo:
            message = ('Repository "{src}" in project "{prj}" does not '
                       'exist.\nList current repos with\n'
                       '$ gcloud beta source repos list\n'
                       'or create with\n'
                       '$ gcloud beta source repos create {src}'.format(
                           src=args.src, prj=res.projectsId))
            raise c_exc.InvalidArgumentException('REPOSITORY_NAME', message)
        if hasattr(repo, 'mirrorConfig') and repo.mirrorConfig:
            mirror_url = repo.mirrorConfig.url
            message = (
                'Repository "{src}" in project "{prj}" is a mirror. Clone the '
                'mirrored repository directly with \n$ git clone '
                '{url}'.format(src=args.src,
                               prj=res.projectsId,
                               url=mirror_url))
            raise c_exc.InvalidArgumentException('REPOSITORY_NAME', message)
        # do the actual clone
        git_helper = git.Git(res.projectsId, args.src, uri=repo.url)
        path = git_helper.Clone(destination_path=args.dst or args.src,
                                dry_run=args.dry_run,
                                full_path=args.use_full_gcloud_path)
        if path and not args.dry_run:
            log.status.write('Project [{prj}] repository [{repo}] was cloned '
                             'to [{path}].\n'.format(prj=res.projectsId,
                                                     path=path,
                                                     repo=args.src))
Beispiel #10
0
  def Run(self, args):
    """Clone a GCP repository to the current directory.

    Args:
      args: argparse.Namespace, the arguments this command is run with.

    Raises:
      ToolException: on project initialization errors.
      RepoCreationError: on repo creation errors.

    Returns:
      The path to the new git repository.
    """
    # Ensure that we're logged in.
    c_store.Load()

    project_id = resolvers.FromProperty(properties.VALUES.core.project)
    res = resources.REGISTRY.Parse(
        args.src,
        params={'projectsId': project_id},
        collection='sourcerepo.projects.repos')
    source_handler = sourcerepo.Source()

    # Check for the existence of the named repo in the project and maybe ask
    # the user whether they want to create it if it does not already exist.
    #
    # Note that repo creation can fail if there is a concurrent attempt to
    # create the repo (e.g. through another call to gcloud or a concurrent
    # attempt in the developer console through a browser).
    repo = source_handler.GetRepo(res)
    if not repo:
      message = ('Repository "{src}" in project "{prj}" does not yet '
                 'exist.'.format(src=args.src, prj=res.projectsId))
      prompt_string = 'Would you like to create it'
      if args.autocreate or console_io.PromptContinue(
          message=message, prompt_string=prompt_string, default=True):
        repo = source_handler.CreateRepo(res)
      else:
        message = ('Cannot clone from a non-existent repo. Please create it '
                   'with:\n  $ gcloud alpha source repos create {src}\n and '
                   'try cloning again.'.format(src=args.src))
        raise exceptions.InvalidUserInputError(message)
    # do the actual clone
    git_helper = git.Git(res.projectsId, args.src, uri=repo.url)
    path = git_helper.Clone(
        destination_path=args.dst or args.src, dry_run=args.dry_run)
    if path and not args.dry_run:
      log.status.write('Project [{prj}] repository [{repo}] was cloned '
                       'to [{path}].\n'.format(
                           prj=res.projectsId, path=path, repo=args.src))
Beispiel #11
0
  def testCloneRepoWindowsGitSupportsCredHelperButNotEmptyHelper(self):
    self.git_version_mock.return_value = 'git version 2.10.0'

    self.StartObjectPatch(git, '_GetGcloudScript', return_value='gcloud')
    project_repo = git.Git('fake-project', 'fake-repo')
    path = project_repo.Clone(destination_path='repo-path')
    repo_path = os.path.abspath('repo-path')
    self.assertEqual(repo_path, path)
    self.AssertErrContains('gcloud auth print-access-token')
    self.assertEqual([
        mock.call([
            'git', 'clone',
            'https://source.developers.google.com/p/fake-project/r/fake-repo',
            repo_path
        ])
    ], self.clone_command_mock.call_args_list)
Beispiel #12
0
  def testCloneRepo_DryRun(self):
    properties.VALUES.core.account.Set('fake-git-account')
    self.git_version_mock.return_value = 'git version 2.15.0'

    self.StartObjectPatch(git, '_GetGcloudScript', return_value='gcloud')
    project_repo = git.Git('fake-project', 'fake-repo')
    path = project_repo.Clone(destination_path='repo-path', dry_run=True)
    repo_path = os.path.abspath('repo-path')
    self.assertEqual(repo_path, path)
    self.AssertOutputContains(
        'git clone '
        'https://source.developers.google.com/p/fake-project/r/fake-repo {0} '
        '--config credential.helper= '
        '--config credential.helper='
        '!gcloud auth git-helper --account=fake-git-account '
        '--ignore-unknown $@'.format(repo_path))
Beispiel #13
0
  def testCloneRepoGitSupportsEmptyHelper(self):
    properties.VALUES.core.account.Set('fake-git-account')
    self.git_version_mock.return_value = 'git version 2.15.0'

    self.StartObjectPatch(git, '_GetGcloudScript', return_value='gcloud')
    project_repo = git.Git('fake-project', 'fake-repo')
    path = project_repo.Clone(destination_path='repo-path')
    repo_path = os.path.abspath('repo-path')
    self.assertEqual(repo_path, path)
    self.assertEqual([
        mock.call([
            'git', 'clone',
            'https://source.developers.google.com/p/fake-project/r/fake-repo',
            repo_path, '--config', 'credential.helper=', '--config',
            'credential.helper='
            '!gcloud auth git-helper --account=fake-git-account '
            '--ignore-unknown $@'
        ])
    ], self.clone_command_mock.call_args_list)
  def Run(self, args):
    """Clone a GCP repository to the current directory.

    Args:
      args: argparse.Namespace, the arguments this command is run with.

    Returns:
      The path to the new git repository.
    """
    # Ensure that we're logged in.
    c_store.Load()

    res = sourcerepo.ParseRepo(args.src)
    source_handler = sourcerepo.Source()

    repo = source_handler.GetRepo(res)
    if not repo:
      message = ('Repository "{src}" in project "{prj}" does not '
                 'exist.\nList current repos with\n'
                 '$ gcloud beta source repos list\n'
                 'or create with\n'
                 '$ gcloud beta source repos create {src}'.format(
                     src=args.src, prj=res.projectsId))
      raise c_exc.InvalidArgumentException('REPOSITORY_NAME', message)
    if hasattr(repo, 'mirrorConfig') and repo.mirrorConfig:
      mirror_url = repo.mirrorConfig.url
      self.ActionIfMirror(
          project=res.projectsId, repo=args.src, mirror_url=mirror_url)
    # do the actual clone
    git_helper = git.Git(res.projectsId, args.src, uri=repo.url)
    path = git_helper.Clone(
        destination_path=args.dst or args.src,
        dry_run=args.dry_run,
        full_path=self.UseFullGcloudPath(args))
    if path and not args.dry_run:
      log.status.write('Project [{prj}] repository [{repo}] was cloned '
                       'to [{path}].\n'.format(
                           prj=res.projectsId, path=path, repo=args.src))
Beispiel #15
0
  def testCloneRepoOldGitVersion(self):
    self.git_version_mock.return_value = 'git version 1.7.9'
    self.StartObjectPatch(git, '_GetGcloudScript', return_value='gcloud')

    expected_min = '2.0.1'
    if (platforms.OperatingSystem.Current() == platforms.OperatingSystem.WINDOWS
       ):
      expected_min = '2.15.0'
    project_repo = git.Git('fake-project', 'fake-repo')
    repo_path = os.path.abspath('repo-path')
    project_repo.Clone(destination_path=repo_path, dry_run=True)
    self.AssertErrContains(
        textwrap.dedent("""\
    WARNING: You are using a Google-hosted repository with a
    git version {current} which is older than {min_version}. If you upgrade
    to {min_version} or later, gcloud can handle authentication to
    this repository. Otherwise, to authenticate, use your Google
    account and the password found by running the following command.
     $ gcloud auth print-access-token
               """.format(current='1.7.9', min_version=expected_min)))
    self.AssertOutputEquals(
        'git clone '
        'https://source.developers.google.com/p/fake-project/r/fake-repo {0}\n'
        .format(repo_path))
Beispiel #16
0
    def Upload(self, branch, root_path, ignore_file=None):
        """Uploads files to a branch in Cloud Source Repositories.

    Args:
      branch: (string) The name of the branch to upload to. If empty, a
        name will be generated.
      root_path: (string) The path of a directory tree to upload.
      ignore_file: (string) The file overrides the `.gcloudignore` file and
        uses the specified file instead.

    Returns:
      A dictionary containing various status information:
        'branch': The name of the branch.
        'source_contexts': One or more dictionaries compatible with the
          ExtendedSourceContext message, including one context pointing
          to the upload. This context will be the only one with the value
          'capture' for its 'category' label.
        'files_written': The number of files uploaded.
        'files_skipped': The number of files skipped.
        'size_written': The total number of bytes in all files uploaded.
    """
        try:
            sourcerepo.Source().GetRepo(sourcerepo.ParseRepo(UPLOAD_REPO_NAME))
        except exceptions.HttpNotFoundError:
            raise RepoNotFoundError(
                REPO_NOT_FOUND_ERROR.format(UPLOAD_REPO_NAME,
                                            self._project_id))

        file_chooser = gcloudignore.GetFileChooserForDir(
            root_path, write_on_disk=False, ignore_file=ignore_file)
        branch = branch or (_GetNow().strftime(TIME_FORMAT) + '.' +
                            _GetUuid().hex)
        all_paths = [
            os.path.join(root_path, f)
            for f in file_chooser.GetIncludedFiles(root_path,
                                                   include_dirs=False)
        ]
        paths = [
            f for f in all_paths if not os.path.islink(f)
            and os.path.getsize(f) <= self.SIZE_THRESHOLD
        ]
        git.Git(self._project_id, UPLOAD_REPO_NAME).ForcePushFilesToBranch(
            branch, root_path, sorted(paths))

        source_context = {
            'context': {
                'cloudRepo': {
                    'repoId': {
                        'projectRepoId': {
                            'projectId': self._project_id,
                            'repoName': UPLOAD_REPO_NAME
                        }
                    },
                    'aliasContext': {
                        'kind': 'MOVABLE',
                        'name': branch
                    }
                }
            },
            'labels': {
                'category': 'capture'
            }
        }

        return {
            'branch': branch,
            'source_contexts': [source_context],
            'files_written': len(paths),
            'files_skipped': len(all_paths) - len(paths),
            'size_written': sum([os.path.getsize(f) for f in paths])
        }
    def Upload(self, branch, root_path):
        """Uploads files to a branch in Cloud Source Repositories.

    Args:
      branch: (string) The name of the branch to upload to. If empty, a
        name will be generated.
      root_path: (string) The path of a directory tree to upload.

    Returns:
      A dictionary containing various status information:
        'branch': The name of the branch.
        'source_contexts': One or more dictionaries compatible with the
          ExtendedSourceContext message, including one context pointing
          to the upload. This context will be the only one with the value
          'capture' for its 'category' label.
        'files_written': The number of files uploaded.
        'files_skipped': The number of files skipped.
        'size_written': The total number of bytes in all files uploaded.
    """
        if not sourcerepo.Source().GetRepo(
                sourcerepo.ParseRepo(UPLOAD_REPO_NAME)):
            raise exceptions.Error(
                REPO_NOT_FOUND_ERROR.format(UPLOAD_REPO_NAME,
                                            self._project_id))

        branch = branch or (_GetNow().strftime(TIME_FORMAT) + '.' +
                            _GetUuid().hex)
        all_paths = [
            f
            for f in self._ignore_handler.GetFiles(os.path.abspath(root_path))
            if not os.path.islink(f)
        ]
        paths = [
            f for f in all_paths if os.path.getsize(f) <= self.SIZE_THRESHOLD
        ]
        git.Git(self._project_id, UPLOAD_REPO_NAME).ForcePushFilesToBranch(
            branch, root_path, paths)

        source_context = {
            'context': {
                'cloudRepo': {
                    'repoId': {
                        'projectRepoId': {
                            'projectId': self._project_id,
                            'repoName': UPLOAD_REPO_NAME
                        }
                    },
                    'aliasContext': {
                        'kind': 'MOVABLE',
                        'name': branch
                    }
                }
            },
            'labels': {
                'category': 'capture'
            }
        }

        return {
            'branch': branch,
            'source_contexts': [source_context],
            'files_written': len(paths),
            'files_skipped': len(all_paths) - len(paths),
            'size_written': sum([os.path.getsize(f) for f in paths])
        }
Beispiel #18
0
 def testNoCredentialHelper(self, subprocess_mock):
   subprocess_mock.return_value = ''
   project_repo = git.Git('fake-project', 'fake-repo')
   project_repo.Clone('dest', dry_run=True)
   self.AssertErrNotContains('cancel')