diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a3f797b2978e8a6d818790b45c0f82edf307227d..fbe0a46698e49871c68de5ede32c569ee62670ca 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,133 +1,32 @@
-default:
-  image: python:3.12-slim
+include:
+  - project: "cdos-pub/pycode-quality"
+    ref: "main"
+    file:
+      - ".gitlab/ci/static-analysis.yml"
+      - ".gitlab/ci/doc.yml"
+      - ".gitlab/ci/pip.yml"
 
-workflow:
-  rules:
-    - if: $CI_MERGE_REQUEST_ID
-    - if: $CI_COMMIT_BRANCH == 'main'
+variables:
+  IMPL_MODULE_NAME: theia_dumper
 
-cache:
-  paths:
-    - .cache/pip
-    - .venv
+  PYTHON_IMG: python:3.12-slim
 
-before_script:
-  - pip install virtualenv
-  - virtualenv .venv
-  - source .venv/bin/activate
-  - pip install -e .
+  DOC_BUILD_SELF: true
+
+  TWINE_USERNAME: __token__
+  TWINE_PASSWORD: $PYPI_TOKEN
+  PIP_PACKAGE_URL: https://upload.pypi.org/legacy/
 
 stages:
-  - Install
   - Static Analysis
   - Test
-  - Ship
   - Documentation
+  - Pip
 
-# ------------------------------- Install -------------------------------------
-
-pip_install:
-  stage: Install
-  before_script:
-    - python --version ; pip --version
-  script:
-    - pip install .
-    - pip list -v
-
-# ------------------------------ Static analysis ------------------------------
-
-.static_analysis_base:
-  stage: Static Analysis
-  allow_failure: true
-
-flake8:
-  needs:
-    - pip_install
-  extends: .static_analysis_base
-  script:
-    - pip install flake8
-    - flake8 --ignore E501 ./theia_dumper
-
-pylint:
-  needs:
-    - pip_install
-  extends: .static_analysis_base
-  script:
-    - pip install pylint
-    - pylint ./theia_dumper
-
-codespell:
-  needs:
-    - pip_install
-  extends: .static_analysis_base
-  script: 
-    - pip install codespell
-    - codespell ./theia_dumper docs README.md
-
-pydocstyle:
-  needs:
-    - pip_install
-  extends: .static_analysis_base
-  script:
-    - pip install pydocstyle
-    - pydocstyle ./theia_dumper
-
-mypy:
-  needs:
-    - pip_install
-  extends: .static_analysis_base
-  script:
-    - pip install mypy
-    - pip list -v
-    - mypy --install-types --non-interactive .
-
-
-# --------------------------------- Doc ---------------------------------------
-
-.doc_base:
-  stage: Documentation
-  artifacts:
-    paths:
-      - public
-      - public_test
-
-test:
-  extends: .doc_base
-  except:
-    - main
-  script:
-    - pip install -r doc/doc_requirements.txt
-    - mkdocs build --site-dir public_test
-
-pages:
-  extends: .doc_base
-  only:
-    - main
-  script:
-    - pip install -r doc/doc_requirements.txt
-    - mkdocs build --site-dir public
-
-# --------------------------------- Test --------------------------------------
-
-.tests_base:
+Test API:
+  extends: .static_analysis_with_pip_install
   stage: Test
-  except:
-    - main
-
-Tests:
-  extends: .tests_base
-  script:
-   - python tests/all.py
-
-# --------------------------------- Ship --------------------------------------
-
-pypi:
-  stage: Ship
-  only:
-   - main
-  before_script:
-   - python3 -m pip install --upgrade build twine
+  allow_failure: false
+  except: [main]
   script:
-   - python3 -m build
-  after_script:
-   - python3 -m twine upload --repository-url https://upload.pypi.org/legacy/ --non-interactive --verbose -u __token__ -p $pypi_token dist/*
+    - python tests/all.py
diff --git a/README.md b/README.md
index 1c17c93c67a57b64cd6a3f62dc52dc47007936ee..18b4aebdaca6778403e1e92b4739f60b01448fda 100644
--- a/README.md
+++ b/README.md
@@ -21,4 +21,4 @@ For more information read the [documentation](https://cdos-pub.pages.mia.inra.fr
 
 ## Contact
 
-remi cresson @ inrae
+remi cresson @ inrae.fr
diff --git a/doc/access.md b/doc/access.md
index 139249acfabc73666c0c3687654520275e71f8b2..1c59655fe0213c314e117be0c53508285d9c50ea 100644
--- a/doc/access.md
+++ b/doc/access.md
@@ -42,5 +42,5 @@ used, e.g.:
     ...
 ```
 
-Note that collections IDs and buckets/paths prefixes are completely independant.
+Note that collections IDs and buckets/paths prefixes are completely independent.
 
diff --git a/doc/gen_ref_pages.py b/doc/gen_ref_pages.py
index 176c7e46a4006c1b7af5da35e09dcb6146e9618e..9421dbb3ea95f9c03992a77b6df30819e1952aa0 100755
--- a/doc/gen_ref_pages.py
+++ b/doc/gen_ref_pages.py
@@ -17,8 +17,8 @@ for path in sorted(Path("theia_dumper").rglob("*.py")):  #
         continue
 
     with mkdocs_gen_files.open(full_doc_path, "w") as fd:  #
-        identifier = ".".join(parts)  #
-        print("::: " + identifier)
-        print("::: " + identifier, file=fd)  #
+        IDENTIFIER = ".".join(parts)  #
+        print("::: " + IDENTIFIER)
+        print("::: " + IDENTIFIER, file=fd)  #
 
     mkdocs_gen_files.set_edit_path(full_doc_path, path)
diff --git a/pyproject.toml b/pyproject.toml
index 717d8812ab655d5f6ef8f1ef8e1f75062aa19ceb..44ccfbc4c4efe01c2acb3a2ca0a25f499a20410e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
 
 [project]
 name = "theia_dumper"
-version = "0.0.4"
+version = "0.0.5"
 description = "THEIA-MTP geospatial data publisher"
 authors = [{ name = "Rémi Cresson", email = "remi.cresson@inrae.fr" }]
 requires-python = ">=3.9"
@@ -44,5 +44,8 @@ exclude = ["doc", "venv", ".venv"]
 [tool.pylint]
 disable = "W1203,R0903,E0401,W0622,C0116,C0115"
 
+[tool.pylint.MASTER]
+ignore-paths = '^.venv'
+
 [tool.setuptools]
 packages = ["theia_dumper"]
diff --git a/tests/all.py b/tests/all.py
index 9f43d3a0e379191ef6f90a60119a3dc435bb2f4a..f176ec57cc6512c27e95ed410a83b8434872135d 100755
--- a/tests/all.py
+++ b/tests/all.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+"""Test file."""
 
 import os
 import shutil
@@ -17,27 +17,27 @@ handler = stac.TransactionsHandler(
     assets_overwrite=True,
 )
 
-image_href = (
+IMAGE_HREF = (
     "https://gitlab.orfeo-toolbox.org/orfeotoolbox/"
     "otb/-/raw/develop/Data/Input/SP67_FR_subset_1.tif"
 )
 
-col_id = "collection-for-theia-dumper-tests"
+COL_ID = "collection-for-theia-dumper-tests"
 items_ids = ["item_1", "item_2"]
 
-raster_file1 = "/tmp/raster1.tif"
-raster_file2 = "/tmp/raster2.tif"
-with open(raster_file1, "wb") as f:
-    r = requests.get(image_href, timeout=5)
+RASTER_FILE1 = "/tmp/raster1.tif"
+RASTER_FILE2 = "/tmp/raster2.tif"
+with open(RASTER_FILE1, "wb") as f:
+    r = requests.get(IMAGE_HREF, timeout=5)
     f.write(r.content)
-shutil.copyfile(raster_file1, raster_file2)
+shutil.copyfile(RASTER_FILE1, RASTER_FILE2)
 
 
 def clear():
     """Clear all test items and collection."""
     for item_id in items_ids:
-        handler.delete(col_id=col_id, item_id=item_id)
-    handler.delete(col_id=col_id)
+        handler.delete(col_id=COL_ID, item_id=item_id)
+    handler.delete(col_id=COL_ID)
 
 
 def create_item(item_id: str):
@@ -60,8 +60,8 @@ def create_item(item_id: str):
         datetime=datetime.now().replace(year=1999),
         properties={},
         assets={
-            "ndvi": pystac.Asset(href=raster_file1),
-            "crswir": pystac.Asset(href=raster_file2),
+            "ndvi": pystac.Asset(href=RASTER_FILE1),
+            "crswir": pystac.Asset(href=RASTER_FILE2),
         },
     )
 
@@ -73,7 +73,7 @@ def create_collection():
     spat_extent = pystac.SpatialExtent([[0, 0, 2, 3]])
     temp_extent = pystac.TemporalExtent(intervals=[(None, None)])
     col = pystac.Collection(
-        id=col_id,
+        id=COL_ID,
         extent=pystac.Extent(spat_extent, temp_extent),
         description="Some description",
         href="http://hello.fr/collections/collection-for-tests",
diff --git a/theia_dumper/stac.py b/theia_dumper/stac.py
index c120e8f26310db229319caa6d125ec0c2a8ddfd1..b8614a93ddacca76a3e01b6f2bf9ab4191a0db02 100644
--- a/theia_dumper/stac.py
+++ b/theia_dumper/stac.py
@@ -234,8 +234,7 @@ class TransactionsHandler:
             self.publish_item_collection(item_collection=obj)
         else:
             raise TypeError(
-                "Invalid type, must be ItemCollection or Collection "
-                f"(got {type(obj)})"
+                f"Invalid type, must be ItemCollection or Collection (got {type(obj)})"
             )
 
     def delete(self, col_id: str, item_id: str | None = None):