Artifacts: dsci@007aefe.1789628812. File: answer.md


artifacts

Below is a complete **DSCI** pipeline that builds, tests and (optionally) deploys a generic C++ project that uses a **Makefile**. All heavy‑lifting is done in normal Bash scripts – the only DSCI‑specific parts are the tiny `jobs.yaml` file and the helper calls (`run_task`, `config`, `update_state`, …). --- ## 1️⃣ Repository layout ``` . ├── .dsci/ │ ├── jobs.yaml # pipeline definition (list of jobs) │ ├── build_job/ # ── Job 1 – compile the project │ │ ├── job.bash │ │ ├── config.yaml # default job parameters │ │ └── tasks/ │ │ └── build/ │ │ └── task.bash │ ├── test_job/ # ── Job 2 – run unit‑tests │ │ ├── job.bash │ │ └── tasks/ │ │ └── test/ │ │ └── task.bash │ └── deploy_job/ # ── Job 3 – optional deployment │ ├── job.bash │ └── tasks/ │ └── deploy/ │ └── task.bash ├── Makefile # (your regular C++ makefile – not shown) └── src/ … # C++ source tree ``` All files that contain DSCI logic are shown below inside **markdown code blocks** labelled with their filenames. --- ## 2️⃣ `jobs.yaml` – only the job list ```yaml # .dsci/jobs.yaml # ---------------------------------------------------------------------- # The pipeline consists of three sequential jobs: # 1️⃣ build_job – compiles the code with `make` # 2️⃣ test_job – runs the test suite # 3️⃣ deploy_job – copies the binary somewhere if tests passed # ---------------------------------------------------------------------- jobs: - id: build_job path: build_job/ # optional override of the default build type (Debug|Release) # params: # BUILD_TYPE: Debug - id: test_job path: test_job/ - id: deploy_job path: deploy_job/ # you could add a `skip: $(config SKIP_DEPLOY) == "true"` flag here ``` *Only the list of jobs (and optional per‑job `params`) is declared – all real logic lives in the script files.* --- ## 3️⃣ Job 1 – **build_job** ### 3.1 Default parameters (`config.yaml`) ```yaml # .dsci/build_job/config.yaml # ---------------------------------------------------------------------- # Default values for this job. They can be overridden in `jobs.yaml` # ---------------------------------------------------------------------- BUILD_TYPE: Release # can be “Debug” or “Release” BUILD_TARGET: all # the target you want `make` to run ``` ### 3.2 Job entry point (`job.bash`) ```bash # .dsci/build_job/job.bash #!/usr/bin/env bash # ---------------------------------------------------------------------- # Job “build_job” – simply runs the single “build” task. # ---------------------------------------------------------------------- set -euo pipefail # Run the only task of this job run_task "build" ``` ### 3.3 Build task (`task.bash`) ```bash # .dsci/build_job/tasks/build/task.bash #!/usr/bin/env bash # ---------------------------------------------------------------------- # Task “build” – compiles the C++ sources with `make`. # It reads the job parameters via the `config` helper and stores the # produced binary in the shared `~/artifacts` directory. # ---------------------------------------------------------------------- set -euo pipefail # ---------------------------------------------------------------------- # 1️⃣ Read job parameters (they come from config.yaml or from the pipeline) # ---------------------------------------------------------------------- BUILD_TYPE=$(config BUILD_TYPE) # e.g. Release or Debug BUILD_TARGET=$(config BUILD_TARGET) # default is “all” echo "=== Build job: BUILD_TYPE=${BUILD_TYPE}, BUILD_TARGET=${BUILD_TARGET} ===" # ---------------------------------------------------------------------- # 2️⃣ Run make. Pass the build type as a variable – adapt to your Makefile. # ---------------------------------------------------------------------- make ${BUILD_TARGET} BUILD_TYPE=${BUILD_TYPE} # ---------------------------------------------------------------------- # 3️⃣ Export the binary as an artifact for downstream jobs. # (Assume the binary is ./bin/app) # ---------------------------------------------------------------------- ARTIFACT_DIR="${HOME}/artifacts" mkdir -p "${ARTIFACT_DIR}" cp ./bin/app "${ARTIFACT_DIR}/app_${BUILD_TYPE}" echo "✅ Built binary copied to ${ARTIFACT_DIR}/app_${BUILD_TYPE}" ``` --- ## 4️⃣ Job 2 – **test_job** ### 4.1 Job entry point (`job.bash`) ```bash # .dsci/test_job/job.bash #!/usr/bin/env bash # ---------------------------------------------------------------------- # Job “test_job” – executes the unit‑test suite. # ---------------------------------------------------------------------- set -euo pipefail run_task "test" ``` ### 4.2 Test task (`task.bash`) ```bash # .dsci/test_job/tasks/test/task.bash #!/usr/bin/env bash # ---------------------------------------------------------------------- # Task “test” – runs `make test` (or any command you prefer) and # records the result in the job state so that later jobs can read it. # ---------------------------------------------------------------------- set -euo pipefail echo "=== Running test suite ===" # Run the tests – adapt the target name to your Makefile. # The command must return a non‑zero exit code on failure, # otherwise the whole job would abort (set -e). if make test; then TEST_STATUS="passed" echo "✅ Tests passed" else TEST_STATUS="failed" echo "❌ Tests failed" fi # ---------------------------------------------------------------------- # 5️⃣ Export the test status as state (shared with later jobs) # ---------------------------------------------------------------------- # IMPORTANT: update_state must receive ONE JSON object. update_state "{ \"test_status\": \"${TEST_STATUS}\" }" ``` *The downstream **deploy_job** can read `test_status` from the pipeline state.* --- ## 5️⃣ Job 3 – **deploy_job** > **Optional** – you can skip this job (or add a `skip:` clause in `jobs.yaml`) if you only want to build & test. ### 5️⃣1 Job entry point (`job.bash`) ```bash # .dsci/deploy_job/job.bash #!/usr/bin/env bash # ---------------------------------------------------------------------- # Job “deploy_job” – copies the built binary to a deployment folder # only when the previous test job succeeded. # ---------------------------------------------------------------------- set -euo pipefail run_task "deploy" ``` ### 5️⃣2 Deploy task (`task.bash`) ```bash # .dsci/deploy_job/tasks/deploy/task.bash #!/usr/bin/env bash # ---------------------------------------------------------------------- # Task “deploy” – reads the test result from the pipeline state, # selects the appropriate artifact, and copies it to a target location. # ---------------------------------------------------------------------- set -euo pipefail # ---------------------------------------------------------------------- # 1️⃣ Read the whole pipeline state (JSON) and pull the test status. # The state is automatically placed under the reserved key "_dsci_". # ---------------------------------------------------------------------- PIPELINE_STATE=$(config) # returns the full JSON TEST_STATUS=$(echo "$PIPELINE_STATE" | jq -r '._dsci_.test_job.test_status') echo "=== Deploy job – test status reported as: ${TEST_STATUS} ===" if [[ "${TEST_STATUS}" != "passed" ]]; then echo "⚠️ Tests did not pass – aborting deployment." exit 0 # not an error, just skip the deployment step fi # ---------------------------------------------------------------------- # 2️⃣ Locate the built artifact. We stored it as: # ~/artifacts/app_ # The build type is the same parameter used in the build job. # ---------------------------------------------------------------------- BUILD_TYPE=$(config BUILD_TYPE) # will fall back to default if not overridden ARTIFACT="${HOME}/artifacts/app_${BUILD_TYPE}" if [[ ! -f "${ARTIFACT}" ]]; then echo "❌ Expected artifact ${ARTIFACT} not found" exit 1 fi # ---------------------------------------------------------------------- # 3️⃣ Deploy – here we simply copy it to /opt/deploy (adjust to your env) # ---------------------------------------------------------------------- DEPLOY_DIR="/opt/deploy" mkdir -p "${DEPLOY_DIR}" cp "${ARTIFACT}" "${DEPLOY_DIR}/app" echo "🚀 Deployed ${ARTIFACT} → ${DEPLOY_DIR}/app" ``` *If you need a more sophisticated deployment (e.g. Docker push, SSH upload, etc.) replace the copy command with the appropriate logic – the same DSCI helpers (`config`, `update_state`, …) remain available.* --- ## 6️⃣ How the pieces talk together | Component | How it accesses data | |-----------|---------------------| | **build task** | `$(config BUILD_TYPE)` – reads job defaults or pipeline overrides. | | **test task** | `update_state "{ \"test_status\": \"${TEST_STATUS}\" }"` – publishes a JSON object that DSCI stores under `._dsci_.test_job`. | | **deploy task** | `config` → `jq` extracts `._dsci_.test_job.test_status`; also reads `$(config BUILD_TYPE)` to locate the right artifact. | | **Artifacts** | Anything written under `~/artifacts/` in one job is automatically visible to the next jobs. | --- ## 7️⃣ Quick checklist for a real project 1. **Makefile** must expose at least two targets used above: *`make BUILD_TYPE=…`* (default target `all`) and *`make test`*. 2. **Permissions** – ensure every `*.bash` file is executable (`chmod +x`). 3. **Optional overrides** – to build a Debug version only for a specific CI run, add to `jobs.yaml`: ```yaml - id: build_job path: build_job/ params: BUILD_TYPE: Debug ``` 4. **Environment** – DSCI runs each job in a fresh container (default `alpine:latest`). If you need extra packages (e.g. `g++`, `make`), add a small wrapper script or a Dockerfile and set `image: your‑image` in the job definition (the documentation shows how – omitted here for brevity). --- ## 8️⃣ All files together (for copy‑paste) ```yaml # .dsci/jobs.yaml jobs: - id: build_job path: build_job/ - id: test_job path: test_job/ - id: deploy_job path: deploy_job/ ``` ```yaml # .dsci/build_job/config.yaml BUILD_TYPE: Release BUILD_TARGET: all ``` ```bash # .dsci/build_job/job.bash #!/usr/bin/env bash set -euo pipefail run_task "build" ``` ```bash # .dsci/build_job/tasks/build/task.bash #!/usr/bin/env bash set -euo pipefail BUILD_TYPE=$(config BUILD_TYPE) BUILD_TARGET=$(config BUILD_TARGET) echo "=== Build job: BUILD_TYPE=${BUILD_TYPE}, BUILD_TARGET=${BUILD_TARGET} ===" make ${BUILD_TARGET} BUILD_TYPE=${BUILD_TYPE} ARTIFACT_DIR="${HOME}/artifacts" mkdir -p "${ARTIFACT_DIR}" cp ./bin/app "${ARTIFACT_DIR}/app_${BUILD_TYPE}" echo "✅ Built binary copied to ${ARTIFACT_DIR}/app_${BUILD_TYPE}" ``` ```bash # .dsci/test_job/job.bash #!/usr/bin/env bash set -euo pipefail run_task "test" ``` ```bash # .dsci/test_job/tasks/test/task.bash #!/usr/bin/env bash set -euo pipefail echo "=== Running test