From 6dc1846fbe0b3939a089964bc2b8867db57f4d9d Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:25:01 -0500 Subject: [PATCH 01/15] [lh]inting --- chord_drs/backend.py | 2 +- chord_drs/commands.py | 4 ++-- chord_drs/models.py | 3 +-- chord_drs/routes.py | 37 ++++++++++++++++++++----------------- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/chord_drs/backend.py b/chord_drs/backend.py index 22efb9c..ef12287 100644 --- a/chord_drs/backend.py +++ b/chord_drs/backend.py @@ -23,5 +23,5 @@ def get_backend() -> Optional[Backend]: return g.backend -def close_backend(_e=None): +def close_backend(_e=None) -> None: g.pop("backend", None) diff --git a/chord_drs/commands.py b/chord_drs/commands.py index 5dd3c9b..5c9e411 100644 --- a/chord_drs/commands.py +++ b/chord_drs/commands.py @@ -33,7 +33,7 @@ def create_drs_bundle(location: str, parent: Optional[DrsBundle] = None) -> DrsB return bundle -def create_drs_object(location: str, parent: Optional[DrsBundle] = None): +def create_drs_object(location: str, parent: Optional[DrsBundle] = None) -> None: drs_object = DrsObject(location=location) if parent: @@ -47,7 +47,7 @@ def create_drs_object(location: str, parent: Optional[DrsBundle] = None): @click.command("ingest") @click.argument("source") @with_appcontext -def ingest(source: str): +def ingest(source: str) -> None: """ When provided with a file or a directory, this command will add these to our list of objects, to be served by the application. diff --git a/chord_drs/models.py b/chord_drs/models.py index 62a4ef5..11cd1df 100644 --- a/chord_drs/models.py +++ b/chord_drs/models.py @@ -9,7 +9,6 @@ from chord_drs.backend import get_backend from chord_drs.backends.minio import MinioBackend -from chord_drs.constants import SERVICE_NAME from chord_drs.db import db from chord_drs.utils import drs_file_checksum @@ -77,7 +76,7 @@ def __init__(self, *args, **kwargs): try: current_location = backend.save(location, new_filename) except Exception as e: - current_app.logger.error(f"[{SERVICE_NAME}] Encountered exception during DRS object creation: {e}") + current_app.logger.error(f"Encountered exception during DRS object creation: {e}") # TODO: implement more specific exception handling raise Exception("Well if the file is not saved... we can't do squat") diff --git a/chord_drs/routes.py b/chord_drs/routes.py index 9225ad7..b415f8d 100644 --- a/chord_drs/routes.py +++ b/chord_drs/routes.py @@ -94,7 +94,7 @@ def build_object_json(drs_object: DrsObject, inside_container: bool = False) -> default_access_method = { "access_url": { "url": url_for("drs_service.object_download", object_id=drs_object.id, _external=True) - # No headers means that auth will have to be obtained via some + # No headers --> auth will have to be obtained via some # out-of-band method, or the object's contents are public. This # will depend on how the service is deployed. }, @@ -187,8 +187,8 @@ def service_info(): @drs_service.route("/objects/", methods=["GET"]) @drs_service.route("/ga4gh/drs/v1/objects/", methods=["GET"]) def object_info(object_id: str): - drs_bundle = DrsBundle.query.filter_by(id=object_id).first() - drs_object = None + drs_bundle: Optional[DrsBundle] = DrsBundle.query.filter_by(id=object_id).first() + drs_object: Optional[DrsObject] = None if not drs_bundle: # Only try hitting the database for an object if no bundle was found drs_object = DrsObject.query.filter_by(id=object_id).first() @@ -196,21 +196,21 @@ def object_info(object_id: str): if not drs_object: return flask_errors.flask_not_found_error("No object found for this ID") - # Are we inside the bento singularity container? if so, provide local accessmethod - inside_container = request.headers.get("X-CHORD-Internal", "0") == "1" - # Log X-CHORD-Internal header - current_app.logger.info( - f"[{SERVICE_NAME}] object_info X-CHORD-Internal: {request.headers.get('X-CHORD-Internal', 'not set')}" - ) + current_app.logger.info(f"object_info X-CHORD-Internal: {request.headers.get('X-CHORD-Internal', 'not set')}") + + # Are we inside the bento singularity container? if so, provide local access method + inside_container = request.headers.get("X-CHORD-Internal", "0") == "1" # The requester can specify object internal path to be added to the response use_internal_path = strtobool(request.args.get("internal_path", "")) + include_internal_path = inside_container or use_internal_path + if drs_bundle: - response = build_bundle_json(drs_bundle, inside_container=(inside_container or use_internal_path)) + response = build_bundle_json(drs_bundle, inside_container=include_internal_path) else: - response = build_object_json(drs_object, inside_container=(inside_container or use_internal_path)) + response = build_object_json(drs_object, inside_container=include_internal_path) return jsonify(response) @@ -237,6 +237,8 @@ def object_search(): @drs_service.route("/objects//download", methods=["GET"]) def object_download(object_id): + logger = current_app.logger + try: drs_object = DrsObject.query.filter_by(id=object_id).one() except NoResultFound: @@ -256,23 +258,23 @@ def object_download(object_id): download_name=drs_object.name, ) - current_app.logger.debug(f"Found Range header: {range_header}") + logger.debug(f"Found Range header: {range_header}") rh_split = range_header.split("=") if len(rh_split) != 2 or rh_split[0] != "bytes": err = f"Malformatted range header: expected bytes=X-Y or bytes=X-, got {range_header}" - current_app.logger.error(err) + logger.error(err) return flask_errors.flask_bad_request_error(err) byte_range = rh_split[1].strip().split("-") - current_app.logger.debug(f"Retrieving byte range {byte_range}") + logger.debug(f"Retrieving byte range {byte_range}") start = int(byte_range[0]) end = int(byte_range[1]) if byte_range[1] else None if end is not None and end < start: err = f"Invalid range header: end cannot be less than start (start={start}, end={end})" - current_app.logger.error(err) + logger.error(err) return flask_errors.flask_bad_request_error(err) def generate_bytes(): @@ -282,7 +284,7 @@ def generate_bytes(): # Then, read in either CHUNK_SIZE byte segments or however many bytes are left to send, whichever is # left. This avoids filling memory with the contents of large files. - byte_offset = start + byte_offset: int = start while True: # Add a 1 to the amount to read if it's below chunk size, because the last coordinate is inclusive. data = fh2.read(min(CHUNK_SIZE, (end + 1 - byte_offset) if end is not None else CHUNK_SIZE)) @@ -319,6 +321,7 @@ def generate_bytes(): @drs_service.route("/private/ingest", methods=["POST"]) def object_ingest(): + logger = current_app.logger data = request.json or {} obj_path: str = data.get("path") @@ -342,7 +345,7 @@ def object_ingest(): db.session.add(drs_object) db.session.commit() except Exception as e: # TODO: More specific handling - current_app.logger.error(f"[{SERVICE_NAME}] Encountered exception during ingest: {e}") + logger.error(f"Encountered exception during ingest: {e}") return flask_errors.flask_bad_request_error("Error while creating the object") response = build_object_json(drs_object) From fbcf186441a15c43bf83c0339472de8de65abe1d Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:25:24 -0500 Subject: [PATCH 02/15] chore!: default deduplication to True instead of False --- chord_drs/routes.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/chord_drs/routes.py b/chord_drs/routes.py index b415f8d..222a55c 100644 --- a/chord_drs/routes.py +++ b/chord_drs/routes.py @@ -329,14 +329,15 @@ def object_ingest(): if not obj_path or not isinstance(obj_path, str): return flask_errors.flask_bad_request_error("Missing or invalid path parameter in JSON request") - # TODO: Should this always be the case? - deduplicate: bool = data.get("deduplicate", False) - drs_object: Optional[DrsObject] = None + deduplicate: bool = data.get("deduplicate", True) # Change for v0.9: default to True + if deduplicate: # Get checksum of original file, and query database for objects that match checksum = drs_file_checksum(obj_path) drs_object = DrsObject.query.filter_by(checksum=checksum).first() + if drs_object: + logger.info(f"Found duplicate DRS object via checksum (will deduplicate): {drs_object}") if not drs_object: try: From 3c47fea879f470d103ac45d99b646515a807f758 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:25:48 -0500 Subject: [PATCH 03/15] feat: git commit in bento service-info --- chord_drs/routes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chord_drs/routes.py b/chord_drs/routes.py index 222a55c..8df8057 100644 --- a/chord_drs/routes.py +++ b/chord_drs/routes.py @@ -176,6 +176,8 @@ def service_info(): res_branch_str = res_branch.decode().strip() info["git_branch"] = res_branch_str info["bento"]["gitBranch"] = res_branch_str + if res_commit := subprocess.check_output(["git", "rev-parse", "HEAD"]): + info["bento"]["gitCommit"] = res_commit.decode().strip() except Exception as e: except_name = type(e).__name__ From ca87184be64bd511117079e29eee81690c963710 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:25:55 -0500 Subject: [PATCH 04/15] chore: additional logging --- chord_drs/routes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chord_drs/routes.py b/chord_drs/routes.py index 8df8057..2852637 100644 --- a/chord_drs/routes.py +++ b/chord_drs/routes.py @@ -329,6 +329,7 @@ def object_ingest(): obj_path: str = data.get("path") if not obj_path or not isinstance(obj_path, str): + logger.error(f"Missing or invalid path parameter in JSON request: {obj_path}") return flask_errors.flask_bad_request_error("Missing or invalid path parameter in JSON request") drs_object: Optional[DrsObject] = None @@ -344,9 +345,9 @@ def object_ingest(): if not drs_object: try: drs_object = DrsObject(location=obj_path) - db.session.add(drs_object) db.session.commit() + logger.info(f"Added DRS object: {drs_object}") except Exception as e: # TODO: More specific handling logger.error(f"Encountered exception during ingest: {e}") return flask_errors.flask_bad_request_error("Error while creating the object") From 8ae8d41c368750a4e1ad37ab267842775898a683 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:26:01 -0500 Subject: [PATCH 05/15] chore: bump version to 0.9.0 --- chord_drs/package.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chord_drs/package.cfg b/chord_drs/package.cfg index e35a06b..f59d4ab 100644 --- a/chord_drs/package.cfg +++ b/chord_drs/package.cfg @@ -1,5 +1,5 @@ [package] name = chord_drs -version = 0.8.0 +version = 0.9.0 authors = Simon Chénard, David Lougheed author_emails = simon.chenard2@mcgill.ca, david.lougheed@mail.mcgill.ca From f213ca8e8ad2e9bdfb19b34042fbca33a291302e Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:31:51 -0500 Subject: [PATCH 06/15] chore: update test deps --- requirements.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index bbc1f6b..8cce86b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -66,16 +66,17 @@ pytz==2022.7.1 PyYAML==5.4.1 redis==3.5.3 requests==2.28.2 -responses==0.13.4 +responses==0.22.0 s3transfer==0.5.0 six==1.16.0 SQLAlchemy==1.4.46 toml==0.10.2 tomli==2.0.1 -tox==4.3.5 +tox==4.4.4 +types-toml==0.10.8.3 urllib3==1.26.14 -virtualenv==20.17.1 +virtualenv==20.18.0 Werkzeug==2.2.2 xmltodict==0.12.0 yarl==1.8.2 -zipp==3.11.0 +zipp==3.12.1 From cb266c299832c8b7fb426697ec63dc720737fd8c Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:32:04 -0500 Subject: [PATCH 07/15] fix: handle file not found when checking checksum for dedup --- chord_drs/routes.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/chord_drs/routes.py b/chord_drs/routes.py index 2852637..a9fe5e2 100644 --- a/chord_drs/routes.py +++ b/chord_drs/routes.py @@ -337,7 +337,14 @@ def object_ingest(): if deduplicate: # Get checksum of original file, and query database for objects that match - checksum = drs_file_checksum(obj_path) + + try: + checksum = drs_file_checksum(obj_path) + except FileNotFoundError: + err = f"File not found at path {obj_path}" + logger.error(err) + return flask_errors.flask_bad_request_error(err) + drs_object = DrsObject.query.filter_by(checksum=checksum).first() if drs_object: logger.info(f"Found duplicate DRS object via checksum (will deduplicate): {drs_object}") From 438b3cfc1512f4140115c4238082c6574860be41 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:32:11 -0500 Subject: [PATCH 08/15] fix: tests --- tests/test_routes.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index 4fe9820..0684d68 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -213,11 +213,11 @@ def test_object_ingest(client): def test_object_ingest_x2(client): data_1 = _ingest_one(client) - data_2 = _ingest_one(client) - assert data_1["id"] != data_2["id"] + data_2 = _ingest_one(client, data_1["id"]) + assert json.dumps(data_1, sort_keys=True) == json.dumps(data_2, sort_keys=True) # deduplicate is True by default -def test_object_ingest_deduplicate(client): +def test_object_ingest_no_deduplicate(client): data_1 = _ingest_one(client) - data_2 = _ingest_one(client, data_1["id"], {"deduplicate": True}) - assert json.dumps(data_1, sort_keys=True) == json.dumps(data_2, sort_keys=True) + data_2 = _ingest_one(client, params={"deduplicate": False}) + assert json.dumps(data_1, sort_keys=True) != json.dumps(data_2, sort_keys=True) From ef72c9f39840218413fa62b36c72e951d49a586f Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:52:03 -0500 Subject: [PATCH 09/15] fix: range header error handling test: range header error states --- chord_drs/routes.py | 14 +++++++++----- tests/test_routes.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/chord_drs/routes.py b/chord_drs/routes.py index a9fe5e2..15001b6 100644 --- a/chord_drs/routes.py +++ b/chord_drs/routes.py @@ -261,18 +261,22 @@ def object_download(object_id): ) logger.debug(f"Found Range header: {range_header}") + range_err = f"Malformatted range header: expected bytes=X-Y or bytes=X-, got {range_header}" rh_split = range_header.split("=") if len(rh_split) != 2 or rh_split[0] != "bytes": - err = f"Malformatted range header: expected bytes=X-Y or bytes=X-, got {range_header}" - logger.error(err) - return flask_errors.flask_bad_request_error(err) + logger.error(range_err) + return flask_errors.flask_bad_request_error(range_err) byte_range = rh_split[1].strip().split("-") logger.debug(f"Retrieving byte range {byte_range}") - start = int(byte_range[0]) - end = int(byte_range[1]) if byte_range[1] else None + try: + start = int(byte_range[0]) + end = int(byte_range[1]) if byte_range[1] else None + except (IndexError, ValueError): + logger.error(range_err) + return flask_errors.flask_bad_request_error(range_err) if end is not None and end < start: err = f"Invalid range header: end cannot be less than start (start={start}, end={end})" diff --git a/tests/test_routes.py b/tests/test_routes.py index 0684d68..f087518 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -84,6 +84,7 @@ def _test_object_and_download(client, obj, test_range=False): assert len(body) == 1900 # Size is 2455, so these'll run off the end and return the whole thing after 100 + res = client.get(data["access_methods"][0]["access_url"]["url"], headers=(("Range", "bytes=100-19999"),)) assert res.status_code == 206 body = res.get_data(as_text=False) @@ -98,6 +99,17 @@ def _test_object_and_download(client, obj, test_range=False): body = res.get_data(as_text=False) assert len(body) == 2455 + # Test range error state + + res = client.get(data["access_methods"][0]["access_url"]["url"], headers=(("Range", "bytes"),)) + assert res.status_code == 400 + + res = client.get(data["access_methods"][0]["access_url"]["url"], headers=(("Range", "bytes="),)) + assert res.status_code == 400 + + res = client.get(data["access_methods"][0]["access_url"]["url"], headers=(("Range", "bites=0-4"),)) + assert res.status_code == 400 + def test_object_and_download_minio(client_minio, drs_object_minio): _test_object_and_download(client_minio, drs_object_minio) From f7beee21704cde4af5cad38ec6e55d508592bf07 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:53:07 -0500 Subject: [PATCH 10/15] test: reversed byte range --- tests/test_routes.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_routes.py b/tests/test_routes.py index f087518..b5e0c23 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -101,15 +101,22 @@ def _test_object_and_download(client, obj, test_range=False): # Test range error state + # - no range, no equals res = client.get(data["access_methods"][0]["access_url"]["url"], headers=(("Range", "bytes"),)) assert res.status_code == 400 + # - no range, with equals res = client.get(data["access_methods"][0]["access_url"]["url"], headers=(("Range", "bytes="),)) assert res.status_code == 400 + # - typo for bytes res = client.get(data["access_methods"][0]["access_url"]["url"], headers=(("Range", "bites=0-4"),)) assert res.status_code == 400 + # - reversed interval + res = client.get(data["access_methods"][0]["access_url"]["url"], headers=(("Range", "bytes=4-0"),)) + assert res.status_code == 400 + def test_object_and_download_minio(client_minio, drs_object_minio): _test_object_and_download(client_minio, drs_object_minio) From 411dcdf6d354cf219e59551a2cd3517ef1f2334e Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 14:59:39 -0500 Subject: [PATCH 11/15] test file checksum directly + increase chunk size for checksumming --- chord_drs/utils.py | 4 +++- tests/conftest.py | 1 + tests/empty_file.txt | 0 tests/test_checksum.py | 10 ++++++++++ 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/empty_file.txt create mode 100644 tests/test_checksum.py diff --git a/chord_drs/utils.py b/chord_drs/utils.py index ebeb62f..5b40e40 100644 --- a/chord_drs/utils.py +++ b/chord_drs/utils.py @@ -3,12 +3,14 @@ __all__ = ["drs_file_checksum"] +CHUNK_SIZE = 16 * 1024 + def drs_file_checksum(path: str) -> str: hash_obj = sha256() with open(path, "rb") as f: - for chunk in iter(lambda: f.read(4096), b""): + while chunk := f.read(CHUNK_SIZE): hash_obj.update(chunk) return hash_obj.hexdigest() diff --git a/tests/conftest.py b/tests/conftest.py index 729bd51..5733cf0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,6 +19,7 @@ NON_EXISTENT_DUMMY_FILE = os.path.join(BASEDIR, "potato") DUMMY_FILE = os.path.join(BASEDIR, "tests", "dummy_file.txt") DUMMY_DIRECTORY = os.path.join(APP_DIR, "migrations") +EMPTY_FILE = os.path.join(BASEDIR, "tests", "empty_file.txt") @pytest.fixture diff --git a/tests/empty_file.txt b/tests/empty_file.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_checksum.py b/tests/test_checksum.py new file mode 100644 index 0000000..42dddd6 --- /dev/null +++ b/tests/test_checksum.py @@ -0,0 +1,10 @@ +from .conftest import DUMMY_FILE, EMPTY_FILE +from chord_drs.utils import drs_file_checksum + + +def test_sha256_checksum(): + # see https://crypto.stackexchange.com/questions/26133/sha-256-hash-of-null-input + assert drs_file_checksum(EMPTY_FILE) == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + + # file with content + assert drs_file_checksum(DUMMY_FILE) == "ca5170c51e4d4e68d4c39832489ea9ad8e275c9f46e0c195c86aaf61ee2ce3d8" From 801b9e376b12fc05065623bbebc8f8baeb6e5dda Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Tue, 7 Feb 2023 15:10:37 -0500 Subject: [PATCH 12/15] docs: document deduplicate: false option for ingest --- README.md | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a4c1693..ad9943e 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,12 @@ A proof of concept based on [GA4GH's DRS specifications](https://ga4gh.github.io/data-repository-service-schemas/preview/release/drs-1.0.0/docs/). This flask application offers an interface to query files in such -a fashion: "drs://some-domain/some-ID". +a fashion: `drs://some-domain/some-ID`. For storing the files, two methods are currently supported : in the current filesystem or inside a MinIO instance (which is a s3-like software). + ## TODO / Future considerations - Ingesting is either through the command line or by the endpoint of the same name @@ -19,6 +20,7 @@ or inside a MinIO instance (which is a s3-like software). - Consider how to be aware of http vs https depending on the deployment setup (in singularity, docker, as is). + ## Configuration At the root of this project there is a sample dotenv file (.env-sample). These can be @@ -29,6 +31,7 @@ provide the missing values. cp .env-sample .env ``` + ## Running in Development Development dependencies are described in `requirements.txt` and can be @@ -57,6 +60,7 @@ The Flask development server can be run with the following command: FLASK_DEBUG=True flask run ``` + ## Running Tests To run all tests and calculate coverage, run the following command: @@ -69,6 +73,7 @@ Tox is configured to run both pytest and flake8, you may want to uncomment the second line of tox.ini (envlist = ...) so as to run these commands for multiple versions of Python. + ## Deploying In production, the service should be deployed using a WSGI service like @@ -78,6 +83,7 @@ With uWSGI you should point to chord_drs.app:application, the wsgi.py file at the root of the project is there to simplify executing the commands (such as "ingest") + ## API ##### GET a single object @@ -86,6 +92,8 @@ as "ingest") `/ga4gh/drs/v1/objects/` +Returns a standard GA4GH record for the object. + ##### GET search `/search` @@ -105,9 +113,20 @@ partial match `/search?fuzzy_name=1001` e.g. POST body -```bash +```json { - "path": "examples/P-1001.hc.g.vcf.gz" + "path": "examples/P-1001.hc.g.vcf.gz" +} +``` + +This will automatically deduplicate with existing DRS objects if the file matches. + +To ingest and force-create a duplicate record, provide the `deduplicate` parameter, set to `false`: + +```json +{ + "path": "examples/P-1001.hc.g.vcf.gz", + "deduplicate": false } ``` @@ -115,3 +134,5 @@ e.g. POST body ##### GET service info `/service-info` + +Returns a GA4GH+Bento-formatted service info response. From 988e8b0bf8c62940d227f748fdca3b2a5be331cb Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Thu, 9 Feb 2023 12:39:24 -0500 Subject: [PATCH 13/15] chore: set gitconfig for dev docker image --- entrypoint.dev.bash | 3 +++ 1 file changed, 3 insertions(+) diff --git a/entrypoint.dev.bash b/entrypoint.dev.bash index 48d06fd..896439e 100644 --- a/entrypoint.dev.bash +++ b/entrypoint.dev.bash @@ -1,5 +1,8 @@ #!/bin/bash +# Set .gitconfig for development +/set_gitconfig.bash + export FLASK_ENV=development export FLASK_APP=chord_drs.app:application From 8dd45b125c0b7ea065564079b679ac7fa2aed217 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Thu, 9 Feb 2023 12:39:40 -0500 Subject: [PATCH 14/15] ci: bump bba to 0.10.1 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bff85b4..a5be06a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v3 - name: Run Bento build action - uses: bento-platform/bento_build_action@v0.9.3 + uses: bento-platform/bento_build_action@v0.10.1 with: registry: ghcr.io registry-username: ${{ github.actor }} From ccc0a4ce82eb0c2a32ed049b43a692d5eb5ba349 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Thu, 9 Feb 2023 12:40:08 -0500 Subject: [PATCH 15/15] chore: update docker base image ver --- Dockerfile | 2 +- dev.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 45ed903..5d9a701 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/bento-platform/bento_base_image:python-debian-2022.12.06 +FROM ghcr.io/bento-platform/bento_base_image:python-debian-2023.02.09 # TODO: change USER USER root diff --git a/dev.Dockerfile b/dev.Dockerfile index d27e5a3..dfa16bf 100644 --- a/dev.Dockerfile +++ b/dev.Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/bento-platform/bento_base_image:python-debian-2022.12.06 +FROM ghcr.io/bento-platform/bento_base_image:python-debian-2023.02.09 # TODO: change USER USER root