Esempio n. 1
0
    async def _metadata_folder(self, folder: BitbucketPath, **kwargs) -> list:

        this_dir = await self._fetch_dir_listing(folder)
        if folder.commit_sha is None:
            folder.set_commit_sha(this_dir['node'])

        ret = []
        for name in this_dir['directories']:
            ret.append(
                BitbucketFolderMetadata(
                    {'name': name},
                    folder.child(name, folder=True),
                    owner=self.owner,
                    repo=self.repo,
                ))

        for item in this_dir['files']:
            name = self.bitbucket_path_to_name(item['path'], this_dir['path'])
            # TODO: mypy doesn't like the mix of File & Folder Metadata objects
            ret.append(
                BitbucketFileMetadata(  # type: ignore
                    item,
                    folder.child(name, folder=False),
                    owner=self.owner,
                    repo=self.repo,
                ))

        return ret
Esempio n. 2
0
    async def validate_path(self, path: str, **kwargs) -> BitbucketPath:
        commit_sha = kwargs.get('commitSha')
        branch_name = kwargs.get('branch')

        # revision query param could be commit sha OR branch
        # take a guess which one it will be.
        revision = kwargs.get('revision', None)
        if revision is not None:
            try:
                int(revision, 16)  # is revision valid hex?
            except (TypeError, ValueError):
                branch_name = revision
            else:
                commit_sha = revision

        if not commit_sha and not branch_name:
            branch_name = await self._fetch_default_branch()

        if path == '/':
            return BitbucketPath(path, _ids=[(commit_sha, branch_name)])

        path_obj = BitbucketPath(path)
        for part in path_obj.parts:
            part._id = (commit_sha, branch_name)

        return path_obj
    async def _metadata_folder(self, folder: BitbucketPath, **kwargs) -> list:

        this_dir = await self._fetch_dir_listing(folder)
        if folder.commit_sha is None:
            folder.set_commit_sha(this_dir['node'])

        ret = []
        for name in this_dir['directories']:
            ret.append(BitbucketFolderMetadata(
                {'name': name},
                folder.child(name, folder=True),
                owner=self.owner,
                repo=self.repo,
            ))

        for item in this_dir['files']:
            name = self.bitbucket_path_to_name(item['path'], this_dir['path'])
            # TODO: mypy doesn't like the mix of File & Folder Metadata objects
            ret.append(BitbucketFileMetadata(  # type: ignore
                item,
                folder.child(name, folder=False),
                owner=self.owner,
                repo=self.repo,
            ))

        return ret
Esempio n. 4
0
 def test_child_inherits_id(self):
     bb_parent = BitbucketPath('/foo/',
                               _ids=[(COMMIT_SHA, BRANCH),
                                     (COMMIT_SHA, BRANCH)])
     bb_child = bb_parent.child('foo')
     assert bb_child.commit_sha == COMMIT_SHA
     assert bb_child.branch_name == BRANCH
     assert bb_child.ref == COMMIT_SHA
Esempio n. 5
0
    async def validate_v1_path(self, path: str, **kwargs) -> BitbucketPath:
        commit_sha = kwargs.get('commitSha')
        branch_name = kwargs.get('branch')

        # revision query param could be commit sha OR branch
        # take a guess which one it will be.
        revision = kwargs.get('revision', None)
        if revision is not None:
            try:
                int(revision, 16)  # is revision valid hex?
            except (TypeError, ValueError):
                branch_name = revision
            else:
                commit_sha = revision

        if not commit_sha and not branch_name:
            branch_name = await self._fetch_default_branch()

        if path == '/':
            return BitbucketPath(path, _ids=[(commit_sha, branch_name)])

        path_obj = BitbucketPath(path)
        for part in path_obj.parts:
            part._id = (commit_sha, branch_name)

        # Cache parent directory listing (a WB API V1 feature)
        # Note: Property ``_parent_dir`` has been re-structured for Bitbucket API 2.0.  Please refer
        #       to ``_fetch_path_metadata()`` and ``_fetch_dir_listing()`` for detailed information.
        self._parent_dir = {
            'metadata': await self._fetch_path_metadata(path_obj.parent),
            'contents': await self._fetch_dir_listing(path_obj.parent)
        }

        # Tweak dir_commit_sha and dir_path for Bitbucket API 2.0
        parent_dir_commit_sha = self._parent_dir['metadata']['commit']['hash'][:12]
        parent_dir_path = '{}/'.format(self._parent_dir['metadata']['path'])

        # Check file or folder existence
        path_obj_type = 'commit_directory' if path_obj.is_dir else 'commit_file'
        if path_obj.name not in [
                self.bitbucket_path_to_name(x['path'], parent_dir_path)
                for x in self._parent_dir['contents'] if x['type'] == path_obj_type
        ]:
            raise exceptions.NotFoundError(str(path))

        # _fetch_dir_listing() will tell us the commit sha used to look up the listing
        # if not set in path_obj or if the lookup sha is shorter than the returned sha, update it
        if not commit_sha or (len(commit_sha) < len(parent_dir_commit_sha)):
            path_obj.set_commit_sha(parent_dir_commit_sha)

        return path_obj
    def test_child_given_explicit_branch(self):
        """This one is weird.  An explicit child id should override the id from the parent,
        but I don't know if this is sensible behavior."""

        bb_parent = BitbucketPath('/foo/', _ids=[(COMMIT_SHA, BRANCH), (COMMIT_SHA, BRANCH)])
        bb_child = bb_parent.child('foo', _id=('413006763', 'master'))

        assert bb_child.commit_sha == '413006763'
        assert bb_child.branch_name == 'master'
        assert bb_child.ref == '413006763'

        assert bb_parent.commit_sha == COMMIT_SHA
        assert bb_parent.branch_name == BRANCH
        assert bb_parent.ref == COMMIT_SHA
Esempio n. 7
0
    def test_child_given_explicit_branch(self):
        """This one is weird.  An explicit child id should override the id from the parent,
        but I don't know if this is sensible behavior."""

        bb_parent = BitbucketPath('/foo/',
                                  _ids=[(COMMIT_SHA, BRANCH),
                                        (COMMIT_SHA, BRANCH)])
        bb_child = bb_parent.child('foo', _id=('413006763', 'master'))

        assert bb_child.commit_sha == '413006763'
        assert bb_child.branch_name == 'master'
        assert bb_child.ref == '413006763'

        assert bb_parent.commit_sha == COMMIT_SHA
        assert bb_parent.branch_name == BRANCH
        assert bb_parent.ref == COMMIT_SHA
Esempio n. 8
0
 def test_id_accessors(self):
     bb_path = BitbucketPath('/foo',
                             _ids=[(COMMIT_SHA, BRANCH),
                                   (COMMIT_SHA, BRANCH)])
     assert bb_path.commit_sha == COMMIT_SHA
     assert bb_path.branch_name == BRANCH
     assert bb_path.ref == COMMIT_SHA
Esempio n. 9
0
    def test_build_file_metadata(self, file_metadata, owner, repo):

        name = 'file0002.20bytes.txt'
        subdir = 'folder2-lvl1/folder1-lvl2/folder1-lvl3'
        full_path = '/{}/{}'.format(subdir, name)
        # Note: When building Bitbucket Path, the length of ``_ids`` array must be equal to the
        #       number of path segments, including the root.
        path = BitbucketPath(full_path,
                             _ids=[(COMMIT_SHA, BRANCH)
                                   for _ in full_path.split('/')])

        try:
            metadata = BitbucketFileMetadata(file_metadata,
                                             path,
                                             owner=owner,
                                             repo=repo)
        except Exception as exc:
            pytest.fail(str(exc))
            return

        assert metadata.name == name
        assert metadata.path == full_path
        assert metadata.kind == 'file'
        assert metadata.modified == '2019-04-26T15:13:12+00:00'
        assert metadata.modified_utc == '2019-04-26T15:13:12+00:00'
        assert metadata.created_utc == '2019-04-25T06:18:21+00:00'
        assert metadata.content_type is None
        assert metadata.size == 20
        assert metadata.size_as_int == 20
        assert metadata.etag == '{}::{}'.format(full_path, COMMIT_SHA)
        assert metadata.provider == 'bitbucket'
        assert metadata.last_commit_sha == 'dd8c7b642e32'
        assert metadata.commit_sha == COMMIT_SHA
        assert metadata.branch_name == BRANCH

        web_view = ('https://bitbucket.org/{}/{}/src/{}{}?'
                    'fileviewer=file-view-default'.format(
                        owner, repo, COMMIT_SHA, full_path))
        assert metadata.web_view == web_view

        assert metadata.extra == {
            'commitSha': COMMIT_SHA,
            'branch': BRANCH,
            'webView': web_view,
            'lastCommitSha': 'dd8c7b642e32',
        }

        resource = 'mst3k'
        assert metadata._json_api_links(resource) == {
            'delete':
            None,
            'upload':
            None,
            'move':
            'http://localhost:7777/v1/resources/{}/providers/bitbucket{}?'
            'commitSha={}'.format(resource, full_path, COMMIT_SHA),
            'download':
            'http://localhost:7777/v1/resources/{}/providers/bitbucket{}?'
            'commitSha={}'.format(resource, full_path, COMMIT_SHA),
        }
Esempio n. 10
0
    async def download(self, path: BitbucketPath,  # type: ignore
                       range: Tuple[int, int]=None, **kwargs) -> streams.ResponseStreamReader:
        """Get the stream to the specified file on Bitbucket

        In BB API 2.0, the ``repo/username/repo_slug/src/node/path`` endpoint is used for download.

        Please note that same endpoint has several different usages / behaviors depending on the
        type of the path and the query params.

        1) File download: type is file, no query param``format=meta``
        2) File metadata: type is file, with ``format=meta`` as query param
        3) Folder contents: type is folder, no query param``format=meta``
        4) Folder metadata: type is folder, with ``format=meta`` as query param

        API Doc: https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/src/%7Bnode%7D/%7Bpath%7D

        :param path: the BitbucketPath object of the file to be downloaded
        :param range: the range header
        """
        metadata = await self.metadata(path)
        logger.debug('requested-range:: {}'.format(range))
        resp = await self.make_request(
            'GET',
            self._build_v2_repo_url('src', path.commit_sha, *path.path_tuple()),
            range=range,
            expects=(200, ),
            throws=exceptions.DownloadError,
        )
        logger.debug('download-headers:: {}'.format([(x, resp.headers[x]) for x in resp.headers]))
        return streams.ResponseStreamReader(resp, size=metadata.size)
Esempio n. 11
0
    async def _fetch_path_metadata(self, path: BitbucketPath) -> dict:
        """Get the metadata for folder and file itself.

        Bitbucket API 2.0 provides an easy way to fetch metadata for files and folders by simply
        appending ``?format=meta`` to the path endpoint.

        Quirk 1: This new feature no longer returns several WB required attributes out of the box:
        ``node`` and ``path`` for folder, ``revision``, ``timestamp`` and ``created_utc`` for file.

        1) The ``path`` for folders no longer has an ending slash.
        2) The ``node`` for folders and ``revision`` for files are gone.  They have always been the
           first 12 chars of the commit hash in both 1.0 and 2.0.
        3) ``timestamp`` and ``created_utc`` for files are gone and must be obtained using the file
           history endpoint indicated by ``links.history.href``. See ``_metadata_file()`` and
           ``_fetch_commit_history_by_url()`` for details.

        Quirk 2:

        This PATH endpoint ``/2.0/repositories/{username}/{repo_slug}/src/{node}/{path}`` returns
        HTTP 404 if the ``node`` segment is a branch of which the name contains a slash.  This is
        a either a limitation or a bug on several BB API 2.0 endpoints.  It has nothing to do with
        encoding.  More specifically, neither encoding / with %2F nor enclosing ``node`` with curly
        braces %7B%7D works.  Here is the closest reference to the issue we can find as of May 2019:
        https://bitbucket.org/site/master/issues/9969/get-commit-revision-api-does-not-accept.  The
        fix is simple, just make an extra request to fetch the commit sha of the branch.  See
        ``_fetch_branch_commit_sha()`` for details.  In addition, this will happen on all branches,
        no matter if the name contains a slash or not.

        API Doc: https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/src/%7Bnode%7D/%7Bpath%7D

        :param path: the file or folder of which the metadata is requested
        :return: the file metadata dict
        """
        query_params = {
            'format': 'meta',
            'fields': 'commit.hash,commit.date,path,size,links.history.href'
        }
        if not path.commit_sha:
            path.set_commit_sha(await self._fetch_branch_commit_sha(path.branch_name))
        path_meta_url = self._build_v2_repo_url('src', path.ref, *path.path_tuple())
        resp = await self.make_request(
            'GET',
            '{}/?{}'.format(path_meta_url, urlencode(query_params)),
            expects=(200,),
            throws=exceptions.ProviderError,
        )
        return await resp.json()
Esempio n. 12
0
    def test_build_file_metadata(self, file_metadata, owner, repo):
        name = 'aaa-01-2.txt'
        subdir = 'plaster'
        full_path = '/{}/{}'.format(subdir, name)
        branch = 'master'

        path = BitbucketPath(full_path,
                             _ids=[(COMMIT_SHA, branch), (COMMIT_SHA, branch),
                                   (COMMIT_SHA, branch)])

        try:
            metadata = BitbucketFileMetadata(file_metadata,
                                             path,
                                             owner=owner,
                                             repo=repo)
        except Exception as exc:
            pytest.fail(str(exc))

        assert metadata.name == name
        assert metadata.path == full_path
        assert metadata.kind == 'file'
        assert metadata.modified == '2016-10-14T00:37:55Z'
        assert metadata.modified_utc == '2016-10-14T00:37:55+00:00'
        assert metadata.created_utc is None
        assert metadata.content_type is None
        assert metadata.size == 13
        assert metadata.size_as_int == 13
        assert metadata.etag == '{}::{}'.format(full_path, COMMIT_SHA)
        assert metadata.provider == 'bitbucket'
        assert metadata.last_commit_sha == '90c8f7eef948'
        assert metadata.commit_sha == COMMIT_SHA
        assert metadata.branch_name == branch

        web_view = ('https://bitbucket.org/{}/{}/src/{}{}?'
                    'fileviewer=file-view-default'.format(
                        owner, repo, COMMIT_SHA, full_path))
        assert metadata.web_view == web_view

        assert metadata.extra == {
            'commitSha': COMMIT_SHA,
            'branch': 'master',
            'webView': web_view,
            'lastCommitSha': '90c8f7eef948',
        }

        resource = 'mst3k'
        assert metadata._json_api_links(resource) == {
            'delete':
            None,
            'upload':
            None,
            'move':
            'http://localhost:7777/v1/resources/{}/providers/bitbucket{}?commitSha={}'
            .format(resource, full_path, COMMIT_SHA),
            'download':
            'http://localhost:7777/v1/resources/{}/providers/bitbucket{}?commitSha={}'
            .format(resource, full_path, COMMIT_SHA),
        }
Esempio n. 13
0
    async def validate_v1_path(self, path: str, **kwargs) -> BitbucketPath:
        commit_sha = kwargs.get('commitSha')
        branch_name = kwargs.get('branch')

        # revision query param could be commit sha OR branch
        # take a guess which one it will be.
        revision = kwargs.get('revision', None)
        if revision is not None:
            try:
                int(revision, 16)  # is revision valid hex?
            except (TypeError, ValueError):
                branch_name = revision
            else:
                commit_sha = revision

        if not commit_sha and not branch_name:
            branch_name = await self._fetch_default_branch()

        if path == '/':
            return BitbucketPath(path, _ids=[(commit_sha, branch_name)])

        path_obj = BitbucketPath(path)
        for part in path_obj.parts:
            part._id = (commit_sha, branch_name)

        self._parent_dir = await self._fetch_dir_listing(path_obj.parent)

        if path_obj.is_dir:
            if path_obj.name not in self._parent_dir['directories']:
                raise exceptions.NotFoundError(str(path))
        else:
            if path_obj.name not in [
                    self.bitbucket_path_to_name(x['path'],
                                                self._parent_dir['path'])
                    for x in self._parent_dir['files']
            ]:
                raise exceptions.NotFoundError(str(path))

        # _fetch_dir_listing will tell us the commit sha used to look up the listing
        # if not set in path_obj or if the lookup sha is shorter than the returned sha, update it
        if not commit_sha or (len(commit_sha) < len(self._parent_dir['node'])):
            path_obj.set_commit_sha(self._parent_dir['node'])

        return path_obj
Esempio n. 14
0
    async def validate_v1_path(self, path: str, **kwargs) -> BitbucketPath:
        commit_sha = kwargs.get('commitSha')
        branch_name = kwargs.get('branch')

        # revision query param could be commit sha OR branch
        # take a guess which one it will be.
        revision = kwargs.get('revision', None)
        if revision is not None:
            try:
                int(revision, 16)  # is revision valid hex?
            except (TypeError, ValueError):
                branch_name = revision
            else:
                commit_sha = revision

        if not commit_sha and not branch_name:
            branch_name = await self._fetch_default_branch()

        if path == '/':
            return BitbucketPath(path, _ids=[(commit_sha, branch_name)])

        path_obj = BitbucketPath(path)
        for part in path_obj.parts:
            part._id = (commit_sha, branch_name)

        self._parent_dir = await self._fetch_dir_listing(path_obj.parent)

        if path_obj.is_dir:
            if path_obj.name not in self._parent_dir['directories']:
                raise exceptions.NotFoundError(str(path))
        else:
            if path_obj.name not in [
                    self.bitbucket_path_to_name(x['path'], self._parent_dir['path'])
                    for x in self._parent_dir['files']
            ]:
                raise exceptions.NotFoundError(str(path))

        # _fetch_dir_listing will tell us the commit sha used to look up the listing
        # if not set in path_obj or if the lookup sha is shorter than the returned sha, update it
        if not commit_sha or (len(commit_sha) < len(self._parent_dir['node'])):
            path_obj.set_commit_sha(self._parent_dir['node'])

        return path_obj
    def test_update_commit_sha(self):
        bb_child = BitbucketPath('/foo/bar', _ids=[(None, BRANCH), (None, BRANCH), (None, BRANCH)])
        assert bb_child.commit_sha == None
        assert bb_child.branch_name == BRANCH
        assert bb_child.ref == BRANCH

        bb_child.set_commit_sha(COMMIT_SHA)
        assert bb_child.commit_sha == COMMIT_SHA
        assert bb_child.branch_name == BRANCH
        assert bb_child.ref == COMMIT_SHA

        bb_parent = bb_child.parent
        assert bb_parent.commit_sha == COMMIT_SHA
        assert bb_parent.branch_name == BRANCH
        assert bb_parent.ref == COMMIT_SHA

        bb_grandparent = bb_parent.parent
        assert bb_grandparent.commit_sha == COMMIT_SHA
        assert bb_grandparent.branch_name == BRANCH
        assert bb_grandparent.ref == COMMIT_SHA
Esempio n. 16
0
    def test_update_commit_sha(self):
        bb_child = BitbucketPath('/foo/bar',
                                 _ids=[(None, BRANCH), (None, BRANCH),
                                       (None, BRANCH)])
        assert bb_child.commit_sha == None
        assert bb_child.branch_name == BRANCH
        assert bb_child.ref == BRANCH

        bb_child.set_commit_sha(COMMIT_SHA)
        assert bb_child.commit_sha == COMMIT_SHA
        assert bb_child.branch_name == BRANCH
        assert bb_child.ref == COMMIT_SHA

        bb_parent = bb_child.parent
        assert bb_parent.commit_sha == COMMIT_SHA
        assert bb_parent.branch_name == BRANCH
        assert bb_parent.ref == COMMIT_SHA

        bb_grandparent = bb_parent.parent
        assert bb_grandparent.commit_sha == COMMIT_SHA
        assert bb_grandparent.branch_name == BRANCH
        assert bb_grandparent.ref == COMMIT_SHA
Esempio n. 17
0
    async def _fetch_dir_listing(self, folder: BitbucketPath) -> list:
        """Get a list of the folder's full contents (upto the max limit setting if there is one).

        Bitbucket API 2.0 refactored the response structure for listing folder contents.

        1) The response is paginated.  If ``resp_dict`` contains the key ``next``, the contents are
           partial.  The caller must use the URL provided by ``dict['next']`` to fetch the next page
           after this method returns.

        2) The response no longer provides the metadata about the folder itself.  In order to obtain
           the ``node`` and ``path`` attributes, please use  ``_fetch_path_metadata()`` instead.

        API Doc: https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/src/%7Bnode%7D/%7Bpath%7D

        :param folder: the folder of which the contents should be listed
        :returns: a list of the folder's full contents
        """
        query_params = {
            'pagelen': self.RESP_PAGE_LEN,
            'fields': 'values.path,values.size,values.type,next',
        }
        if not folder.commit_sha:
            folder.set_commit_sha(await self._fetch_branch_commit_sha(folder.branch_name))
        next_url = '{}/?{}'.format(self._build_v2_repo_url('src', folder.ref, *folder.path_tuple()),
                                   urlencode(query_params))
        dir_list = []  # type: ignore
        while next_url:
            resp = await self.make_request(
                'GET',
                next_url,
                expects=(200,),
                throws=exceptions.ProviderError,
            )
            content = await resp.json()
            next_url = content.get('next', None)
            dir_list.extend(content['values'])
        return dir_list
Esempio n. 18
0
    async def download(self, path: BitbucketPath, **kwargs):  # type: ignore
        '''Get the stream to the specified file on bitbucket
        :param str path: The path to the file on bitbucket
        '''
        metadata = await self.metadata(path)

        resp = await self.make_request(
            'GET',
            self._build_v1_repo_url('raw', path.commit_sha,
                                    *path.path_tuple()),
            expects=(200, ),
            throws=exceptions.DownloadError,
        )

        return streams.ResponseStreamReader(resp, size=metadata.size)
Esempio n. 19
0
    async def download(self, path: BitbucketPath,  # type: ignore
                       range: Tuple[int, int]=None, **kwargs) -> streams.ResponseStreamReader:
        """Get the stream to the specified file on Bitbucket

        :param path: The path to the file on Bitbucket
        :param range: the range header
        """
        metadata = await self.metadata(path)

        logger.debug('requested-range:: {}'.format(range))
        resp = await self.make_request(
            'GET',
            self._build_v1_repo_url('raw', path.commit_sha, *path.path_tuple()),
            range=range,
            expects=(200, ),
            throws=exceptions.DownloadError,
        )
        logger.debug('download-headers:: {}'.format([(x, resp.headers[x]) for x in resp.headers]))

        return streams.ResponseStreamReader(resp, size=metadata.size)
Esempio n. 20
0
    def test_build_folder_metadata(self, folder_metadata, owner, repo):
        name = 'folder1-lvl3'
        subdir = 'folder2-lvl1/folder1-lvl2'
        full_path = '/{}/{}'.format(subdir, name)
        path = BitbucketPath(full_path,
                             _ids=[(None, BRANCH)
                                   for _ in full_path.split('/')])

        try:
            metadata = BitbucketFolderMetadata(folder_metadata,
                                               path,
                                               owner=owner,
                                               repo=repo)
        except Exception as exc:
            pytest.fail(str(exc))
            return

        assert metadata.name == name
        assert metadata.path == '{}/'.format(full_path)
        assert metadata.kind == 'folder'
        assert metadata.children is None
        assert metadata.extra == {
            'commitSha': None,
            'branch': BRANCH,
        }
        assert metadata.provider == 'bitbucket'

        assert metadata.commit_sha is None
        assert metadata.branch_name == BRANCH

        assert metadata._json_api_links('mst3k') == {
            'delete':
            None,
            'upload':
            None,
            'move':
            'http://localhost:7777/v1/resources/mst3k/providers/bitbucket{}/?'
            'branch={}'.format(full_path, BRANCH),
            'new_folder':
            None,
        }
Esempio n. 21
0
    async def _fetch_dir_listing(self, folder: BitbucketPath) -> dict:
        """Get listing of contents within a BitbucketPath folder object.

        https://confluence.atlassian.com/bitbucket/src-resources-296095214.html#srcResources-GETalistofreposource

        Note::

            Using this endpoint for a file will return the file contents.

        :param BitbucketPath folder: the folder whose contents should be listed
        :rtype dict:
        :returns: a directory listing of the contents of the folder
        """
        assert folder.is_dir  # don't use this method on files

        resp = await self.make_request(
            'GET',
            self._build_v1_repo_url('src', folder.ref, *folder.path_tuple()) + '/',
            expects=(200, ),
            throws=exceptions.ProviderError,
        )
        return await resp.json()
Esempio n. 22
0
    def test_build_folder_metadata(self, folder_metadata, owner, repo):
        branch = 'master'
        name = 'plaster'

        path = BitbucketPath('/{}/'.format(name),
                             _ids=[(None, branch), (None, branch)])

        try:
            metadata = BitbucketFolderMetadata(folder_metadata,
                                               path,
                                               owner=owner,
                                               repo=repo)
        except Exception as exc:
            pytest.fail(str(exc))

        assert metadata.name == name
        assert metadata.path == '/{}/'.format(name)
        assert metadata.kind == 'folder'
        assert metadata.children is None
        assert metadata.extra == {
            'commitSha': None,
            'branch': branch,
        }
        assert metadata.provider == 'bitbucket'

        assert metadata.commit_sha is None
        assert metadata.branch_name == branch

        assert metadata._json_api_links('mst3k') == {
            'delete':
            None,
            'upload':
            None,
            'move':
            'http://localhost:7777/v1/resources/mst3k/providers/bitbucket/{}/?branch={}'
            .format(name, branch),
            'new_folder':
            None,
        }
Esempio n. 23
0
 def path_from_metadata(self,  # type: ignore
                        parent_path: BitbucketPath,
                        metadata) -> BitbucketPath:
     return parent_path.child(metadata.name, folder=metadata.is_folder)
Esempio n. 24
0
 def path_from_metadata(self,  # type: ignore
                        parent_path: BitbucketPath,
                        metadata) -> BitbucketPath:
     return parent_path.child(metadata.name, folder=metadata.is_folder)
Esempio n. 25
0
 async def _fetch_commit_history_by_path(self, path: BitbucketPath) -> list:
     if not path.commit_sha:
         path.set_commit_sha(await self._fetch_branch_commit_sha(path.branch_name))
     return await self._fetch_commit_history_by_url(
         self._build_v2_repo_url('filehistory', path.ref, path.path)
     )
 def test_child_inherits_id(self):
     bb_parent = BitbucketPath('/foo/', _ids=[(COMMIT_SHA, BRANCH), (COMMIT_SHA, BRANCH)])
     bb_child = bb_parent.child('foo')
     assert bb_child.commit_sha == COMMIT_SHA
     assert bb_child.branch_name == BRANCH
     assert bb_child.ref == COMMIT_SHA
Esempio n. 27
0
 def test_id_accessors_no_sha(self):
     bb_path = BitbucketPath('/foo', _ids=[(None, BRANCH), (None, BRANCH)])
     assert bb_path.commit_sha == None
     assert bb_path.branch_name == BRANCH
     assert bb_path.ref == BRANCH
Esempio n. 28
0
 def test_id_accessors_no_branch(self):
     bb_path = BitbucketPath('/foo',
                             _ids=[(COMMIT_SHA, None), (COMMIT_SHA, None)])
     assert bb_path.commit_sha == COMMIT_SHA
     assert bb_path.branch_name == None
     assert bb_path.ref == COMMIT_SHA
Esempio n. 29
0
    async def _metadata_folder(self, folder: BitbucketPath, **kwargs) -> list:
        """Get a list of the folder contents, each item of which is a BitbucketPath object.

        :param folder: the folder of which the contents should be listed
        :return: a list of BitbucketFileMetadata and BitbucketFolderMetadata objects
        """

        # Fetch metadata itself
        dir_meta = await self._fetch_path_metadata(folder)
        # Quirk: ``node`` attribute is no longer available for folder metadata in BB API 1.0.  The
        #        value of ``node`` can still be obtained from the commit hash of which the first 12
        #        chars turn out to be the value we need.
        dir_commit_sha = dir_meta['commit']['hash'][:12]
        # Quirk: the ``path`` attribute in folder metadata no longer has an trailing slash in BB API
        #        2.0.  To keep ``bitbucket_path_to_name()`` intact, a trailing slash is added.
        dir_path = '{}/'.format(dir_meta['path'])

        # Fetch content list
        dir_list = await self._fetch_dir_listing(folder)

        # Set the commit hash
        if folder.commit_sha is None:
            folder.set_commit_sha(dir_commit_sha)

        # Build the metadata to return
        # Quirks:
        # 1) BB API 2.0 treats both files and folders the same way.``path`` for both is a full or
        #    absolute path.  ``bitbucket_path_to_name()`` must be called to get the correct name.
        # 2) Both files and folders share the same list and use the same dict/json structure. Use
        #    the ``type`` field to check whether a path is a folder or not.
        # 3) ``revision`` for files is gone but can be replaced with part of the commit hash.
        #    However, it is tricky for files.  The ``commit`` field of each file item in the
        #    returned content list is the latest branch commit.  In order to obtain the correct
        #    time when the file was last modified, WB needs to fetch the file history.  This adds
        #    lots of requests and significantly hits performance due to folder listing being called
        #    very frequently.  The decision is to remove them.
        # 4) Similar to ``revision``, ``timestamp``, and ``created_utc`` are removed.
        ret = []
        for value in dir_list:
            if value['type'] == 'commit_file':
                name = self.bitbucket_path_to_name(value['path'], dir_path)
                # TODO: existing issue - find out why timestamp doesn't show up on the files page
                item = {
                    'size': value['size'],
                    'path': value['path'],
                }
                ret.append(BitbucketFileMetadata(  # type: ignore
                    item,
                    folder.child(name, folder=False),
                    owner=self.owner,
                    repo=self.repo,
                ))
            if value['type'] == 'commit_directory':
                name = self.bitbucket_path_to_name(value['path'], dir_path)
                ret.append(BitbucketFolderMetadata(  # type: ignore
                    {'name': name},
                    folder.child(name, folder=True),
                    owner=self.owner,
                    repo=self.repo,
                ))

        return ret