DSCI Report: dsci@007aefe.1789736466


13:01:08 :: [repository] - index updated from http://sparrowhub.io/repo/api/v1/index
run stage: main
[task run: task.bash - create directory scm]
[task stdout]
13:01:09 :: directory path: scm
13:01:09 :: directory owner: <ubuntu>
13:01:09 :: directory group: <ubuntu>
13:01:09 :: directory access rights: drwxr-xr-x
scm: http://localhost:8080/pipeline-generator.git
sha: 007aefe
message: keep question by dsci@sparrowhub.io - manual run
container runtime: podman
raku version
Raku++ (rakupp) 3.25.0 — a Raku interpreter and compiler in C++
Implements Raku 6.d, and 6.e under `use v6.e.PREVIEW`.
Build  v3.25.0 (2026-09-03), x86_64-linux, clang 18.1.3
Home   https://raku.online — docs, a tour of the language, and a browser playground
sparrow version
0.0.94
runner version: 0.1.1
=======
[task run: task.bash - bash: git config --global advice.detachedHead false]
[task stdout]
[task run: task.bash - bash: git clone http://localhost:8080/pipeline-generator ...]
[task stdout]
13:01:09 :: /home/ubuntu/.dsci/.sparky/.cache/007aefe.1789736466/.sparrowdo/scm
[task stderr]
13:01:10 :: Cloning into '.'...
[task run: task.bash - bash: git checkout 007aefe]
[task stdout]
13:01:10 :: /home/ubuntu/.dsci/.sparky/.cache/007aefe.1789736466/.sparrowdo/scm
[task stderr]
13:01:10 :: HEAD is now at 007aefe keep question
pipeline mode: localhost
run dsci agent container from image: melezhik/dsci-agent-rakupp
ai_agent_message set: 4275696c64204453434920706970656c696e6520666f72205048502070726f6a656374207769746820756e697420746573747320616e6420696e7374616c6c696e6720504850206f662073706563696669632076657273696f6e20666f722044656269616e20
>>> POST http://127.0.0.1:8181/stash
>>> POST http://127.0.0.1:8181/queue
>>> wait for jobs, timeout: 600 sec
>>> GET http://127.0.0.1:8181/stash/job.run/jsmyxcoepqngtbhiwvua.4109216
job test ... [OK]
...
>>> GET job report, status=200
13:01:18 :: [repository] - index updated from http://sparrowhub.io/repo/api/v1/index
run stage: job-run
raku version
Raku++ (rakupp) 3.25.0 — a Raku interpreter and compiler in C++
Implements Raku 6.d, and 6.e under `use v6.e.PREVIEW`.
Build  v3.25.0 (2026-09-03), x86_64-linux, clang 18.1.3
Home   https://raku.online — docs, a tour of the language, and a browser playground
sparrow version
0.0.94
runner version: 0.1.1
run job: test
===
>>> GET http://127.0.0.1:8181/stash/job.run/jsmyxcoepqngtbhiwvua.4109216
[task run: task.bash - create directory scm]
[task stdout]
13:01:19 :: directory path: scm
13:01:19 :: directory owner: <ubuntu>
13:01:19 :: directory group: <ubuntu>
13:01:19 :: directory access rights: drwxr-xr-x
[task run: task.bash - bash: git clone http://localhost:8080/pipeline-generator ...]
[task stdout]
13:01:19 :: /home/ubuntu/.dsci/.sparky/.cache/jsmyxcoepqngtbhiwvua.4109216/.sparrowdo/scm
[task stderr]
13:01:19 :: Cloning into '.'...
[task run: task.bash - bash: git checkout 007aefe]
[task stdout]
13:01:20 :: /home/ubuntu/.dsci/.sparky/.cache/jsmyxcoepqngtbhiwvua.4109216/.sparrowdo/scm
[task stderr]
13:01:20 :: HEAD is now at 007aefe keep question
[task run: task.bash - bash: prepare dsci scripts]
[task stdout]
>>> GET http://127.0.0.1:8181/stash/job.run/jsmyxcoepqngtbhiwvua.4109216
[task run: task.bash - .]
[task stdout]
13:01:20 :: total 8
13:01:20 :: -rw-r--r-- 1 ubuntu ubuntu 109 Sep 18 13:01 jobs.yaml
13:01:20 :: -rw-r--r-- 1 ubuntu ubuntu 301 Sep 18 13:01 task.bash
13:01:20 :: 4275696c64204453434920706970656c696e6520666f72205048502070726f6a656374207769746820756e697420746573747320616e6420696e7374616c6c696e6720504850206f662073706563696669632076657273696f6e20666f722044656269616e20
13:01:25 :: ===
13:01:25 :: Build DSCI pipeline for PHP project with unit tests and installing PHP of specific version for Debian 
13:01:25 :: ===
13:01:25 :: **File structure**
13:01:25 :: 
13:01:25 :: ```
13:01:25 :: .
13:01:25 :: ├── jobs.yaml
13:01:25 :: ├── job_build/
13:01:25 :: │   ├── config.yaml
13:01:25 :: │   ├── job.bash
13:01:25 :: │   └── tasks
13:01:25 :: │       ├── install_php
13:01:25 :: │       │   └── task.bash
13:01:25 :: │       ├── composer_install
13:01:25 :: │       │   └── task.bash
13:01:25 :: │       └── run_tests
13:01:25 :: │           └── task.bash
13:01:25 :: ```
13:01:25 :: 
13:01:25 :: ---
13:01:25 :: 
13:01:25 :: ## `jobs.yaml`
13:01:25 :: 
13:01:25 :: ```yaml
13:01:25 :: # .dsci/jobs.yaml
13:01:25 :: jobs:
13:01:25 ::   -
13:01:25 ::     id: build
13:01:25 ::     path: job_build/
13:01:25 ::     # Optional override of the PHP version (default is defined in config.yaml)
13:01:25 ::     # params:
13:01:25 ::     #   php_version: "8.2"
13:01:25 :: ```
13:01:25 :: 
13:01:25 :: ---
13:01:25 :: 
13:01:25 :: ## `job_build/config.yaml`  *(default job parameters)*
13:01:25 :: 
13:01:25 :: ```yaml
13:01:25 :: php_version: "8.2"
13:01:25 :: ```
13:01:25 :: 
13:01:25 :: ---
13:01:25 :: 
13:01:25 :: ## `job_build/job.bash`  *(orchestrates the tasks)*
13:01:25 :: 
13:01:25 :: ```bash
13:01:25 :: #!/usr/bin/env bash
13:01:25 :: # job_build/job.bash
13:01:25 :: 
13:01:25 :: # Run tasks sequentially
13:01:25 :: run_task "install_php"
13:01:25 :: run_task "composer_install"
13:01:25 :: run_task "run_tests"
13:01:25 :: ```
13:01:25 :: 
13:01:25 :: ---
13:01:25 :: 
13:01:25 :: ## `job_build/tasks/install_php/task.bash`
13:01:25 :: 
13:01:25 :: ```bash
13:01:25 :: #!/usr/bin/env bash
13:01:25 :: # job_build/tasks/install_php/task.bash
13:01:25 :: 
13:01:25 :: # ------------------------------------------------------------------
13:01:25 :: # Install a specific PHP version on Debian (using apt)
13:01:25 :: # ------------------------------------------------------------------
13:01:25 :: 
13:01:25 :: # Retrieve the requested version from job parameters (or default)
13:01:25 :: php_version=$(config php_version)
13:01:25 :: 
13:01:25 :: echo "=== Installing PHP ${php_version} on Debian ==="
13:01:25 :: 
13:01:25 :: # Update package index
13:01:25 :: apt-get update -y
13:01:25 :: 
13:01:25 :: # Add the sury.org repository (commonly used for multiple PHP versions)
13:01:25 :: apt-get install -y lsb-release ca-certificates apt-transport-https software-properties-common wget gnupg2
13:01:25 :: 
13:01:25 :: wget -qO /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
13:01:25 :: echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
13:01:25 :: 
13:01:25 :: apt-get update -y
13:01:25 :: 
13:01:25 :: # Install the requested PHP version and common extensions
13:01:25 :: apt-get install -y php${php_version} php${php_version}-cli php${php_version}-common php${php_version}-mbstring php${php_version}-xml php${php_version}-curl php${php_version}-zip
13:01:25 :: 
13:01:25 :: # Verify installation
13:01:25 :: php -v
13:01:25 :: 
13:01:25 :: # Export the installed version as state for downstream tasks (optional)
13:01:25 :: update_state '{"php_version":"'"$php_version"'"}'
13:01:25 :: ```
13:01:25 :: 
13:01:25 :: ---
13:01:25 :: 
13:01:25 :: ## `job_build/tasks/composer_install/task.bash`
13:01:25 :: 
13:01:25 :: ```bash
13:01:25 :: #!/usr/bin/env bash
13:01:25 :: # job_build/tasks/composer_install/task.bash
13:01:25 :: 
13:01:25 :: # ------------------------------------------------------------------
13:01:25 :: # Install Composer (if not present) and run `composer install`
13:01:25 :: # ------------------------------------------------------------------
13:01:25 :: 
13:01:25 :: # Ensure PHP is available (state from previous task)
13:01:25 :: php_version=$(config php_version)   # just to prove we can read it again
13:01:25 :: 
13:01:25 :: # Install Composer globally
13:01:25 :: if ! command -v composer >/dev/null 2>&1; then
13:01:25 ::     echo "=== Installing Composer ==="
13:01:25 ::     EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
13:01:25 ::     php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
13:01:25 ::     ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
13:01:25 :: 
13:01:25 ::     if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
13:01:25 ::         echo 'ERROR: Invalid Composer installer checksum'
13:01:25 ::         exit 1
13:01:25 ::     fi
13:01:25 :: 
13:01:25 ::     php composer-setup.php --install-dir=/usr/local/bin --filename=composer
13:01:25 ::     rm composer-setup.php
13:01:25 :: fi
13:01:25 :: 
13:01:25 :: composer --version
13:01:25 :: 
13:01:25 :: # Install project dependencies
13:01:25 :: if [ -f composer.json ]; then
13:01:25 ::     echo "=== Running composer install ==="
13:01:25 ::     composer install --no-interaction --prefer-dist --optimize-autoloader
13:01:25 :: else
13:01:25 ::     echo "WARNING: composer.json not found – skipping dependency install"
13:01:25 :: fi
13:01:25 :: ```
13:01:25 :: 
13:01:25 :: ---
13:01:25 :: 
13:01:25 :: ## `job_build/tasks/run_tests/task.bash`
13:01:25 :: 
13:01:25 :: ```bash
13:01:25 :: #!/usr/bin/env bash
13:01:25 :: # job_build/tasks/run_tests/task.bash
13:01:25 :: 
13:01:25 :: # ------------------------------------------------------------------
13:01:25 :: # Run PHP unit tests (phpunit) and store the result as an artifact
13:01:25 :: # ------------------------------------------------------------------
13:01:25 :: 
13:01:25 :: # Ensure phpunit is available – try local vendor binary first
13:01:25 :: if [ -f vendor/bin/phpunit ]; then
13:01:25 ::     PHPUNIT_CMD="vendor/bin/phpunit"
13:01:25 :: else
13:01:25 ::     # Fallback: install phpunit globally for the requested PHP version
13:01:25 ::     echo "phpunit not found locally – installing globally"
13:01:25 ::     apt-get install -y php${php_version}-phpunit || true   # some Debian versions ship phpunit as a package
13:01:25 ::     PHPUNIT_CMD="phpunit"
13:01:25 :: fi
13:01:25 :: 
13:01:25 :: # Run the tests
13:01:25 :: echo "=== Executing PHP Unit Tests ==="
13:01:25 :: set -o pipefail
13:01:25 :: TEST_OUTPUT=$($PHPUNIT_CMD 2>&1 | tee /dev/stdout)
13:01:25 :: TEST_EXIT_CODE=${PIPESTATUS[0]}
13:01:25 :: 
13:01:25 :: # Save the raw output as an artifact
13:01:25 :: ARTIFACT_DIR="${HOME}/artifacts"
13:01:25 :: mkdir -p "$ARTIFACT_DIR"
13:01:25 :: echo "$TEST_OUTPUT" > "$ARTIFACT_DIR/phpunit_output.txt"
13:01:25 :: 
13:01:25 :: # Export test result state (pass/fail) for potential downstream jobs
13:01:25 :: if [ "$TEST_EXIT_CODE" -eq 0 ]; then
13:01:25 ::     test_status="passed"
13:01:25 :: else
13:01:25 ::     test_status="failed"
13:01:25 :: fi
13:01:25 :: update_state '{"test_status":"'"$test_status"'"}'
13:01:25 :: 
13:01:25 :: # Exit with the original phpunit status so the pipeline fails on test failures
13:01:25 :: exit "$TEST_EXIT_CODE"
13:01:25 :: ```
13:01:25 :: 
13:01:25 :: ---
13:01:25 :: 
13:01:25 :: ### How the pipeline works
13:01:25 :: 
13:01:25 :: 1. **Job `build`** is listed in `jobs.yaml`.  
13:01:25 :: 2. The job reads its default parameter `php_version` from `job_build/config.yaml`.  
13:01:25 :: 3. **Task `install_php`** installs the requested PHP version on a Debian‑based runner and stores the version in the job state.  
13:01:25 :: 4. **Task `composer_install`** ensures Composer is present and installs project dependencies.  
13:01:25 :: 5. **Task `run_tests`** runs `phpunit`, writes the full console output to `~/artifacts/phpunit_output.txt` (so any later job could read it) and exports a simple `test_status` state (`passed`/`failed`).  
13:01:25 :: 
13:01:25 :: All logic lives in standard Bash scripts; the tiny `jobs.yaml` only declares the job and its optional parameters, satisfying the DSCI “99 % less YAML” principle.
[task stderr]
13:01:25 :: 
13:01:25 :: real	0m4.984s
13:01:25 :: user	0m0.611s
13:01:25 :: sys	0m0.100s
saving job artifacts ...
>> PUT http://127.0.0.1:8181/file/project/dsci/job/007aefe.1789736466/filename/answer.md
>> PUT http://127.0.0.1:8181/file/project/dsci/job/007aefe.1789736466/filename/question.txt
>>> POST http://127.0.0.1:8181/stash
---

---