diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 98b377a41..d9ab82142 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 6.1.0 +current_version = 6.2.0 commit = True tag = False parse = (?P\d+)\.(?P\d+)\.(?P[A-z0-9-]+) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 4fe0284c5..ca5c077f1 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -19,7 +19,7 @@ jobs: SM_API_DOCKER: australia-southeast1-docker.pkg.dev/cpg-common/images/sm-api defaults: run: - shell: bash -l {0} + shell: bash -eo pipefail -l {0} steps: - uses: actions/checkout@main diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index a51b1fc91..d4863658a 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - shell: bash -l {0} + shell: bash -eo pipefail -l {0} steps: - uses: actions/checkout@v2 @@ -19,7 +19,6 @@ jobs: - name: Install packages run: | pip install -r requirements-dev.txt - pip install -r requirements-server.txt pip install . - name: pre-commit diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5ffe1fbf2..aaffc014b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -14,7 +14,7 @@ jobs: SM_DOCKER: samplemetadata:dev defaults: run: - shell: bash -l {0} + shell: bash -eo pipefail -l {0} steps: - uses: actions/checkout@main diff --git a/api/routes/enum.py b/api/routes/enum.py index 7be845778..c655ddca3 100644 --- a/api/routes/enum.py +++ b/api/routes/enum.py @@ -20,6 +20,12 @@ def _create_route(e: Type[EnumTable]): async def get(connection=get_projectless_db_connection) -> list[str]: return await e(connection).get() + @router.post('/' + hyphenated_name, operation_id='post' + camel_case_name + 's') + async def post( + new_type: str, connection=get_projectless_db_connection + ) -> list[str]: + return await e(connection).insert(new_type) + for enum in enum_tables.__dict__.values(): if not isclass(enum): diff --git a/api/server.py b/api/server.py index c52b93e4d..cf547abd6 100644 --- a/api/server.py +++ b/api/server.py @@ -20,7 +20,7 @@ from api.settings import PROFILE_REQUESTS, SKIP_DATABASE_CONNECTION # This tag is automatically updated by bump2version -_VERSION = '6.1.0' +_VERSION = '6.2.0' logger = get_logger() diff --git a/db/python/enum_tables/enums.py b/db/python/enum_tables/enums.py index 1ac50f0d9..e6419b98b 100644 --- a/db/python/enum_tables/enums.py +++ b/db/python/enum_tables/enums.py @@ -64,3 +64,4 @@ async def insert(self, value: str): await self.connection.execute(_query, {'name': value.lower()}) # clear the cache so results are up-to-date self.get.cache_clear() # pylint: disable=no-member + return value diff --git a/deploy/python/version.txt b/deploy/python/version.txt index dfda3e0b4..6abaeb2f9 100644 --- a/deploy/python/version.txt +++ b/deploy/python/version.txt @@ -1 +1 @@ -6.1.0 +6.2.0 diff --git a/regenerate_api.py b/regenerate_api.py index 370d9ada2..07112163e 100755 --- a/regenerate_api.py +++ b/regenerate_api.py @@ -1,15 +1,14 @@ #!/usr/bin/env python3 # pylint: disable=logging-not-lazy,subprocess-popen-preexec-fn,consider-using-with import logging -import re -from typing import Optional, List - import os +import re +import shutil import signal +import subprocess import tempfile -import shutil import time -import subprocess +from typing import List, Optional import requests @@ -35,6 +34,15 @@ def check_if_server_is_accessible() -> bool: return False +def assert_server_is_accessible(): + """Assert that the server is accessible""" + if not check_if_server_is_accessible(): + raise requests.ConnectionError( + f'Could not connect to server at {SCHEMA_URL}. ' + 'Please make sure the server is running and accessible.' + ) + + def start_server() -> Optional[subprocess.Popen]: """Start the API server, and return a process when it's started""" @@ -124,7 +132,9 @@ def check_openapi_version(): logger.info(f'Got openapi version: {version}') -def generate_api_and_copy(output_type, output_copyer, extra_commands: List[str] = None): +def generate_api_and_copy( + output_type, output_copyer, extra_commands: List[str] | None = None +): """ Use OpenApiGenerator to generate the installable API """ @@ -161,7 +171,9 @@ def generate_api_and_copy(output_type, output_copyer, extra_commands: List[str] time.sleep(2) if not succeeded: - return + raise RuntimeError( + f'openapi generation failed after trying {n_attempts} time(s)' + ) output_copyer(tmpdir) shutil.rmtree(tmpdir) @@ -169,7 +181,7 @@ def generate_api_and_copy(output_type, output_copyer, extra_commands: List[str] def generate_schema_file(): """ - Generate schema file and place int he metamist/graphql/ directory + Generate schema file and place in the metamist/graphql/ directory """ command = ['strawberry', 'export-schema', 'api.graphql.schema:schema'] schema = subprocess.check_output(command, stderr=subprocess.STDOUT).decode() @@ -299,21 +311,47 @@ def main(): else: process = start_server() + # Loop until Docker has initialised server and is ready to accept connections + startup_tries = 5 + wait_time_in_seconds = 2 + while (not check_if_server_is_accessible()) and startup_tries > 0: + startup_tries -= 1 + logger.info( + f'Dockerised API server is not ready yet. ' + + f'Retrying in {wait_time_in_seconds} seconds. ' + + f'Remaining tries: {startup_tries}' + ) + time.sleep(wait_time_in_seconds) + try: + assert_server_is_accessible() check_openapi_version() + + # Generate the installable Python API generate_api_and_copy( 'python', copy_python_files_from, ['--template-dir', 'openapi-templates'], ) - generate_api_and_copy('typescript-axios', copy_typescript_files_from) + # Generate the Typescript API for React application + generate_api_and_copy( + 'typescript-axios', + copy_typescript_files_from, + ) + + # Generate the GraphQL schema generate_schema_file() + + # Copy resources and README shutil.copy( './resources/muck-the-duck.svg', os.path.join('web/src', 'muck-the-duck.svg'), ) - shutil.copy('README.md', os.path.join(OUTPUT_DOCS_DIR, 'index.md')) + shutil.copy( + 'README.md', + os.path.join(OUTPUT_DOCS_DIR, 'index.md'), + ) # pylint: disable=broad-except except BaseException as e: diff --git a/setup.py b/setup.py index 2256adf0d..ff82a42dc 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ setup( name=PKG, # This tag is automatically updated by bump2version - version='6.1.0', + version='6.2.0', description='Python API for interacting with the Sample API system', long_description=readme, long_description_content_type='text/markdown', diff --git a/web/src/pages/project/AnalysisRunnerView/AnalysisRunnerSummary.tsx b/web/src/pages/project/AnalysisRunnerView/AnalysisRunnerSummary.tsx index 2a78cbc20..9e44f6677 100644 --- a/web/src/pages/project/AnalysisRunnerView/AnalysisRunnerSummary.tsx +++ b/web/src/pages/project/AnalysisRunnerView/AnalysisRunnerSummary.tsx @@ -20,7 +20,7 @@ const PAGE_SIZES = [20, 40, 100, 1000] const GET_ANALYSIS_RUNNER_LOGS = gql(` query AnalysisRunnerLogs($project_name: String!) { project(name: $project_name) { - analyses(type: { eq: "analysis-runner" }) { + analyses(type: { eq: "analysis-runner" }, status: {eq: UNKNOWN}) { author id meta