diff --git a/eossr/api/tests/__init__.py b/eossr/api/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/eossr/api/tests/test_zenodo.py b/eossr/api/tests/test_zenodo.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d84ead5c672274dddf9e0de7b27791a885c0c7a
--- /dev/null
+++ b/eossr/api/tests/test_zenodo.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+
+import json
+import unittest
+import requests
+from pathlib import Path
+from os import remove
+from os.path import dirname, realpath, join
+from eossr.api.zenodo import ZenodoAPI
+
+ROOT_DIR = dirname(realpath("codemeta.json"))
+
+
+class TestZenodoApiSandbox(unittest.TestCase):
+    def test_initialization_sandbox(self):
+        token = 'FakeToken'
+        z = ZenodoAPI(access_token=token,
+                      sandbox=True,
+                      proj_root_dir=ROOT_DIR)
+
+        assert isinstance(z, ZenodoAPI)
+        assert z.zenodo_api_url == 'https://sandbox.zenodo.org/api'
+        assert z.access_token == token
+        assert type(z.exist_codemeta_file) == bool
+        assert type(z.exist_zenodo_metadata_file) == bool
+        assert z.proj_root_dir == Path(ROOT_DIR)
+        assert z.path_codemeta_file == z.proj_root_dir
+        assert z.path_zenodo_metadata_file == z.proj_root_dir
+        assert isinstance(z.proj_root_dir, (Path, str))
+
+
+class TestZenodoAPI(unittest.TestCase):
+    def test_initialization(self):
+        token = 'FakeToken'
+        z = ZenodoAPI(access_token=token,
+                      sandbox=False,
+                      proj_root_dir=ROOT_DIR)
+
+        assert isinstance(z, ZenodoAPI)
+        assert z.zenodo_api_url == 'https://zenodo.org/api'
+        assert z.access_token == token
+        assert type(z.exist_codemeta_file) == bool
+        assert type(z.exist_zenodo_metadata_file) == bool
+        assert z.proj_root_dir == Path(ROOT_DIR)
+        assert z.path_codemeta_file == z.proj_root_dir
+        assert z.path_zenodo_metadata_file == z.proj_root_dir
+        assert isinstance(z.proj_root_dir, (Path, str))
+
+    def test_zenodo_api_methods(self):
+        token = 'FakeToken'
+        z = ZenodoAPI(access_token=token,
+                      sandbox=False,
+                      proj_root_dir=ROOT_DIR)
+
+        test_id = '42'
+        z.search_codemeta_file()
+        test_filename = join(ROOT_DIR, z.path_codemeta_file)
+        path_test_filename = './'
+
+        fetch_user_entry = z.fetch_user_entries()
+        create_new_entry = z.create_new_entry()
+        fetch_single_entry = z.fetch_entry(
+            entry_id=test_id
+        )
+        # upload_file_entry = z.upload_file_entry(
+        #     entry_id=test_id,
+        #     name_file=test_filename,
+        #     path_file=path_test_filename
+        # )
+        upload_metadata_entry = z.update_metadata_entry(
+            entry_id=test_id,
+            json_metadata=test_filename
+        )
+        erase_entry = z.erase_entry(
+            entry_id=test_id
+        )
+        erase_file_entry = z.erase_file_entry(
+            entry_id=test_id,
+            file_id=test_id
+        )
+        publish_entry = z.publish_entry(
+            entry_id=test_id
+        )
+        new_version_entry = z.new_version_entry(
+            entry_id=test_id
+        )
+        community_entries = z.fetch_community_entries()
+        fetch_ids = z.fetch_community_entries_per_id()
+        fetch_filenames = z.fetch_community_entries_per_title()
+
+        assert isinstance(fetch_user_entry, requests.models.Response)
+        assert isinstance(create_new_entry, requests.models.Response)
+        assert isinstance(fetch_single_entry, requests.models.Response)
+        # assert isinstance(upload_file_entry, requests.models.Response)
+        assert isinstance(upload_metadata_entry, requests.models.Response)
+        assert isinstance(erase_entry, requests.models.Response)
+        assert isinstance(erase_file_entry, requests.models.Response)
+        assert isinstance(publish_entry, requests.models.Response)
+        assert isinstance(new_version_entry, requests.models.Response)
+        assert isinstance(community_entries, requests.models.Response)
+        assert isinstance(fetch_ids, list)
+        assert isinstance(fetch_filenames, list)
+
+    def test_search_codemeta_file(self):
+        token = 'FakeToken'
+        z = ZenodoAPI(access_token=token,
+                      sandbox=False,
+                      proj_root_dir=ROOT_DIR)
+
+        assert z.exist_codemeta_file is False
+        z.search_codemeta_file()
+        assert z.exist_codemeta_file is True
+
+        codemeta_file_path = Path(ROOT_DIR) / 'codemeta.json'
+        assert z.path_codemeta_file == codemeta_file_path
+        assert codemeta_file_path.is_file()
+        print(z.path_codemeta_file, type(z.path_codemeta_file))
+        with open(z.path_codemeta_file) as f:
+            json.load(f)
+
+    def test_search_zenodo_json_file(self):
+        token = 'FakeToken'
+        z = ZenodoAPI(access_token=token,
+                      sandbox=False,
+                      proj_root_dir=ROOT_DIR)
+
+        assert z.exist_zenodo_metadata_file is False
+        z.search_zenodo_json_file()
+        assert z.exist_zenodo_metadata_file is False
+
+    def test_conversion_codemeta2zenodo_and_search_zenodo_file(self):
+        token = 'FakeToken'
+        z = ZenodoAPI(access_token=token,
+                      sandbox=False,
+                      proj_root_dir=ROOT_DIR)
+
+        z.search_codemeta_file()
+        z.conversion_codemeta2zenodo()
+
+        z.search_zenodo_json_file()
+        assert z.exist_zenodo_metadata_file is True
+
+        zenodo_file_path = Path(ROOT_DIR) / '.zenodo.json'
+        assert z.path_zenodo_metadata_file == zenodo_file_path
+        assert zenodo_file_path.is_file()
+        with open(z.path_zenodo_metadata_file) as f:
+            json.load(f)
+
+        remove(z.path_zenodo_metadata_file)
diff --git a/eossr/api/zenodo.py b/eossr/api/zenodo.py
new file mode 100644
index 0000000000000000000000000000000000000000..36b0ef88592c5391094119715afd0f6fc567cad5
--- /dev/null
+++ b/eossr/api/zenodo.py
@@ -0,0 +1,403 @@
+#!/usr/bin/env python
+
+import sys
+import json
+import pprint
+import requests
+from os.path import abspath
+from pathlib import Path
+from ..metadata.codemeta2zenodo import parse_codemeta_and_write_zenodo_metadata_file
+
+
+class ZenodoAPI:
+    def __init__(self, access_token, sandbox=True, proj_root_dir='./'):
+        """
+        Manages the communication with the (sandbox.)zenodo REST API through the Python request library.
+        This class is **EXCLUSIVELY** developed to be used within a CI/CD pipeline and to **EXCLUSIVELY PERFORM**
+         the following tasks within the (sandbox.)zenodo api environment:
+
+          - Fetches a user's published entries,
+          - Creates a new deposit,
+          - Fetches any published record,
+          - Creates a new version of an existing deposit,
+          - Uploads files to a specific Zenodo entry,
+          - Erases a non-published entry / new version draft,
+          - Erases (old version) files from an entry (when creating a new_version entry and uploading
+            new_version files),
+          - Uploads information to the entry (Zenodo compulsory deposit information),
+          - Publishes an entry
+          - Find all the published community entries
+            * per title
+            * per entry_id
+
+
+        :param access_token: str
+            Personal access token to (sandbox.)zenodo.org/api
+        :param sandbox: bool
+            Communicates with either zenodo or sandbox.zenodo api
+        """
+
+        if sandbox:
+            zenodo_api_url = "https://sandbox.zenodo.org/api"
+        else:
+            zenodo_api_url = "https://zenodo.org/api"
+
+        self.zenodo_api_url = zenodo_api_url
+        self.access_token = access_token
+        self.parameters = {'access_token': self.access_token}
+
+        self.proj_root_dir = Path(proj_root_dir)
+        self.exist_codemeta_file = False
+        self.path_codemeta_file = self.proj_root_dir
+        self.exist_zenodo_metadata_file = False
+        self.path_zenodo_metadata_file = self.proj_root_dir
+
+    def fetch_user_entries(self):
+        """
+        Fetch the published entries of an user. Works to tests connection to Zenodo too.
+
+        GET method to {zenodo_api_url}/deposit/depositions
+
+        :return: request.get method
+        """
+        url = f"{self.zenodo_api_url}/deposit/depositions"
+
+        return requests.get(url, params=self.parameters)
+
+    def create_new_entry(self):
+        """
+        Create a new entry / deposition in (sandbox.)zenodo
+
+        POST method to {zenodo_api_url}/deposit/depositions
+
+        :return: request.put method
+        """
+        url = f"{self.zenodo_api_url}/deposit/depositions"
+        headers = {"Content-Type": "application/json"}
+
+        return requests.post(url, json={}, headers=headers, params=self.parameters)
+
+    def fetch_entry(self, entry_id):
+        """
+        Fetches (recovers all the existing information, as well as links) of an existing Zenodo entry.
+
+        GET method to {zenodo_api_url}/deposit/depositions/{entry_id}
+
+        :param entry_id: str
+            entry_id of the entry to fetch
+
+        :return: request.get method
+        """
+        # In case of entries created by oneself, or entries in the process of being created, the method to fetch
+        # a record is request.get('api/deposit/deposition/{entry_id}') - see also the upload_file_entry method.
+
+        # To fetch any other entry, already published, use:
+        url = f"{self.zenodo_api_url}/records/{entry_id}"
+        return requests.get(url, params=self.parameters)
+
+    def upload_file_entry(self, entry_id, name_file, path_file):
+        """
+        Upload a file to a Zenodo entry. If first retrieve the entry by a GET method to the
+            {zenodo_api_url}/deposit/depositions/{entry_id}.
+
+        PUT method to {bucket_url}/{filename}. The full api url is recovered when the entry is firstly retrieved.
+
+        :param entry_id: str
+            deposition_id of the Zenodo entry
+        :param name_file: str
+            File name of the file when uploaded
+        :param path_file: str
+            Path to the file to be uploaded
+
+        :return: request.put method
+        """
+        # 1 - Retrieve and recover information of a record that is in process of being published
+        fetch = requests.get(f"{self.zenodo_api_url}/deposit/depositions/{entry_id}",
+                             params=self.parameters)
+
+        # 2 - Upload the files
+        bucket_url = fetch.json()['links']['bucket']  # full url is recovered from previous GET method
+        url = f"{bucket_url}/{name_file}"
+
+        with open(path_file, 'rb') as upload_file:
+            upload = requests.put(url, data=upload_file, params=self.parameters)
+
+        return upload.json()
+
+    def update_metadata_entry(self, entry_id, json_metadata):
+        """
+        Update an entry resource. Data should be the entry information that will be shown when a deposition is visited
+        at the Zenodo site.
+
+        PUT method to {zenodo_api_url}/deposit/depositions/{entry_id}. `data` MUST be included as json.dump(data)
+
+        :param entry_id: str
+            deposition_id of the Zenodo entry
+        :param json_metadata: object
+            json object containing the metadata (compulsory fields) that are enclosed when a new entry is created.
+
+        :return: request.put method
+        """
+        url = f"{self.zenodo_api_url}/deposit/depositions/{entry_id}"
+        headers = {"Content-Type": "application/json"}
+
+        # The metadata field is already created, just need to be updated.
+        # Thus the root 'metadata' key need to be kept, to indicate the field to be updated.
+        data = {"metadata": json_metadata}
+
+        return requests.put(url, data=json.dumps(data),
+                            headers=headers, params=self.parameters)
+
+    def erase_entry(self, entry_id):
+        """
+        Erase an entry/new version of an entry that HAS NOT BEEN published yet.
+        Any new upload/version will be first saved as 'draft' and not published until confirmation (i.e, requests.post)
+
+        DELETE method to {zenodo_api_url}/deposit/depositions/{entry_id}.
+
+        :param entry_id: str
+            deposition_id of the Zenodo entry to be erased
+
+        :return: request.delete method
+        """
+        url = f"{self.zenodo_api_url}/deposit/depositions/{entry_id}"
+        return requests.delete(url, params=self.parameters)
+
+    def erase_file_entry(self, entry_id, file_id):
+        """
+        Erase a file from an entry resource.
+        This method is intended to be used for substitution of files (deletion) within an entry by their correspondent
+         new versions.
+        DELETE method to {zenodo_api_url}/deposit/depositions/{entry_id}/files/{file_id}
+
+        :param entry_id: str
+            deposition_id of the Zenodo entry
+        :param file_id: str
+            Id of the files stored in Zenodo
+
+        :return: requests.delete method
+        """
+        url = f"{self.zenodo_api_url}/deposit/depositions/{entry_id}/files/{file_id}"
+        return requests.delete(url, params=self.parameters)
+
+    def publish_entry(self, entry_id):
+        """
+        Publishes an entry in (sandbox.)zenodo
+        POST method to {zenodo_api_url}/deposit/depositions/{entry_id}/actions/publish
+
+        :param entry_id: str
+            deposition_id of the Zenodo entry
+
+        :return: requests.put method
+        """
+        url = f"{self.zenodo_api_url}/deposit/depositions/{entry_id}/actions/publish"
+        return requests.post(url, params=self.parameters)
+
+    def new_version_entry(self, entry_id):
+        """
+        Creates a new version of AN EXISTING entry resource.
+        POST method to {zenodo_api_url}/deposit/depositions/{entry_id}/actions/newversion
+
+        :param entry_id: str
+            deposition_id of the Zenodo entry
+
+        :return: requests.post method
+        """
+        url = f"{self.zenodo_api_url}/deposit/depositions/{entry_id}/actions/newversion"
+        parameters = {'access_token': self.access_token}
+
+        return requests.post(url, params=parameters)
+
+    def fetch_community_entries(self, community_name='escape2020', results_per_query=100):
+        """
+        Query the entries within a community.
+        GET method, previous modification of the query arguments, to {zenodo_api_url}/records
+
+
+        :param community_name: str
+            Community name. DEFAULT='escape2020'
+        :param results_per_query: int
+            Number of entries returned per call to the REST API. DEFAULT=100.
+
+        :return: requests.get method
+        """
+        # https://developers.zenodo.org/#list36
+        update_query_args = {'communities': str(community_name),
+                             'size': int(results_per_query)
+                             }
+        self.parameters.update(update_query_args)
+
+        # Full answer
+        #   content = requests.post(url, params=self.parameters)
+        # Answer items
+        #   content.json().keys()
+        # Stats
+        #   content.json()['aggregations']
+        # Total num of entries
+        #   content.json()['hits']['total']
+        # Zenodo metadata of each entry
+        #   [item['metadata'] for item in content.json()['hits']['hits']]
+
+        return requests.get(f"{self.zenodo_api_url}/records", params=self.parameters)
+
+    def fetch_community_entries_per_id(self, community_name='escape2020', results_per_query=100):
+        """
+        Query the `entries ids` of all the entries within a community
+
+        :param community_name: str
+            Community name. DEFAULT='escape2020'
+        :param results_per_query: int
+            Number of entries returned per call to the REST API. DEFAULT=100.
+
+        :return: list
+            List containing the `id`s of each community entry
+        """
+        return [entry['id'] for entry in
+                self.fetch_community_entries(community_name, results_per_query).json()['hits']['hits']]
+
+    def fetch_community_entries_per_title(self, community_name='escape2020', results_per_query=100):
+        """
+        Query the title of all the entries within a community
+
+        :param community_name: str
+            Community name. DEFAULT='escape2020'
+        :param results_per_query: int
+            Number of entries returned per call to the REST API. DEFAULT=100.
+
+        :return: list
+            List containing the title of each community entry
+        """
+        return [entry['metadata']['title'] for entry in
+                self.fetch_community_entries(community_name, results_per_query).json()['hits']['hits']]
+
+    def search_codemeta_file(self):
+        """Check if a `codemeta.json` files exists in the ROOT directory of the project"""
+
+        # root_dir = find_root_directory()
+        root_dir = self.proj_root_dir
+        print(f'\nProject root directory {abspath(root_dir)}')  # DEBUG
+
+        codemeta_file = root_dir / 'codemeta.json'
+
+        if codemeta_file.exists():
+            print("\n * Found codemeta.json file within the project !")
+            self.exist_codemeta_file = True
+            self.path_codemeta_file = codemeta_file
+        else:
+            print("\n ! codemeta.json file NOT found in the root directory of the  project !")
+
+    def search_zenodo_json_file(self):
+        """Check if a `.zenodo.json` files exists in the ROOT directory of the project"""
+
+        # root_dir = find_root_directory()
+        root_dir = self.proj_root_dir
+
+        zenodo_metadata_file = root_dir / '.zenodo.json'
+
+        if zenodo_metadata_file.exists():
+            print("\n * Found .zenodo.json file within the project !")
+            self.exist_zenodo_metadata_file = True
+            self.path_zenodo_metadata_file = zenodo_metadata_file
+        else:
+            print("\n ! .zenodo.json file NOT found in the root directory of the  project !")
+
+    def conversion_codemeta2zenodo(self):
+        """Perform the codemeta2zenodo conversion if a codemeta.json file is found"""
+
+        if self.exist_codemeta_file:
+            print("\n * Creating a .zenodo.json file from your codemeta.json file...")
+            self.path_zenodo_metadata_file = self.path_codemeta_file.parent / '.zenodo.json'
+
+            parse_codemeta_and_write_zenodo_metadata_file(self.path_codemeta_file,
+                                                          self.path_zenodo_metadata_file)
+        else:
+            pass
+
+    def check_upload_to_zenodo(self):
+        """
+        `Tests` the different stages of the GitLab-Zenodo connection and that the status_code returned by every
+        stage is the correct one.
+
+        Checks:
+         - The existence of a `.zenodo.json` file in the ROOT dir of the project
+            - If not, it checks if it exists a `codemeta.json` file
+               - If it exists it performs the codemeta2zenodo conversion
+               - If not, it exits the program
+
+         - The communication with Zenodo through its API to verify that:
+            - You can fetch an user entries
+            - You can create a new entry
+            - The provided zenodo metadata can be digested, and not errors appear
+            - Finally erases the test entry - because IT HAS NOT BEEN PUBLISHED !
+        """
+        # Search for the codemeta.json and the .zenodo.json files within the project
+        self.search_codemeta_file()
+        self.search_zenodo_json_file()
+
+        if not self.exist_zenodo_metadata_file:
+
+            if self.exist_codemeta_file:
+                self.conversion_codemeta2zenodo()
+            else:
+                print("\n ! NO codemeta.json NOR .zenodo.json file found. "
+                      "Please add one to the ROOT directory of your project.")
+                sys.exit(-1)
+
+        print("\n * Using the .zenodo.json file to simulate a new upload to Zenodo... \n")
+
+        # 1 - Test connection
+        print("1 --> Testing communication with Zenodo...")
+
+        test_connection = self.fetch_user_entries()
+        if test_connection.status_code == 200:
+            print("  * Test connection status OK !")
+        else:
+            print("  ! ERROR while testing connection status\n", test_connection.json())
+
+        # 2 - Test new entry
+        print("2 --> Testing the creation of a dummy entry to (sandbox)Zenodo...")
+
+        new_entry = self.create_new_entry()
+        if new_entry.status_code == 201:
+            print("  * Test new entry status OK !")
+        else:
+            print("  ! ERROR while testing the creation of new entry\n", new_entry.json())
+
+        # 3 - Test upload metadata
+        print("3 --> Testing the ingestion of the Zenodo metadata...")
+
+        test_entry_id = new_entry.json()['id']
+        with open(self.path_zenodo_metadata_file) as file:
+            metadata_entry = json.load(file)
+        update_metadata = self.update_metadata_entry(test_entry_id,
+                                                     json_metadata=metadata_entry)
+
+        if update_metadata.status_code == 200:
+            print("  * Update metadata status OK !")
+            pprint.pprint(metadata_entry)
+        else:
+            print("  ! ERROR while testing update of metadata\n",
+                  update_metadata.json(), "\n", metadata_entry)
+            print("  ! Erasing dummy test entry...\n")
+            erase_error = self.erase_entry(test_entry_id)
+            if erase_error.status_code != 204:
+                print(f" !! ERROR erasing dummy test entry. Please erase it manually at\n "
+                      f"{self.zenodo_api_url[:-4]}/deposit")
+            else:
+                print("    - Done.\n")
+            sys.exit(-1)
+
+        # 4 - Test delete entry
+        print("4 --> Testing the deletion of the dummy entry...")
+
+        delete_test_entry = self.erase_entry(test_entry_id)
+        if delete_test_entry.status_code == 204:
+            print("  * Delete test entry status OK !")
+        else:
+            print("  ! ERROR while deleting test entry\n", delete_test_entry.json())
+
+        print("\n\tYAY ! Successful testing of the connection to Zenodo ! \n\n"
+              "You should not face any trouble when uploading a project to Zenodo - if you followed the "
+              "`OSSR how to publish tutorial`:\n"
+              "\t https://escape2020.pages.in2p3.fr/wp3/ossr-pages/page/contribute/publish_tutorial/#3-add-the-following-code-snippet \n"
+              "In case you do, please contact us !\n")
diff --git a/eossr/scripts/check_connection_zenodo.py b/eossr/scripts/check_connection_zenodo.py
new file mode 100644
index 0000000000000000000000000000000000000000..81ade0b6cef7e5ad303079ba181c7101714b4e8d
--- /dev/null
+++ b/eossr/scripts/check_connection_zenodo.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+import argparse
+from distutils.util import strtobool
+from eossr.api.zenodo import ZenodoAPI
+
+
+def main():
+    # Required arguments
+    parser = argparse.ArgumentParser(description="Test the connection to zenodo and all the stages of a new upload.")
+
+    parser.add_argument('--token', '-t', type=str,
+                        dest='zenodo_token',
+                        help='Personal access token to (sandbox)Zenodo',
+                        required=True)
+
+    parser.add_argument('--sandbox', '-s', action='store',
+                        type=lambda x: bool(strtobool(x)),
+                        dest='sandbox_flag',
+                        help='Set the Zenodo environment.'
+                             'If True connects with Zenodo. If False with Sandbox Zenodo',
+                        default=False)
+
+    parser.add_argument('--project_dir', '-p', action='store',
+                        dest='project_dir',
+                        help='Path to the root directory of the directory to be uploaded. '
+                             'DEFAULT; assumed to be on it, i.e., "./"',
+                        default='./'
+                        )
+
+    args = parser.parse_args()
+
+    zenodo = ZenodoAPI(access_token=args.zenodo_token,
+                       sandbox=args.sandbox_flag,
+                       proj_root_dir=args.project_dir
+                       )
+
+    zenodo.test_upload_to_zenodo()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/eossr/scripts/eossr_upload_new_deposit.py b/eossr/scripts/eossr_upload_new_deposit.py
new file mode 100644
index 0000000000000000000000000000000000000000..c68f3d9594313de0143df6ba21b55c48339ca40e
--- /dev/null
+++ b/eossr/scripts/eossr_upload_new_deposit.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+
+import os
+import json
+import argparse
+from pathlib import Path
+from distutils.util import strtobool
+from eossr.api.zenodo import ZenodoAPI
+from eossr.metadata.codemeta2zenodo import parse_codemeta_and_write_zenodo_metadata_file
+
+
+def create_zenodo_metadata(metadata_filename, repo_root_dir='./'):
+    """
+    Checks for a zenodo metadata file, otherwise it looks for a codemeta.json file to create a the .zenodo.json file
+
+    :param metadata_filename: str
+        path and name to the zenodo metadata json file
+        NOT TO BE CHANGED. The file must be named `.zenodo.json` and be stored in the root directory of the library.
+
+    :param repo_root_dir: str
+        Path to the project root directory to be uploaded
+    """
+    # root_dir = find_root_directory()
+    root_dir = Path(repo_root_dir)
+    print(f'working dir : {root_dir}')  # DEBUG
+
+    files_json = [file for file in os.listdir(root_dir) if file.endswith('.json')]
+    print(f'JSON files found: \n{files_json}')
+
+    zenodo_metadata_filename = metadata_filename
+    codemeta_file = 'codemeta.json'
+
+    if codemeta_file in files_json and zenodo_metadata_filename not in files_json:
+        print(f"\nCreating {zenodo_metadata_filename} automatically on the CI pipeline.\n")
+        parse_codemeta_and_write_zenodo_metadata_file(codemeta_file, zenodo_metadata_filename)
+
+    elif os.path.isfile(zenodo_metadata_filename):
+        print(f"\n{zenodo_metadata_filename} metadata file found in the root directory of the library ! \n")
+        pass
+
+    else:
+        print(f"\n{codemeta_file} not found, thus any zenodo_metadata file `{zenodo_metadata_filename}` was"
+              f" created during the CI pipeline."
+              f"Please provide one so that the CI can run correctly (examples in the 'codemeta_utils' directory)")
+        exit(-1)
+
+
+def main():
+    parser = argparse.ArgumentParser(description="Upload new deposit entry to Zenodo")
+
+    parser.add_argument('--token', '-t', type=str,
+                        dest='zenodo_token',
+                        help='Personal access token to (sandbox)Zenodo',
+                        required=True)
+
+    parser.add_argument('--sandbox', '-s', action='store',
+                        type=lambda x: bool(strtobool(x)),
+                        dest='sandbox_flag',
+                        help='Set the Zenodo environment.'
+                             'If True connects with Zenodo. If False with Sanbox Zenodo',
+                        default=False)
+
+    parser.add_argument('--input-dir', '-i', type=str,
+                        dest='input_directory',
+                        help='Path to the directory containing the files to upload.'
+                             'ALL files will be uploaded.',
+                        required=True)
+
+    args = parser.parse_args()
+
+    zenodo = ZenodoAPI(
+        access_token=args.zenodo_token,
+        sandbox=args.sandbox_flag  # True for sandbox.zenodo.org !! False for zenodo.org
+    )
+
+    # 1 - create empty deposit
+    new_entry = zenodo.create_new_entry()
+
+    if new_entry.status_code < 399:
+        deposition_id = new_entry.json()['id']
+        doi = new_entry.json()['metadata']['prereserve_doi']['doi']
+        print(f" * Status {new_entry.status_code}. New entry to Zenodo created ! Deposition id {deposition_id}")
+    else:
+        print(f" ! ERROR; the NEW entry COULD NOT be created.")
+        print(new_entry.json())
+
+    # 2 - upload files
+    for file in os.listdir(args.input_directory):
+        full_path_file = args.input_directory + '/' + file
+
+        new_upload = zenodo.upload_file_entry(
+            deposition_id,
+            name_file=file,
+            path_file=full_path_file
+        )
+
+        print(f" * File {file} correctly uploaded !\n", new_upload)
+
+    # 3 - Create the zenodo metadata file from a codemeta.json file
+    zenodo_metadata_filename = '.zenodo.json'
+    create_zenodo_metadata(zenodo_metadata_filename)
+
+    # And upload the repository metadata
+    with open(zenodo_metadata_filename) as json_file:
+        entry_metadata = json.load(json_file)
+
+    # entry_info['metadata']['doi'] = doi  # In the new version of the API the doi is updated automatically.
+    update_entry = zenodo.update_metadata_entry(
+        deposition_id,
+        json_metadata=entry_metadata
+    )
+
+    if update_entry.status_code < 399:
+        print(f" * Status {update_entry.status_code}. Repository information correctly uploaded !")
+    else:
+        print(f" ! Repository information NOT correctly uploaded ! Status {update_entry.status_code}\n",
+              update_entry.json())
+
+    # 4 - publish entry
+    publish = zenodo.publish_entry(deposition_id)
+
+    if publish.status_code == 204:
+        print(" * New deposit correctly published !\n")
+        print(f" * The new doi should look like 10.5281/{deposition_id}. However please")
+        print(f" ** Check the upload at {zenodo.zenodo_api_url[:-4]}/deposit/{deposition_id}  **")
+    else:
+        print(f" ! New deposit NOT correctly published ! Status {publish.status_code}\n",
+              publish.json())
+
+
+if __name__ == '__main__':
+    main()
diff --git a/eossr/scripts/eossr_upload_new_version_deposit.py b/eossr/scripts/eossr_upload_new_version_deposit.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb9d170cdbaed703e5aaa2807a06d48324fe4738
--- /dev/null
+++ b/eossr/scripts/eossr_upload_new_version_deposit.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+
+
+import os
+import json
+import argparse
+from pathlib import Path
+from distutils.util import strtobool
+from eossr.api.zenodo import ZenodoAPI
+from eossr.metadata.codemeta2zenodo import parse_codemeta_and_write_zenodo_metadata_file
+
+
+def create_zenodo_metadata(metadata_filename, repo_root_dir='./'):
+    """
+    Checks for a zenodo metadata file, otherwise it looks for a codemeta.json file to create a the .zenodo.json file
+
+    param metadata_filename: str
+        path and name to the zenodo metada json file
+        NOT TO BE CHANGED. The file must be named `.zenodo.json` and be stored in the root directory of the library.
+    """
+    # root_dir = find_root_directory()
+    root_dir = Path(repo_root_dir)
+
+    files_json = [file for file in os.listdir(root_dir) if file.endswith('.json')]
+    print(f'JSON files : {files_json}')
+
+    zenodo_metadata_filename = metadata_filename
+    codemeta_file = 'codemeta.json'
+
+    if codemeta_file in files_json and zenodo_metadata_filename not in files_json:
+        print(f"\nCreating {zenodo_metadata_filename} automatically at the CI pipeline.\n")
+        parse_codemeta_and_write_zenodo_metadata_file(codemeta_file, zenodo_metadata_filename)
+
+    elif os.path.isfile(zenodo_metadata_filename):
+        print(f"\n{zenodo_metadata_filename} metadata file found in the root directory of the library ! \n")
+        pass
+
+    else:
+        print(f"\n{codemeta_file} not found, thus any zenodo_metadata file `{zenodo_metadata_filename}` was"
+              f" created during the CI pipeline."
+              f"Please provide one so that the CI can run correctly (examples in the 'codemeta_utils' directory)")
+        exit(-1)
+
+
+def main():
+    parser = argparse.ArgumentParser(description="Upload a new version of an existing deposit to Zenodo")
+
+    parser.add_argument('--token', '-t', type=str,
+                        dest='zenodo_token',
+                        help='Personal access token to (sandbox)Zenodo',
+                        required=True)
+
+    parser.add_argument('--sandbox', '-s', action='store',
+                        type=lambda x: bool(strtobool(x)),
+                        dest='sandbox_flag',
+                        help='Set the Zenodo environment.'
+                             'If True connects with Zenodo. If False with Sandbox Zenodo',
+                        default=False)
+
+    parser.add_argument('--input-dir', '-i', type=str,
+                        dest='input_directory',
+                        help='Path to the directory containing the files to upload.'
+                             'ALL files will be uploaded.',
+                        required=True)
+
+    parser.add_argument('--deposit_id', '-id', type=str,
+                        dest='deposit_id',
+                        help='deposit_id of the deposit that is going to be updated by a new version',
+                        required=True)
+
+    args = parser.parse_args()
+
+    zenodo = ZenodoAPI(
+        access_token=args.zenodo_token,
+        sandbox=args.sandbox_flag  # True for sandbox.zenodo.org !! False for zenodo.org
+    )
+
+    # 1 - request a new version of an existing deposit
+    new_version = zenodo.new_version_entry(args.deposit_id)
+
+    if new_version.status_code < 399:
+        print(f" * Status {new_version.status_code}. New version of the {args.deposit_id} entry correctly created !")
+    else:
+        print(f" ! ERROR; new version of the {args.deposit_id} entry COULD NOT be created.")
+        print(new_version.json())
+
+    new_deposition_id = new_version.json()['links']['latest_draft'].rsplit('/')[-1]
+
+    # PRE-2 - If you DO NOT want to erase the old files, comment the following lines
+    old_files_ids = [file['id'] for file in new_version.json()['files']]
+    for file_id in old_files_ids:
+        zenodo.erase_file_entry(
+            new_deposition_id,
+            file_id
+        )
+
+    # 2 - Upload new version of file(s)
+    for file in os.listdir(args.input_directory):
+        full_path_file = args.input_directory + '/' + file
+
+        new_upload = zenodo.upload_file_entry(
+            new_deposition_id,
+            name_file=file,
+            path_file=full_path_file
+        )
+
+        print(f" * File {file} correctly uploaded !\n", new_upload)
+
+    # 3 - Look for a zenodo metadata file, otherwise try to create one
+    zenodo_metadata_filename = '.zenodo.json'
+    create_zenodo_metadata(zenodo_metadata_filename)
+
+    with open(zenodo_metadata_filename) as json_file:
+        update_entry_metadata = json.load(json_file)
+
+    # update_entry_info['metadata']['doi'] = doi  # In the new version of the API the doi is updated automatically.
+    update_entry = zenodo.update_metadata_entry(
+        new_deposition_id,
+        json_metadata=update_entry_metadata
+    )
+
+    if update_entry.status_code < 399:
+        print(f" * Status {update_entry.status_code}. Repository information correctly uploaded !\n")
+    else:
+        print(f" ! Repository information NOT correctly uploaded ! Status {update_entry.status_code}\n",
+              update_entry.json())
+
+    # 4 - publish entry - to publish the entry, uncomment the two lone below
+    publish = zenodo.publish_entry(new_deposition_id)
+
+    if publish.status_code == 204:
+        print(" * New version of the old deposition correctly published !\n")
+        print(f" * Old deposition id {args.deposit_id}, new deposition id {new_deposition_id}")
+        print(f" * The new doi should look like 10.5281/{new_deposition_id}. However please")
+        print(f" ** Check the upload at {zenodo.zenodo_api_url[:-4]}/deposit/{new_deposition_id}  **")
+    else:
+        print(f" ! New deposit NOT correctly published ! Status {publish.status_code}\n",
+              publish.json())
+
+
+if __name__ == '__main__':
+    main()
diff --git a/eossr/scripts/parse_last_release_git.sh b/eossr/scripts/parse_last_release_git.sh
new file mode 100755
index 0000000000000000000000000000000000000000..cf70750df0a454e0a90ac3b56582d3e3b906105c
--- /dev/null
+++ b/eossr/scripts/parse_last_release_git.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+REPOSITORY_NAME="$1"
+REPOSITORY_BASE_URL="$2"
+
+LAST_RELEASE=`git ls-remote --tags --refs --sort="v:refname" $REPOSITORY_BASE_URL.git | tail -n1 | sed 's/.*\///'`
+
+if [ -z "$LAST_RELEASE" ]; then
+    echo "No tag / new release found ! - Or error when parsing. Downloading last commit to the repository (master branch) ;"
+    wget -O $REPOSITORY_NAME-master.zip "$REPOSITORY_BASE_URL"/-/archive/master/"$REPOSITORY_NAME"-master.zip
+    mv $REPOSITORY_NAME-master.zip ./build
+else
+    echo "$LAST_RELEASE tag / release found !"
+    wget -O $REPOSITORY_NAME-$LAST_RELEASE.zip "$REPOSITORY_BASE_URL"/-/archive/"$LAST_RELEASE"/"$REPOSITORY_NAME"-"$LAST_RELEASE".zip
+    mv $REPOSITORY_NAME-$LAST_RELEASE.zip ./build
+fi
diff --git a/eossr/scripts/tests/test_eossr_codemeta2zenodo.py b/eossr/scripts/tests/test_eossr_codemeta2zenodo.py
deleted file mode 100644
index 316b254cbbc7b28e7c75244c75f9c3b231146208..0000000000000000000000000000000000000000
--- a/eossr/scripts/tests/test_eossr_codemeta2zenodo.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import subprocess
-from os.path import dirname, realpath, join
-
-ROOT_DIR = dirname(realpath("codemeta.json"))
-
-
-def run_script(*args):
-    result = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf-8')
-
-    if result.returncode != 0:
-        raise ValueError(
-            f"Running {args[0]} failed with return code {result.returncode}"
-            f", output: \n {result.stdout}"
-        )
-
-
-def test_codemeta2zenodo():
-    run_script("eossr-codemeta2zenodo", "-i", join(ROOT_DIR, "codemeta.json"))
diff --git a/eossr/scripts/tests/test_scripts.py b/eossr/scripts/tests/test_scripts.py
new file mode 100644
index 0000000000000000000000000000000000000000..ead140b080a9fab2035590d0dc3b019f0dce3778
--- /dev/null
+++ b/eossr/scripts/tests/test_scripts.py
@@ -0,0 +1,46 @@
+# Various tests taken/based from
+# https://github.com/cta-observatory/cta-lstchain/blob/master/lstchain/scripts/tests/test_lstchain_scripts.py
+
+import pytest
+import subprocess
+import pkg_resources
+from os.path import dirname, realpath, join
+
+ROOT_DIR = dirname(realpath("codemeta.json"))
+
+
+def find_entry_points(package_name):
+    """from: https://stackoverflow.com/a/47383763/3838691"""
+    entrypoints = [
+        ep.name
+        for ep in pkg_resources.iter_entry_points("console_scripts")
+        if ep.module_name.startswith(package_name)
+    ]
+    return entrypoints
+
+
+ALL_SCRIPTS = find_entry_points("eossr")
+
+
+def run_script(*args):
+    result = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf-8')
+
+    if result.returncode != 0:
+        raise ValueError(
+            f"Running {args[0]} failed with return code {result.returncode}"
+            f", output: \n {result.stdout}"
+        )
+
+
+def test_codemeta2zenodo():
+    run_script("eossr-codemeta2zenodo", "-i", join(ROOT_DIR, "codemeta.json"))
+
+
+def test_parse_last_release_git_bash():
+    run_script("which", "parse_last_release_git.sh")
+
+
+@pytest.mark.parametrize("script", ALL_SCRIPTS)
+def test_help_all_scripts(script):
+    """Test for all scripts if at least the help works"""
+    run_script(script, "--help")
diff --git a/setup.py b/setup.py
index 5a3b1bcce2e80aa72dd9d3bac15d70587c993ed5..bc827db0311d309925b1731af7a3513c9abdd9b4 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,10 @@ import re
 from setuptools import setup, find_packages
 
 entry_points = {'console_scripts': [
-    'eossr-codemeta2zenodo = eossr.scripts.eossr_codemeta2zenodo:main'
+    'eossr-codemeta2zenodo = eossr.scripts.eossr_codemeta2zenodo:main',
+    'eossr-upload-new-deposit = eossr.scripts.eossr_upload_new_deposit:main',
+    'eossr-upload-new-version-deposit = eossr.scripts.eossr_upload_new_version_deposit:main',
+    'eossr-check-connection-zenodo = eossr.scripts.check_connection_zenodo:main'
     ]
 }
 
@@ -19,10 +22,12 @@ setup(
     name='eossr',
     version=get_property('__version__', 'eossr'),
     description="ESCAPE OSSR library",
-    # install_requires=[],
+    install_requires=[
+        "requests"
+    ],
     packages=find_packages(),
-    # scripts=[],
-    # tests_require=['pytest'],
+    scripts=['eossr/scripts/parse_last_release_git.sh'],
+    tests_require=['pytest'],
     author='Thomas Vuillaume & Enrique Garcia',
     author_email='vuillaume<at>lapp.in2p3.fr',
     url='https://gitlab.in2p3.fr/escape2020/wp3/eossr',