diff --git a/.github/ISSUE_TEMPLATE/notebook.yml b/.github/ISSUE_TEMPLATE/notebook.yml index f3ef9ee6..c12b4b63 100644 --- a/.github/ISSUE_TEMPLATE/notebook.yml +++ b/.github/ISSUE_TEMPLATE/notebook.yml @@ -66,7 +66,7 @@ body: attributes: label: Task ID description: Provide the task ID. - placeholder: e.g., 1123e4567-e89b-12d3-a456-426655440000 + placeholder: e.g., 1123e4567-e89b-12d3-a456-42665544000 validations: required: true diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml new file mode 100644 index 00000000..dba4dd6a --- /dev/null +++ b/.github/workflows/on-push.yml @@ -0,0 +1,30 @@ +name: on-push + +on: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -l {0} + +jobs: + validate-notebook-names: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - name: Validate notebook names + run: | + python scripts/validate_notebook_names.py . diff --git a/scripts/validate_notebook_names.py b/scripts/validate_notebook_names.py new file mode 100644 index 00000000..cbc4fe09 --- /dev/null +++ b/scripts/validate_notebook_names.py @@ -0,0 +1,71 @@ +import argparse +import pathlib +import urllib.request +import uuid + +DATA_TYPES = ( + "climate", + "insitu", + "reanalysis", + "satellite", + "seasonal", +) + +ASSESSMENT_CATEGORIES = ( + "climate-and-weather-extremes", + "climate-impact-indicators", + "climate-monitoring", + "consistency-assessment", + "data-completeness", + "forecast-skill", + "intercomparison", + "mean", + "model-performance", + "trend-assessment", + "uncertainty", + "variability", +) + +API_URL = "https://cds.climate.copernicus.eu/api/v2" + + +def main(directory: str): + for path in pathlib.Path(directory).glob("**/*.ipynb"): + assert path.stem.islower(), f"{path=!s}: Invalid {path.name=}" + + segments = path.stem.split("_") + assert len(segments) == 5, f"{path=!s}: Invalid {path.name=}" + ( + data_type, + dataset_id, + assessment_category, + question_number, + task_id, + ) = segments + + assert data_type in DATA_TYPES, f"{path=!s}: Invalid {data_type=}" + + url = f"{API_URL}/resources/dataset/{dataset_id}" + assert ( + urllib.request.urlopen(url).getcode() == 200 + ), f"{path=!s}: Invalid {dataset_id=}" + + assert ( + assessment_category in ASSESSMENT_CATEGORIES + ), f"{path=!s}: Invalid {assessment_category=}." + + assert len(question_number) == 3, f"{path=!s}: Invalid {question_number=}" + assert question_number[0] == "q", f"{path=!s}: Invalid {question_number=}" + assert question_number[1:].isdigit(), f"{path=!s}: Invalid {question_number=}" + + try: + uuid.UUID(task_id) + except ValueError: + raise ValueError(f"{path=!s}: Invalid {task_id=}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("directory", type=str) + args = parser.parse_args() + main(args.directory)