diff --git a/.github/workflows/self-test.yml b/.github/workflows/self-test.yml index 5af7b19..c4cfa2f 100644 --- a/.github/workflows/self-test.yml +++ b/.github/workflows/self-test.yml @@ -232,6 +232,8 @@ jobs: assert "setup_system_packages=false" assert "service_redis=false" assert "service_nats=false" + assert "service_postgres=false" + assert "service_mysql=false" echo "node-only: single-language path clean." - name: Assert outputs (python-poetry) diff --git a/actions/environment-setup/action.yml b/actions/environment-setup/action.yml index d3f3065..10279c5 100644 --- a/actions/environment-setup/action.yml +++ b/actions/environment-setup/action.yml @@ -103,6 +103,12 @@ outputs: service_nats: description: "Whether nats-server was installed onto PATH (true/false)" value: ${{ steps.config.outputs.service_nats }} + service_postgres: + description: "Whether PostgreSQL was installed + started (true/false). When true, POSTGRES_TEST_URL is set in the environment." + value: ${{ steps.config.outputs.service_postgres }} + service_mysql: + description: "Whether MySQL was installed + started (true/false). When true, MYSQL_TEST_URL is set in the environment." + value: ${{ steps.config.outputs.service_mysql }} setup_system_packages: description: "Whether apt system_packages were installed (true/false)" value: ${{ steps.config.outputs.setup_system_packages }} @@ -547,11 +553,60 @@ runs: rm -rf "$TMP" nats-server --version + - name: Install + start PostgreSQL + if: steps.config.outputs.service_postgres == 'true' && runner.os == 'Linux' + shell: bash + run: | + set -euo pipefail + echo "🧰 Installing PostgreSQL via apt" + sudo apt-get update -y + sudo apt-get install -y --no-install-recommends postgresql postgresql-contrib + sudo service postgresql start + # Wait up to 20s for postgres to accept connections. + for i in {1..20}; do + if sudo -u postgres psql -c 'SELECT 1' >/dev/null 2>&1; then break; fi + sleep 1 + done + sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL' + CREATE USER mcpg WITH PASSWORD 'mcpg' CREATEDB; + CREATE DATABASE mcpg_test OWNER mcpg; + SQL + echo "POSTGRES_TEST_URL=postgres://mcpg:mcpg@localhost/mcpg_test" >> "$GITHUB_ENV" + psql --version + + - name: Install + start MySQL + if: steps.config.outputs.service_mysql == 'true' && runner.os == 'Linux' + shell: bash + run: | + set -euo pipefail + echo "🧰 Installing MySQL via apt" + # GitHub's ubuntu-latest ships with mysql-server pre-installed on most + # releases; ensure it's actually available and running. + if ! command -v mysqld >/dev/null 2>&1; then + sudo apt-get update -y + sudo apt-get install -y --no-install-recommends mysql-server + fi + sudo service mysql start + for i in {1..20}; do + if sudo mysql -e 'SELECT 1' >/dev/null 2>&1; then break; fi + sleep 1 + done + sudo mysql -v <<'SQL' + CREATE USER IF NOT EXISTS 'mcpg'@'127.0.0.1' IDENTIFIED BY 'mcpg'; + CREATE USER IF NOT EXISTS 'mcpg'@'localhost' IDENTIFIED BY 'mcpg'; + CREATE DATABASE IF NOT EXISTS mcpg_test; + GRANT ALL PRIVILEGES ON mcpg_test.* TO 'mcpg'@'127.0.0.1'; + GRANT ALL PRIVILEGES ON mcpg_test.* TO 'mcpg'@'localhost'; + FLUSH PRIVILEGES; + SQL + echo "MYSQL_TEST_URL=mysql://mcpg:mcpg@127.0.0.1/mcpg_test" >> "$GITHUB_ENV" + mysql --version + - name: Warn on non-Linux services request - if: (steps.config.outputs.service_redis == 'true' || steps.config.outputs.service_nats == 'true') && runner.os != 'Linux' + if: (steps.config.outputs.service_redis == 'true' || steps.config.outputs.service_nats == 'true' || steps.config.outputs.service_postgres == 'true' || steps.config.outputs.service_mysql == 'true') && runner.os != 'Linux' shell: bash run: | - echo "::warning::services (redis/nats) currently install on Linux only; ignored on ${{ runner.os }}." + echo "::warning::services (redis/nats/postgres/mysql) currently install on Linux only; ignored on ${{ runner.os }}." # ══════════════════════════════════════════════════════════════════════════ @@ -587,8 +642,10 @@ runs: fi SERVICES="" - [[ "${{ steps.config.outputs.service_redis }}" == "true" ]] && SERVICES="${SERVICES}redis " - [[ "${{ steps.config.outputs.service_nats }}" == "true" ]] && SERVICES="${SERVICES}nats " + [[ "${{ steps.config.outputs.service_redis }}" == "true" ]] && SERVICES="${SERVICES}redis " + [[ "${{ steps.config.outputs.service_nats }}" == "true" ]] && SERVICES="${SERVICES}nats " + [[ "${{ steps.config.outputs.service_postgres }}" == "true" ]] && SERVICES="${SERVICES}postgres " + [[ "${{ steps.config.outputs.service_mysql }}" == "true" ]] && SERVICES="${SERVICES}mysql " if [[ -n "$SERVICES" ]]; then echo "| Services | ✅ ${SERVICES% } |" >> $GITHUB_STEP_SUMMARY fi diff --git a/actions/environment-setup/schema.json b/actions/environment-setup/schema.json index 965e961..5c26b4d 100644 --- a/actions/environment-setup/schema.json +++ b/actions/environment-setup/schema.json @@ -180,7 +180,7 @@ "services": { "type": "object", - "description": "External daemons installed onto the runner's PATH so tests can spawn them as subprocesses (via Command::new(\"redis-server\") etc.). Each key toggles a specific service binary. Linux runners only for now.", + "description": "External daemons the runner needs for tests. `redis` and `nats` are installed onto PATH so tests can spawn them as subprocesses; `postgres` and `mysql` are installed AND auto-started with a test user/database, and the connection URL is exported as an env var for tests to read. Linux runners only for now.", "additionalProperties": false, "properties": { "redis": { @@ -190,6 +190,14 @@ "nats": { "type": "boolean", "description": "Install `nats-server` by downloading the latest stable release from github.com/nats-io/nats-server." + }, + "postgres": { + "type": "boolean", + "description": "Install PostgreSQL via apt, start the daemon, create a `mcpg` user + `mcpg_test` database, and export `POSTGRES_TEST_URL=postgres://mcpg:mcpg@localhost/mcpg_test` so tests can connect." + }, + "mysql": { + "type": "boolean", + "description": "Install MySQL via apt, start the daemon, create a `mcpg` user + `mcpg_test` database, and export `MYSQL_TEST_URL=mysql://mcpg:mcpg@127.0.0.1/mcpg_test` so tests can connect." } } }, diff --git a/actions/environment-setup/scripts/parse-config.sh b/actions/environment-setup/scripts/parse-config.sh index cd3e1f3..660e776 100755 --- a/actions/environment-setup/scripts/parse-config.sh +++ b/actions/environment-setup/scripts/parse-config.sh @@ -90,6 +90,8 @@ if [[ ! -f "$CONFIG_FILE" ]]; then out "setup_c=false" out "service_redis=false" out "service_nats=false" + out "service_postgres=false" + out "service_mysql=false" exit 0 fi @@ -352,10 +354,15 @@ fi # ------------------------------------------------------------------------------ SVC_REDIS=$(yq_get '.services.redis' "false") SVC_NATS=$(yq_get '.services.nats' "false") +SVC_POSTGRES=$(yq_get '.services.postgres' "false") +SVC_MYSQL=$(yq_get '.services.mysql' "false") out "service_redis=$SVC_REDIS" out "service_nats=$SVC_NATS" -if [[ "$SVC_REDIS" == "true" || "$SVC_NATS" == "true" ]]; then - echo " ✓ Services: redis=$SVC_REDIS, nats=$SVC_NATS" +out "service_postgres=$SVC_POSTGRES" +out "service_mysql=$SVC_MYSQL" +if [[ "$SVC_REDIS" == "true" || "$SVC_NATS" == "true" \ + || "$SVC_POSTGRES" == "true" || "$SVC_MYSQL" == "true" ]]; then + echo " ✓ Services: redis=$SVC_REDIS, nats=$SVC_NATS, postgres=$SVC_POSTGRES, mysql=$SVC_MYSQL" fi echo "✅ Configuration parsed successfully"