mirror of
https://github.com/Cacti/cacti.git
synced 2026-11-03 10:37:46 +09:00
* build: raise the 1.3 floor to PHP 8.3 RHEL 10 ships 8.3 in AppStream and dropped modularity, so an 8.4 floor would put every RHEL, Alma and Rocky 10 install on Remi. Ubuntu 24.04 is 8.3 as well, which makes it the lowest common denominator of the current LTS fleet. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: raise the documented PHP floor to 8.3 The 1.2.x column keeps 8.1, which still matches that branch's composer constraint. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: run process lock coverage on PHP 8.3 * fix: finish PHP 8.3 floor cleanup Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
541 lines
19 KiB
YAML
541 lines
19 KiB
YAML
# +-------------------------------------------------------------------------+
|
|
# | Copyright (C) 2004-2026 The Cacti Group |
|
|
# | |
|
|
# | This program is free software; you can redistribute it and/or |
|
|
# | modify it under the terms of the GNU General Public License |
|
|
# | as published by the Free Software Foundation; either version 2 |
|
|
# | of the License, or (at your option) any later version. |
|
|
# | |
|
|
# | This program is distributed in the hope that it will be useful, |
|
|
# | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
# | GNU General Public License for more details. |
|
|
# +-------------------------------------------------------------------------+
|
|
# | Cacti: The Complete RRDtool-based Graphing Solution |
|
|
# +-------------------------------------------------------------------------+
|
|
# | This code is designed, written, and maintained by the Cacti Group. See |
|
|
# | about.php and/or the AUTHORS file for specific developer information. |
|
|
# +-------------------------------------------------------------------------+
|
|
# | http://www.cacti.net/ |
|
|
# +-------------------------------------------------------------------------+
|
|
|
|
name: Cacti Commit Audit
|
|
|
|
on:
|
|
push:
|
|
branches: [develop, '1.2.x']
|
|
pull_request:
|
|
branches: [develop, '1.2.x']
|
|
merge_group:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: build-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
"COMPOSER_ALLOW_SUPERUSER": 1
|
|
|
|
jobs:
|
|
javascript-contracts:
|
|
name: JavaScript contracts
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 10
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Install Node.js
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Install managed JavaScript and test contracts
|
|
run: |
|
|
set -euo pipefail
|
|
npm ci
|
|
npm test
|
|
npm run test:coverage
|
|
|
|
# spelling:
|
|
# name: Spell Check
|
|
# runs-on: ubuntu-latest
|
|
# steps:
|
|
# - name: Checkout
|
|
# uses: actions/checkout@v7.0.0
|
|
|
|
# - name: Install codespell
|
|
# run: pip install codespell==2.4.1
|
|
|
|
# - name: Run codespell
|
|
# run: codespell --config .codespell.cfg
|
|
|
|
runtime-compatibility:
|
|
name: PHP ${{ matrix.php }} locked runtime
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 20
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
php: ['8.3', '8.4', '8.5']
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup locked PHP dependencies
|
|
uses: ./.github/actions/setup-php-composer
|
|
with:
|
|
php-version: ${{ matrix.php }}
|
|
extensions: intl, mysql, gd, ldap, gmp, xml, curl, json, mbstring
|
|
coverage: none
|
|
dependency-mode: locked-runtime
|
|
install-args: --no-dev --prefer-dist --no-progress --no-interaction
|
|
|
|
- name: Verify actual platform requirements
|
|
run: composer check-platform-reqs --no-dev
|
|
|
|
- name: Smoke-test the production autoloader
|
|
run: php -r "require 'include/vendor/autoload.php';"
|
|
|
|
native-dependencies:
|
|
name: PHP ${{ matrix.php }} native dependencies
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
php: ['8.3', '8.4', '8.5']
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
|
with:
|
|
node-version: '22'
|
|
cache: npm
|
|
|
|
- name: Build managed JavaScript
|
|
run: npm ci
|
|
|
|
- name: Setup native PHP dependencies
|
|
uses: ./.github/actions/setup-php-composer
|
|
with:
|
|
php-version: ${{ matrix.php }}
|
|
extensions: intl, mysql, gd, ldap, gmp, xml, curl, json, mbstring
|
|
coverage: none
|
|
dependency-mode: native
|
|
cache-dependency-path: composer.json
|
|
|
|
- name: Create native compatibility definition
|
|
run: |
|
|
set -euo pipefail
|
|
cp composer.json composer.compat.json
|
|
COMPOSER=composer.compat.json composer config platform.php "${{ matrix.php }}"
|
|
|
|
- name: Resolve native dependencies
|
|
env:
|
|
COMPOSER: composer.compat.json
|
|
run: composer update --prefer-dist --no-progress --no-interaction
|
|
|
|
- name: Run unit tests
|
|
run: include/vendor/bin/pest --display-warnings --testsuite=Unit
|
|
|
|
check:
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 60
|
|
|
|
services:
|
|
mysql:
|
|
image: mariadb:10.6@sha256:2fdc84794931c0abde9ba6a8c9cb5a4635a02d851a103f0301a8b606dfc5cd98
|
|
env:
|
|
MYSQL_DATABASE: cacti
|
|
MYSQL_HOST: 127.0.0.1
|
|
MYSQL_USER: cactiuser
|
|
MYSQL_PASSWORD: cactiuser
|
|
MYSQL_ROOT_PASSWORD: cactiroot
|
|
ports:
|
|
- 3306:3306
|
|
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
|
|
|
name: PHP 8.3 locked integration
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
|
with:
|
|
node-version: '22'
|
|
cache: npm
|
|
|
|
- name: Build managed JavaScript
|
|
run: npm ci
|
|
|
|
- name: Setup locked PHP 8.3 dependencies
|
|
uses: ./.github/actions/setup-php-composer
|
|
with:
|
|
php-version: '8.3'
|
|
extensions: intl, mysql, gd, ldap, gmp, xml, curl, json, mbstring
|
|
ini-values: post_max_size=256M, max_execution_time=60, date.timezone=America/New_York
|
|
coverage: none
|
|
dependency-mode: locked-quality
|
|
install-args: --prefer-dist --no-progress --no-interaction
|
|
|
|
- name: Check PHP version
|
|
run: php -v
|
|
|
|
- name: Prime fontconfig's cache
|
|
run: sudo fc-cache
|
|
|
|
- name: Validate composer.json and composer.lock
|
|
run: composer validate --strict
|
|
|
|
- name: Verify actual platform requirements
|
|
run: composer check-platform-reqs
|
|
|
|
- name: Run Linter on base code
|
|
run: composer run-script lint
|
|
working-directory: .
|
|
|
|
- name: Run hardening pattern guard
|
|
if: github.event_name == 'pull_request'
|
|
run: composer run-script hardening-patterns -- --base="${{ github.event.pull_request.base.sha }}" --head=HEAD
|
|
working-directory: .
|
|
|
|
- name: Reject committed Composer dependencies
|
|
run: composer run-script vendor-policy
|
|
working-directory: .
|
|
|
|
- name: Checking coding standards on base code
|
|
run: composer run-script phpcsfixer
|
|
working-directory: .
|
|
|
|
- name: Run PHPStan at Level 6 on base code
|
|
run: composer run-script phpstan
|
|
working-directory: .
|
|
|
|
- name: Run Pest Unit Tests
|
|
run: composer run-script test
|
|
working-directory: .
|
|
|
|
- name: Checkout Thold Plugin
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
repository: Cacti/plugin_thold
|
|
ref: 34c4a69b752b8eb0d73e90f1cd1c2a9b317a9d1b
|
|
path: plugins/thold
|
|
persist-credentials: false
|
|
|
|
- name: Checkout Monitor Plugin
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
repository: Cacti/plugin_monitor
|
|
ref: 11c7b6c6422d7ffaba9c2dcac25b729d9cb6ff12
|
|
path: plugins/monitor
|
|
persist-credentials: false
|
|
|
|
- name: Checkout MacTrack Plugin
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
repository: Cacti/plugin_mactrack
|
|
ref: 408adb447cbb7b4ef4360bade646b8d926f7b293
|
|
path: plugins/mactrack
|
|
persist-credentials: false
|
|
|
|
- name: Checkout Intropage Plugin
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
repository: Cacti/plugin_intropage
|
|
ref: f3a00ff7fb4a7f0c26b8910cd32c5c98e45da1e9
|
|
path: plugins/intropage
|
|
persist-credentials: false
|
|
|
|
- name: Checkout FlowView Plugin
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
repository: Cacti/plugin_flowview
|
|
ref: ee37c8938c99bc49f6a2933f373865c65f51fba0
|
|
path: plugins/flowview
|
|
persist-credentials: false
|
|
|
|
- name: Checkout Audit Plugin
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
repository: Cacti/plugin_audit
|
|
ref: 1d7be4f422a3831dcaa150747ad7314168b60605
|
|
path: plugins/audit
|
|
persist-credentials: false
|
|
|
|
- name: Checkout Syslog Plugin
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
repository: Cacti/plugin_syslog
|
|
ref: 82df21ba2acf38ec4052aa862d2b53c67287f311
|
|
path: plugins/syslog
|
|
persist-credentials: false
|
|
|
|
- name: Enable Syslog batch installation
|
|
run: |
|
|
set -euo pipefail
|
|
# With syslog we have to enable batch installs using the lines below
|
|
cd ${{ github.workspace }}/plugins/syslog
|
|
cp -p config.php.dist config.php
|
|
# shellcheck disable=SC2016
|
|
sed -i 's/\/\/\$syslog_install_options/\$syslog_install_options/g' config.php
|
|
|
|
- name: Move plugin config files
|
|
run: |
|
|
set -euo pipefail
|
|
cp -p ${{ github.workspace }}/plugins/flowview/config.php.dist ${{ github.workspace }}/plugins/flowview/config.php
|
|
cp -p ${{ github.workspace }}/plugins/syslog/config.php.dist ${{ github.workspace }}/plugins/syslog/config.php
|
|
sed -i 's/\/\/\$/\$/g' ${{ github.workspace }}/plugins/syslog/config.php
|
|
|
|
- name: Run apt-get update
|
|
run: sudo apt-get -y update
|
|
|
|
- name: Install Apache and Tools
|
|
run: sudo apt-get install apache2 snmp snmpd rrdtool fping libapache2-mod-php
|
|
|
|
- name: Start SNMPD Agent and Test Agent
|
|
run: |
|
|
set -euo pipefail
|
|
sudo systemctl start snmpd
|
|
sudo snmpwalk -c public -v2c -On localhost .1.3.6.1.2.1.1
|
|
|
|
- name: Link Web Root and Grant the Web Group Access
|
|
run: |
|
|
set -euo pipefail
|
|
sudo ln -s /home/runner/work/cacti/cacti /var/www/html
|
|
sudo chgrp -R www-data "${{ github.workspace }}"
|
|
sudo find "${{ github.workspace }}" -type d -exec chmod g+rwx {} +
|
|
sudo find "${{ github.workspace }}" -type f -exec chmod g+rw {} +
|
|
sudo chmod o+x /home
|
|
sudo chmod o+x /home/runner
|
|
sudo chmod o+x /home/runner/work
|
|
sudo chmod o+x /home/runner/work/cacti
|
|
sudo chmod o+x /home/runner/work/cacti/cacti
|
|
|
|
- name: Configure Apache Site
|
|
run: |
|
|
set -euo pipefail
|
|
cp ${{ github.workspace }}/tests/tools/cacti.conf /tmp/cacti.conf
|
|
sed -i "s#GITHUB_WORKSPACE#${{ github.workspace }}#g" /tmp/cacti.conf
|
|
sudo cp /tmp/cacti.conf /etc/apache2/sites-available/000-default.conf
|
|
|
|
- name: Restart Apache2
|
|
run: sudo systemctl restart apache2
|
|
|
|
- name: Create and Initialize Database
|
|
run: |
|
|
set -euo pipefail
|
|
mysql_config="$RUNNER_TEMP/mysql-client.cnf"
|
|
install -m 0600 /dev/null "$mysql_config"
|
|
printf '%s\n' \
|
|
'[client]' \
|
|
'user = root' \
|
|
'password = cactiroot' \
|
|
'host = 127.0.0.1' \
|
|
'max_allowed_packet = 500000000' > "$mysql_config"
|
|
mysql_args=(--defaults-extra-file="$mysql_config")
|
|
mysql "${mysql_args[@]}" -e "CREATE DATABASE IF NOT EXISTS cacti;"
|
|
mysql "${mysql_args[@]}" -e "CREATE USER 'cactiuser'@'localhost' IDENTIFIED BY 'cactiuser';"
|
|
mysql "${mysql_args[@]}" -e "GRANT ALL PRIVILEGES ON cacti.* TO 'cactiuser'@'localhost';"
|
|
mysql "${mysql_args[@]}" -e "FLUSH PRIVILEGES;"
|
|
mysql "${mysql_args[@]}" -e "SET GLOBAL max_allowed_packet=500000000;"
|
|
mysql "${mysql_args[@]}" cacti < "${{ github.workspace }}/cacti.sql"
|
|
mysql "${mysql_args[@]}" -e "INSERT INTO settings (name, value) VALUES ('path_php_binary', '/bin/php')" cacti
|
|
|
|
- name: Prime Cacti config.php File
|
|
run: |
|
|
set -euo pipefail
|
|
sudo install -o runner -g www-data -m 0660 \
|
|
${{ github.workspace }}/include/config.php.dist \
|
|
${{ github.workspace }}/include/config.php
|
|
sudo sed -i "s/localhost/127.0.0.1/g" ${{ github.workspace }}/include/config.php
|
|
|
|
- name: Setup Cacti Daemon
|
|
run: |
|
|
set -euo pipefail
|
|
sudo cp ${{ github.workspace }}/tests/tools/cactid.service /etc/systemd/system/cactid.service
|
|
sudo sed -i 's/apache/www-data/g' /etc/systemd/system/cactid.service
|
|
sudo systemctl enable cactid
|
|
sudo systemctl start cactid
|
|
for _ in {1..15}; do
|
|
if systemctl is-active --quiet cactid; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if ! systemctl is-active --quiet cactid; then
|
|
sudo systemctl status --no-pager cactid || true
|
|
sudo journalctl --no-pager -xeu cactid.service || true
|
|
echo "Cacti daemon failed to become active"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check install code for validity
|
|
run: php -q tests/tools/check_install_code.php
|
|
|
|
- name: Check All Resource XML File Syntax
|
|
run: php tests/tools/check_xml_syntax.php
|
|
|
|
- name: Check Poller Script Syntax after Package Import
|
|
run: find scripts -name '*.php' -print0 | xargs -0 -n1 php -l
|
|
|
|
- name: Check that all CLI scripts have a valid --version flag
|
|
run: sudo -u www-data -- bash tests/tools/check_cli_version.sh
|
|
|
|
- name: Install Cacti through the CLI
|
|
run: sudo -u www-data -- php cli/install_cacti.php --accept-eula --install --force
|
|
|
|
- name: Verify Installer Postconditions
|
|
run: |
|
|
set -euo pipefail
|
|
cd ${{ github.workspace }}
|
|
mysql_config="$RUNNER_TEMP/mysql-client.cnf"
|
|
mysql_args=(--defaults-extra-file="$mysql_config")
|
|
expected_tables=$(grep -c '^CREATE TABLE' cacti.sql)
|
|
actual_tables=$(mysql "${mysql_args[@]}" cacti --batch --skip-column-names -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()")
|
|
installed_version=$(mysql "${mysql_args[@]}" cacti --batch --skip-column-names -e "SELECT cacti FROM version")
|
|
host_templates=$(mysql "${mysql_args[@]}" cacti --batch --skip-column-names -e "SELECT COUNT(*) FROM host_template")
|
|
test "$actual_tables" -eq "$expected_tables"
|
|
test "$installed_version" != "new_install"
|
|
test "$host_templates" -gt 0
|
|
|
|
- name: Install Cacti Packages through CLI
|
|
run: sudo -u www-data -- bash tests/tools/install_packages.sh
|
|
|
|
- name: Check All Resource XML File Syntax Post Package Install
|
|
run: php tests/tools/check_xml_syntax.php
|
|
|
|
- name: Check all perl scripts for syntax errors
|
|
run: find scripts -name '*.pl' -print0 | xargs -0 -n1 perl -c
|
|
|
|
- name: Audit the Installation Schema
|
|
run: sudo -u www-data -- php cli/audit_database.php --report
|
|
|
|
- name: Install and Enable Plugins
|
|
run: sudo -u www-data -- php cli/plugin_manage.php --plugin=thold --plugin=intropage --plugin=monitor --plugin=mactrack --plugin=audit --plugin=flowview --plugin=syslog --install --enable --allperms
|
|
|
|
- name: Add Device for Moc Test, Check CLI scripts for Errors
|
|
run: |
|
|
set -euo pipefail
|
|
sudo -u www-data -- php cli/add_device.php --description=test_device --ip=127.0.0.1 --template=25
|
|
sudo -u www-data -- php cli/rebuild_poller_cache.php --debug
|
|
sudo -u www-data -- php cli/poller_reindex_hosts.php --id=all --debug
|
|
|
|
- name: Run Cacti poller
|
|
run: |
|
|
set -euo pipefail
|
|
sudo -u www-data -- php poller.php --poller=1 --force --debug
|
|
grep -q "SYSTEM STATS" log/cacti.log
|
|
|
|
# The recursive crawl walks the whole authenticated UI one request at a
|
|
# time and is the single most expensive step in CI. Nothing it exercises can
|
|
# change unless server-rendered code, assets or the schema changed, so skip
|
|
# it when a pull request touches only tests, workflows or documentation.
|
|
- name: Decide whether the page crawl can affect this change
|
|
id: crawl_scope
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ "${{ github.event_name }}" != 'pull_request' ]]; then
|
|
echo 'required=true' >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
base='${{ github.event.pull_request.base.sha }}'
|
|
|
|
# Fail open: if the diff cannot be read, run the crawl.
|
|
if ! changed=$(git diff --name-only "$base" HEAD 2>/dev/null); then
|
|
echo 'required=true' >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ -z "$changed" ]]; then
|
|
echo 'required=true' >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
if printf '%s\n' "$changed" | grep -qvE '^(tests/|\.github/|docs/|locales/|CHANGELOG|changelog\.d/|.*\.md$)'; then
|
|
echo 'required=true' >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo 'required=false' >> "$GITHUB_OUTPUT"
|
|
echo "Only tests, workflows or documentation changed; skipping the page crawl."
|
|
fi
|
|
|
|
- name: Check All Pages Using Recursive wget
|
|
if: steps.crawl_scope.outputs.required == 'true'
|
|
run: |
|
|
set -euo pipefail
|
|
install -m 0600 /dev/null .my.cnf
|
|
printf '%s\n' \
|
|
'[client]' \
|
|
'user = root' \
|
|
'password = cactiroot' \
|
|
'host = 127.0.0.1' > .my.cnf
|
|
sudo tests/tools/check_all_pages.sh -vmstat 10 -ps 10
|
|
|
|
- name: View Cacti log on failure
|
|
if: failure()
|
|
run: |
|
|
set -euo pipefail
|
|
log_file=${{ github.workspace }}/log/cacti.log
|
|
if [[ -f "$log_file" ]]; then
|
|
cat "$log_file"
|
|
else
|
|
echo "Cacti log was not created"
|
|
fi
|
|
|
|
changelog:
|
|
name: CHANGELOG format
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 10
|
|
steps:
|
|
- name: Check out source
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
|
|
- name: Validate CHANGELOG ordering and entry format
|
|
run: python3 .github/scripts/check-changelog.py
|
|
|
|
required:
|
|
name: CI / required
|
|
if: always()
|
|
needs: [runtime-compatibility, native-dependencies, check, changelog]
|
|
runs-on: ubuntu-slim
|
|
timeout-minutes: 5
|
|
steps:
|
|
- name: Verify required jobs
|
|
env:
|
|
RUNTIME_RESULT: ${{ needs.runtime-compatibility.result }}
|
|
NATIVE_RESULT: ${{ needs.native-dependencies.result }}
|
|
INTEGRATION_RESULT: ${{ needs.check.result }}
|
|
CHANGELOG_RESULT: ${{ needs.changelog.result }}
|
|
run: |
|
|
set -euo pipefail
|
|
for result in \
|
|
"$RUNTIME_RESULT" \
|
|
"$NATIVE_RESULT" \
|
|
"$INTEGRATION_RESULT" \
|
|
"$CHANGELOG_RESULT"; do
|
|
test "$result" = success
|
|
done
|