diff --git a/.copier-answers.yml b/.copier-answers.yml index 86a19eb..45e22fb 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -2,7 +2,7 @@ # It is needed to track the repo template version, and editing may break things. # This file will be overwritten by copier on template updates. -_commit: v1.4.1 +_commit: v1.5.1 _src_path: https://github.com/bec-project/plugin_copier_template.git make_commit: false project_name: detector_group_bec diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index e3b4d01..55f11b0 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -95,8 +95,19 @@ jobs: uv pip install --system -e ./bec/bec_ipython_client uv pip install --system -e ./bec/bec_server[dev] uv pip install --system -e ./bec_widgets[dev,pyside6] - uv pip install --system -e ./detector_group_bec + uv pip install --system -e ./detector_group_bec[dev] - - name: Run Pytest with Coverage + - name: Run Tests with Coverage id: coverage - run: pytest --random-order --cov=./detector_group_bec --cov-config=./detector_group_bec/pyproject.toml --cov-branch --cov-report=xml --no-cov-on-fail ./detector_group_bec/tests/ || test $? -eq 5 + shell: bash + run: | + set +e + coverage run --branch --source=./detector_group_bec -m pytest --random-order ./detector_group_bec/tests/ + status=$? + # Allow pytest exit code 5 so repositories without tests do not fail CI. + if [ "$status" -ne 0 ] && [ "$status" -ne 5 ]; then + exit "$status" + fi + if [ "$status" -eq 0 ]; then + coverage report + fi diff --git a/.gitea/workflows/create_update_pr.yml b/.gitea/workflows/create_update_pr.yml new file mode 100644 index 0000000..fb90bbb --- /dev/null +++ b/.gitea/workflows/create_update_pr.yml @@ -0,0 +1,70 @@ +name: Create template upgrade PR for detector_group_bec +on: + workflow_dispatch: + +permissions: + pull-requests: write + +jobs: + create_update_branch_and_pr: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Checkout + uses: actions/checkout@v4 + + - name: Create virtualenv + run: | + python -m virtualenv .venv + + - name: Install tools + run: | + source .venv/bin/activate + pip install copier PySide6 bec_lib + + - name: Perform update + run: | + source .venv/bin/activate + git config --global user.email "bec_ci_staging@psi.ch" + git config --global user.name "BEC automated CI" + + branch="chore/update-template-$(python -m uuid)" + echo "switching to branch $branch" + git checkout -b $branch + + echo "Running copier update..." + copier update --trust --defaults --conflict inline 2>&1 | tee copier.log + status=${PIPESTATUS[0]} + output="$(cat copier.log)" + echo $output + msg="$(printf '%s\n' "$output" | head -n 1)" + + if ! grep -q "make_commit: true" .copier-answers.yml ; then + echo "Autocommit not made, committing..." + git add -A + git commit -a -m "$msg" + fi + + if diff-index --quiet HEAD ; then + echo "No changes detected" + exit 0 + fi + + git push -u origin $branch + curl -X POST "https://gitea.psi.ch/api/v1/repos/${{ gitea.repository }}/pulls" \ + -H "Authorization: token ${{ secrets.CI_REPO_WRITE }}" \ + -H "Content-Type: application/json" \ + -d "{ + \"title\": \"Template: $(echo $msg)\", + \"body\": \"This PR was created by Gitea Actions\", + \"head\": \"$(echo $branch)\", + \"base\": \"main\" + }" diff --git a/detector_group_bec/file_writer/storage_copy.py b/detector_group_bec/file_writer/storage_copy.py new file mode 100644 index 0000000..d713094 --- /dev/null +++ b/detector_group_bec/file_writer/storage_copy.py @@ -0,0 +1,76 @@ +""" +Beamline storage-copy hook for detector_group_bec. + +Use this module to handle ``bec.beamline_storage_copy(...)`` requests with +beamline-specific file transfer logic. + +The plugin_storage_copy function is commented out by default. Uncomment and implement it to handle +beamline-specific storage copy operations. The function should accept the source file path, +a scope identifier, the active BEC account, and an optional subdirectory for the destination. It should +perform the necessary checks and copy the file to the appropriate location based on the provided scope. +The subdirectory, if provided, has already been sanitized to ensure it is safe for use in file paths. +""" + +# import os +# import shutil + +# from bec_lib.logger import bec_logger + +# logger = bec_logger.logger + + +# def plugin_storage_copy( +# source_file: str, scope: str, active_account: str, subdir: str | None = None +# ) -> None: +# """ +# Run a beamline-defined storage copy operation. + +# Args: +# source_file: Source file that should be copied. +# scope: Beamline-defined copy scope identifier. +# active_account: Active BEC account, if one is available. +# subdir: Optional sanitized relative destination subdirectory. +# """ +# supported_file_extensions = [ +# ".h5", +# ".txt", +# ".csv", +# ".log", +# ".json", +# ".png", +# ".jpg", +# ".jpeg", +# ".tiff", +# ".yaml", +# ".yml", +# ] +# if not any(source_file.endswith(ext) for ext in supported_file_extensions): +# logger.error( +# f"Unsupported file type for '{source_file}'. Supported extensions: " +# f"{supported_file_extensions}" +# ) +# return + +# # Example storage mapping. Replace this with beamline-specific scopes and paths. +# storage_locations = {"alignment": f"/sls/x99sa/data/p12345/raw/bec/alignment/{active_account}/"} +# if scope not in storage_locations: +# logger.error( +# f"Received unknown scope '{scope}'. Available scopes: {list(storage_locations.keys())}" +# ) +# return + +# if not os.path.isfile(source_file): +# logger.error(f"File '{source_file}' does not exist or is not reachable.") +# return + +# destination_dir = storage_locations[scope] +# if subdir: +# destination_dir = os.path.join(destination_dir, subdir) +# os.makedirs(destination_dir, exist_ok=True) +# destination_file = os.path.join(destination_dir, os.path.basename(source_file)) + +# try: +# shutil.copy(source_file, destination_file) +# logger.info(f"Copied '{source_file}' to '{destination_file}'") +# except Exception as exc: +# logger.error(f"Failed to copy '{source_file}' to '{destination_file}': {exc}") diff --git a/pyproject.toml b/pyproject.toml index b10b6d3..ad68109 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,9 @@ plugin_ds_startup = "detector_group_bec.deployments.device_server.startup:run" [project.entry-points."bec.file_writer"] plugin_file_writer = "detector_group_bec.file_writer" +[project.entry-points."bec.file_writer.storage_copy"] +plugin_storage_copy = "detector_group_bec.file_writer.storage_copy:plugin_storage_copy" + [project.entry-points."bec.scans"] plugin_scans = "detector_group_bec.scans"