diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000..7def27b --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,68 @@ + +name: Build test and release + +on: + workflow_dispatch: + push: + +env: + KBC_TEST_TOKEN: ${{ secrets.KBC_TEST_TOKEN }} + KBC_TEST_API_URL: https://connection.keboola.com + KBC_AZ_TEST_TOKEN: ${{ secrets.KBC_AZ_TEST_TOKEN }} + KBC_AZ_TEST_API_URL: https://connection.north-europe.azure.keboola.com + +jobs: + build_and_test: + runs-on: ubuntu-latest + outputs: + is_semantic_tag: ${{steps.tag.outputs.is_semantic_tag}} + steps: + - name: Checkout the repo + uses: actions/checkout@v3 + - name: Print Docker version + run: | + docker -v + - name: Docker login + if: env.DOCKERHUB_TOKEN + run: docker login --username "$DOCKERHUB_USER" --password "$DOCKERHUB_TOKEN" + - name: build + run: docker-compose build sapi-python-client + - name: show images + run: docker images + - name: run tests flake8 + run: docker-compose run --rm --entrypoint=flake8 sapi-python-client + - name: run tests aws + run: docker-compose run --rm -e KBC_TEST_TOKEN=$KBC_TEST_TOKEN -e KBC_TEST_API_URL=$KBC_TEST_API_URL -e SKIP_ABS_TEST=1 sapi-python-client -m unittest discover + - name: run tests azure + run: docker-compose run --rm -e KBC_TEST_TOKEN=$KBC_AZ_TEST_TOKEN -e KBC_TEST_API_URL=$KBC_AZ_TEST_API_URL sapi-python-client -m unittest discover + + - name: Check if tag is semantic + id: tag + run: | + TAG="${GITHUB_REF##*/}" + IS_SEMANTIC_TAG=$(echo "$TAG" | grep -q '^v\?[0-9]\+\.[0-9]\+\.[0-9]\+$' && echo true || echo false) + echo "Tag = '$TAG', is semantic tag = '$IS_SEMANTIC_TAG'" + echo "is_semantic_tag=$IS_SEMANTIC_TAG" >> $GITHUB_OUTPUT + deploy_to_pypi: + needs: + - build_and_test + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') && needs.build_and_test.outputs.is_semantic_tag == 'true' + steps: + - name: Checkout the repo + uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b53122e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -sudo: required -language: bash -services: -- docker -before_script: -- docker login --username "$DOCKERHUB_USER" --password "$DOCKERHUB_TOKEN" -- docker-compose build sapi-python-client -script: -- docker-compose run --rm --entrypoint=flake8 sapi-python-client -- docker-compose run --rm -e KBC_TEST_TOKEN -e KBC_TEST_API_URL -e SKIP_ABS_TEST=1 sapi-python-client -m unittest discover -- docker-compose run --rm -e KBC_TEST_TOKEN=$KBC_AZ_TEST_TOKEN -e KBC_TEST_API_URL=$KBC_AZ_TEST_API_URL sapi-python-client -m unittest discover -after_success: -- docker images -deploy: - provider: script - skip_cleanup: true - script: "./deploy.sh" - on: - tags: true -notifications: - slack: - rooms: - secure: IHfa2pHnjC/lY3H4062fTTz7y1CmHw0FbVtyxG8mMD9iuAbEIvgOs8+BRLFzqx6Baej1TnELFek7QCFdMV5SVDda7XMCOY5WLMoG1YoQ4UtnYE2mhvEsoKEu5C73rZ/OIm1jIihLFGpznwhq+ZSbPT2wiKfJglic87NW5XPsYE52XvZRQ3RY0dZpTxpXIdKOKUvcMK0FZfzDbkGHOB8GTVRNyaa1r4uI4XTyNW3c3l8sTOQo3l4rCtQXyMVqWIKXywxSfo7r+h1XPqrxpUtm+2d/B05bYRlD39OGR3O5LwK1YDFl7F3Dc9u503IhMs1p5gc3jRb4L1QCJXy0VcXgHPyaKMSnE6Ambja6S8oXXao167iR7qJ3sHgd1PAs48pSZPoqSvVB8K26X59l9jKf0xAqFm2tZVEOuYD2yGKoWpB4f201yTfVQaQ69P/lLFhao+kI2XuupCgyVTeuOFyc4fYS6k1ooJvFY8NPlhnCVW6xYJCfRcy0gYFXCAVgqpl6Icm4nMVQ66AU6tQckfuZK/7vfpw1SsfifeHLFLQp0AiXydS4ozhFYzejDxVnKH8a1S4ZGfvgPEVfc2xp5C8nJR8YJn9KA3V0JJ01foBofymWnB2QPLUQr3iaLbPsep3ixtjxTSTTjFWCv5kd6Sh193KcK/0RkHWs+1Tz0Lb+FZM= diff --git a/Dockerfile b/Dockerfile index 961886a..86a6b31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,6 @@ FROM python:3.8 WORKDIR /code COPY . /code/ -RUN pip3 install --no-cache-dir flake8 responses +RUN pip3 install --no-cache-dir flake8 responses typing_extensions RUN python setup.py install ENTRYPOINT ["python"] diff --git a/kbcstorage/base.py b/kbcstorage/base.py index 17e82dc..4f8afd8 100644 --- a/kbcstorage/base.py +++ b/kbcstorage/base.py @@ -145,4 +145,6 @@ def _delete(self, *args, **kwargs): except requests.HTTPError: # Handle different error codes raise - # Should delete return something on success? + + if 'application/json' in r.headers.get('Content-Type', ''): + return r.json() diff --git a/kbcstorage/buckets.py b/kbcstorage/buckets.py index 5203df1..6146229 100644 --- a/kbcstorage/buckets.py +++ b/kbcstorage/buckets.py @@ -7,6 +7,7 @@ http://docs.keboola.apiary.io/#reference/buckets/ """ from kbcstorage.base import Endpoint +from kbcstorage.jobs import Jobs class Buckets(Endpoint): @@ -100,7 +101,7 @@ def create(self, name, stage='in', description='', backend=None): return self._post(self.base_url, data=body) - def delete(self, bucket_id, force=False): + def delete(self, bucket_id, force=False, asynchronous=True): """ Delete a bucket referenced by ``bucket_id``. @@ -112,12 +113,20 @@ def delete(self, bucket_id, force=False): bucket_id (str): The id of the bucket to be deleted. force (bool): If ``True``, deletes the bucket even if it is not empty. Default ``False``. + asynchronous (bool): if asynchronous then the """ # How does the API handle it when force == False and the bucket is non- # empty? url = '{}/{}'.format(self.base_url, bucket_id) - params = {'force': force} - self._delete(url, params=params) + params = {'force': force, 'async': asynchronous} + if (asynchronous): + job = self._delete(url, params=params) + jobs = Jobs(self.root_url, self.token) + job = jobs.block_until_completed(job['id']) + if job['status'] == 'error': + raise RuntimeError(job['error']['message']) + else: + self._delete(url, params=params) def link(self, *args, **kwargs): """ diff --git a/setup.py b/setup.py index 67593d9..7956738 100644 --- a/setup.py +++ b/setup.py @@ -18,5 +18,6 @@ test_suite='tests', tests_require=['responses'], long_description=readme, + long_description_content_type='text/markdown', license="MIT" ) diff --git a/tests/functional/test_buckets.py b/tests/functional/test_buckets.py index 0384313..9899e75 100644 --- a/tests/functional/test_buckets.py +++ b/tests/functional/test_buckets.py @@ -18,6 +18,7 @@ def setUp(self): except exceptions.HTTPError as e: if e.response.status_code != 404: raise + # https://github.com/boto/boto3/issues/454 warnings.simplefilter("ignore", ResourceWarning) diff --git a/tests/functional/test_files.py b/tests/functional/test_files.py index 4ef8b37..cabdb2b 100644 --- a/tests/functional/test_files.py +++ b/tests/functional/test_files.py @@ -13,7 +13,6 @@ class TestFiles(unittest.TestCase): def setUp(self): - # timeout for files from previous tests to appear time.sleep(1) self.files = Files(os.getenv('KBC_TEST_API_URL'), diff --git a/tests/functional/test_workspaces.py b/tests/functional/test_workspaces.py index 3182773..be2fbf8 100644 --- a/tests/functional/test_workspaces.py +++ b/tests/functional/test_workspaces.py @@ -33,6 +33,7 @@ def setUp(self): except exceptions.HTTPError as e: if e.response.status_code != 404: raise + # https://github.com/boto/boto3/issues/454 warnings.simplefilter("ignore", ResourceWarning) diff --git a/tests/mocks/test_buckets.py b/tests/mocks/test_buckets.py index 6af60a1..fba81ed 100644 --- a/tests/mocks/test_buckets.py +++ b/tests/mocks/test_buckets.py @@ -50,12 +50,12 @@ def test_delete(self): responses.add( responses.Response( method='DELETE', - url='https://connection.keboola.com/v2/storage/buckets/1', + url='https://connection.keboola.com/v2/storage/buckets/1?force=False&async=False', json={} ) ) bucket_id = '1' - deleted_detail = self.buckets.delete(bucket_id) + deleted_detail = self.buckets.delete(bucket_id, asynchronous=False) assert deleted_detail is None @responses.activate