diff --git a/.github/actions/workflow-info/action.yaml b/.github/actions/workflow-info/action.yaml new file mode 100644 index 0000000..06f2f83 --- /dev/null +++ b/.github/actions/workflow-info/action.yaml @@ -0,0 +1,62 @@ +name: 'Report Workflow Information' +description: 'Reusable action meant to be used in workflow steps' +branding: + icon: 'watch' + color: 'green' + +inputs: + title: + description: 'A reference to put in the report title' + required: true + default: 'the Job' + parameters: + description: 'Input variables used in Job' + required: false + content: + description: 'Content to put in the report' + required: false +outputs: + status: + description: "Return report status" + value: ${{ steps.report_workflow_generation.outputs.status }} +runs: + using: "composite" + steps: + - name: Report Workflow Information + id: report_workflow_generation + env: + REPORT_PARAMS: '${{ inputs.parameters }}' + REPORT_CONTENT: '${{ inputs.content }}' + shell: bash + run: | + echo "::group::Generating report" + echo "status=started" >> "${GITHUB_OUTPUT}"; + + dump_ctx(){ + echo "::group::Context ${1:-Unknown}" + local text; + if ! text="$(cat -)"; then printf 'Failed to dump context for %s\n' "${1:-Unknown}" >> "${GITHUB_STEP_SUMMARY}"; fi + text="${text#"${text%%[![:space:]]*}"}" + if test "${#text}" -gt 3; then + printf '\n### %s Context\n\n\n```json\n%s\n```\n' "${1:-Unknown}" "${text:-Nothing in context}" >> "${GITHUB_STEP_SUMMARY}"; + fi + echo "::endgroup::"; + }; + + printf '# Workflow Information on ${{ inputs.title }}\n\n' >> "${GITHUB_STEP_SUMMARY}"; + printf '\n## Event Information\n\n' >> "${GITHUB_STEP_SUMMARY}"; + echo '- github.ref_name: ${{ github.ref_name }}' >> "${GITHUB_STEP_SUMMARY}"; + echo '- github.sha: ${{ github.sha }}' >> "${GITHUB_STEP_SUMMARY}"; + + echo "${REPORT_PARAMS:-}" | dump_ctx "Parameters"; + if test -n "${REPORT_CONTENT:-}"; then + printf '\n## Summary\n\n' >> "${GITHUB_STEP_SUMMARY}"; + echo "${REPORT_CONTENT:-}" >> "${GITHUB_STEP_SUMMARY}"; + fi + + printf '\n## Context Information\n' >> "${GITHUB_STEP_SUMMARY}"; + echo '${{ toJson(runner) }}' | dump_ctx "Runner"; + echo '${{ toJson(job) }}' | dump_ctx "Job"; + + echo "status=finished" >> "${GITHUB_OUTPUT}"; + echo "::endgroup::" diff --git a/.github/workflows/testing_changes.yml b/.github/workflows/testing_changes.yml index 9792108..d5b4535 100644 --- a/.github/workflows/testing_changes.yml +++ b/.github/workflows/testing_changes.yml @@ -1,15 +1,11 @@ -# for simplicity we are checking compilation and testing everything on the Ubuntu environment only. - name: testing_changes -on: +on: push: - branches-ignore: - - 'main' - - 'master' - - 'draft/*' + branches: [ "master" ] pull_request: - types: [opened, reopened, synchronize] + branches: [ "master" ] + types: [opened, reopened, synchronize, ready_for_review] release: types: [created, edited] workflow_dispatch: @@ -62,53 +58,246 @@ jobs: ci: name: ci-testing_changes strategy: - # max-parallel: 1 + fail-fast: false matrix: - target: [latest, 5, 5.0.2, 5-noble, 5-jammy, 4, 4.0.5, 3, 3.0.12] - os: [ "ubuntu-latest" ] - #TODO: os: [ "ubuntu-latest", "windows-latest", "macos-latest" ] + os: [ "ubuntu-latest", "windows-latest", "macos-13" ] + # ubuntu-latest: https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md + # macos-13: https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md (x86_64/amd64) + # macos-latest (ARM64/macos-15) is excluded: nested virtualisation required for Docker is not supported + # windows-latest: https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-Readme.md + target: [ 'latest', '5', '5.0.2', '5-noble', '5-jammy', '4', '4.0.5', '3', '3.0.12' ] + # https://github.com/FirebirdSQL/firebird-docker + exclude: + # Limit non-ubuntu to a representative subset to keep CI time manageable + - { os: "windows-latest", target: "5.0.2" } + - { os: "windows-latest", target: "5-noble" } + - { os: "windows-latest", target: "5-jammy" } + - { os: "windows-latest", target: "4.0.5" } + - { os: "windows-latest", target: "3.0.12" } + - { os: "macos-13", target: "5.0.2" } + - { os: "macos-13", target: "5-noble" } + - { os: "macos-13", target: "5-jammy" } + - { os: "macos-13", target: "4.0.5" } + - { os: "macos-13", target: "3.0.12" } runs-on: "${{ matrix.os }}" steps: - name: Checkout source code on event ${{ github.event_name }} triggered by '${{ github.sha }}' if: github.event_name != 'release' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Testing changes with FirebirdSQL version ${{ matrix.target }} on ${{ github.event_name }} triggered by '${{ github.sha }}' + - name: Report Workflow Information if: github.event_name != 'release' - uses: ./ # Uses an action in the root directory + id: workflow_report + uses: ./.github/actions/workflow-info + with: + title: '${{ github.ref_name }}' + parameters: '${{ toJson(inputs) }}' + content: | + - OS: ${{ matrix.os }} + - Firebird version: ${{ matrix.target }} + - Ref: ${{ github.head_ref }} + + # macOS runners do not have Docker pre-installed; use the official docker/setup-docker-action (Lima VM). + - name: Setup Docker on macOS (${{ matrix.os }}) + if: github.event_name != 'release' && runner.os == 'macOS' + uses: docker/setup-docker-action@v5 + env: + LIMA_START_ARGS: "--cpus 4 --memory 8" + + # Windows runners use Windows containers by default; switch to Linux containers. + # This step tries multiple approaches in order: + # 1. DockerCli.exe (Docker Desktop - not present on GitHub-hosted runners) + # 2. docker context use desktop-linux (available in some Docker configurations) + # 3. npipe:////./pipe/docker_engine_linux (Linux containers named pipe on Windows) + # 4. WSL2 Ubuntu: install dockerd if needed and start it on tcp://0.0.0.0:2375 + # The DOCKER_HOST is persisted to GITHUB_ENV so all subsequent steps use it. + - name: Switch to Linux containers on Windows + if: github.event_name != 'release' && runner.os == 'Windows' + shell: pwsh + run: | + $osType = (docker info --format '{{.OSType}}' 2>&1) -replace '\s', '' + Write-Host "Docker OS type (initial): $osType" + + if ($osType -eq 'linux') { + Write-Host "Docker is already in Linux containers mode." + exit 0 + } + + # Method 1: DockerCli.exe (Docker Desktop) + $dockerCli = 'C:\Program Files\Docker\Docker\DockerCli.exe' + if (Test-Path $dockerCli) { + Write-Host "Switching Docker Desktop to Linux containers via DockerCli.exe..." + & $dockerCli -SwitchLinuxEngine + # Wait for the Linux daemon to finish starting up (Docker Desktop takes ~30 s to restart) + Start-Sleep -Seconds 30 + $osType = (docker info --format '{{.OSType}}' 2>&1) -replace '\s', '' + Write-Host "Docker OS type after DockerCli switch: $osType" + if ($osType -eq 'linux') { exit 0 } + } + + # Method 2: docker context use desktop-linux + $contexts = (docker context ls --format '{{.Name}}' 2>&1) + Write-Host "Available Docker contexts: $contexts" + if ($contexts -match 'desktop-linux') { + Write-Host "Switching to desktop-linux Docker context..." + docker context use desktop-linux + Start-Sleep -Seconds 10 + $osType = (docker info --format '{{.OSType}}' 2>&1) -replace '\s', '' + Write-Host "Docker OS type after context switch: $osType" + if ($osType -eq 'linux') { exit 0 } + } + + # Method 3: Linux containers named pipe (available when Docker Engine has Hyper-V support) + Write-Host "Trying Linux containers named pipe..." + $env:DOCKER_HOST = 'npipe:////./pipe/docker_engine_linux' + $osType = (docker info --format '{{.OSType}}' 2>&1) -replace '\s', '' + Write-Host "Docker OS type via linux pipe: $osType" + if ($osType -eq 'linux') { + Write-Host "Connected to Linux containers daemon via named pipe." + "DOCKER_HOST=npipe:////./pipe/docker_engine_linux" | Out-File -FilePath $env:GITHUB_ENV -Append + exit 0 + } + $env:DOCKER_HOST = '' + + # Method 4: Start Docker daemon in WSL2 Ubuntu and expose it on TCP 2375. + # GitHub-hosted Windows runners include WSL2 with an Ubuntu distribution. + # WSL2 port-forwarding makes tcp://localhost:2375 accessible from Windows. + Write-Host "Trying Docker daemon via WSL2..." + # WSL --list --quiet outputs UTF-16 with embedded null bytes; strip them. + $wslDistros = (wsl --list --quiet 2>&1) | + ForEach-Object { ($_ -replace '\x00', '').Trim() } | + Where-Object { $_ -match '\S' } + Write-Host "WSL2 distributions: $($wslDistros -join ', ')" + $ubuntuDistro = $wslDistros | Where-Object { $_ -match '^Ubuntu' } | Select-Object -First 1 + if ($ubuntuDistro) { + $distroName = $ubuntuDistro.Trim() + Write-Host "Preparing Docker daemon in WSL2 ($distroName)..." + # Install dockerd inside WSL2 if not already present + $installOut = wsl -d $distroName -- bash -c "command -v dockerd >/dev/null 2>&1 || (export DEBIAN_FRONTEND=noninteractive && sudo apt-get update -q && sudo apt-get install -y -q docker.io 2>&1)" + if ($LASTEXITCODE -ne 0) { Write-Host "docker.io install output: $installOut" } + # Launch dockerd as an independent background process so it outlives this step. + # Bind to 127.0.0.1 only; WSL2 port-forwarding exposes this as localhost on Windows. + # Start-Process creates a child process that survives the current pwsh instance. + Write-Host "Starting dockerd in WSL2 ($distroName) on tcp://127.0.0.1:2375..." + Start-Process wsl -ArgumentList "-d", $distroName, "--", "sudo", "dockerd", "-H", "tcp://127.0.0.1:2375" -WindowStyle Hidden + # Poll until dockerd is ready (up to 60 s) + $env:DOCKER_HOST = 'tcp://localhost:2375' + $osType = '' + for ($i = 1; $i -le 12; $i++) { + Start-Sleep -Seconds 5 + $dockerInfoOut = (docker info --format '{{.OSType}}' 2>&1) + $osType = $dockerInfoOut -replace '\s', '' + if ($osType -eq 'linux') { break } + Write-Host "Waiting for WSL2 dockerd... ($($i * 5)s elapsed); docker info: $dockerInfoOut" + } + Write-Host "Docker OS type via WSL2 daemon: $osType" + if ($osType -eq 'linux') { + Write-Host "Connected to Linux Docker daemon via WSL2." + "DOCKER_HOST=tcp://localhost:2375" | Out-File -FilePath $env:GITHUB_ENV -Append + exit 0 + } + } + + Write-Host "::error::Unable to switch Docker to Linux containers mode on this runner." + Write-Host "::error::Tried: DockerCli.exe, docker context desktop-linux, npipe docker_engine_linux, WSL2 dockerd." + exit 1 + + - name: Report Docker version on ${{ matrix.os }} + if: github.event_name != 'release' + shell: bash + run: | + echo "::group::Docker version" + docker --version + docker version + echo "::endgroup::" + + - name: Testing release with FirebirdSQL version ${{ matrix.target }} triggered by version '${{ github.event.release.tag_name }}' + if: github.event_name == 'release' && matrix.os == 'ubuntu-latest' + uses: juarezr/firebirdsql-github-action@master with: version: '${{ matrix.target }}' firebird_database: 'my_database.fdb' firebird_user: 'my_user' firebird_password: 'my_password' - - name: Testing release with FirebirdSQL version ${{ matrix.target }} triggered by version '${{ github.event.release.tag_name }}' - if: github.event_name == 'release' - uses: juarezr/firebirdsql-github-action@master + # On ubuntu-latest the action runs via Docker (uses: ./); for other OSes run entrypoint.sh directly + - name: Testing changes with FirebirdSQL version ${{ matrix.target }} on ubuntu-latest + if: github.event_name != 'release' && matrix.os == 'ubuntu-latest' + uses: ./ # Uses an action in the root directory with: version: '${{ matrix.target }}' firebird_database: 'my_database.fdb' firebird_user: 'my_user' firebird_password: 'my_password' + firebird_conf: 'ConnectionTimeout=180,DeadlockTimeout=10' + + - name: Testing changes with FirebirdSQL version ${{ matrix.target }} on ${{ matrix.os }} + if: github.event_name != 'release' && matrix.os != 'ubuntu-latest' + shell: bash + env: + INPUT_CONTAINER_NAME: 'firebirdsql' + INPUT_VERSION: '${{ matrix.target }}' + INPUT_PORT: '3050' + INPUT_FIREBIRD_DATABASE: 'my_database.fdb' + INPUT_FIREBIRD_USER: 'my_user' + INPUT_FIREBIRD_PASSWORD: 'my_password' + INPUT_FIREBIRD_CONF: 'ConnectionTimeout=180,DeadlockTimeout=10' + run: bash entrypoint.sh - - name: Install FirebirdSQL clients + # Install Python driver (pure-Python, no native Firebird client library required) + - name: Install Python firebird driver + shell: bash run: | - sudo apt-get update + python3 -m pip install --upgrade pip + python3 -m pip install firebirdsql + + - name: Install FirebirdSQL client tools on ubuntu-latest + if: matrix.os == 'ubuntu-latest' + shell: bash + run: | + sudo apt-get update -qq sudo apt-get install -y --no-install-recommends firebird3.0-utils libfbclient2 - - name: Testing Connection and Query to ${{ matrix.target }} + # Ubuntu: wait using netcat (available by default), then run isql-fb from the host + - name: Wait for Firebird ${{ matrix.target }} to accept connections (ubuntu-latest) + if: matrix.os == 'ubuntu-latest' + shell: bash + run: | + for i in {0..120}; do nc -z localhost 3050 && echo "Up after ${i}s" && break; sleep 1; done + + - name: Test connection with isql-fb on ubuntu-latest + if: matrix.os == 'ubuntu-latest' + shell: bash run: | - for i in {0..120} ; do nc -z localhost 3050 && echo "Up: ${i} secs" && break; sleep 1; done - echo 'select * from rdb$database;' | isql-fb -bail -quiet -z -user my_user -password my_password 'localhost:/var/lib/firebird/data/my_database.fdb' + echo 'SELECT * FROM rdb$roles;' | isql-fb -bail -quiet -z -user my_user -password my_password 'localhost:/var/lib/firebird/data/my_database.fdb' + + # All platforms: use the pure-Python test_connection.py (includes wait + retry logic) + # MSYS_NO_PATHCONV=1 prevents Git Bash on Windows from converting the Linux-style + # server-side database path (/var/lib/...) to a Windows path before passing to Python. + - name: Test connection and query with Python on ${{ matrix.os }} + shell: bash + env: + MSYS_NO_PATHCONV: '1' + run: | + python3 test_connection.py \ + --host localhost \ + --user my_user \ + --password my_password \ + --wait 120 \ + --retries 5 \ + /var/lib/firebird/data/my_database.fdb - name: Stop Container + if: always() + shell: bash run: | - docker rm --volumes --force firebirdsql + docker rm --volumes --force firebirdsql || true ci-volumes: name: ci-testing_volumes strategy: + fail-fast: false matrix: target: [latest, 5, 4, 3] os: [ "ubuntu-latest" ] @@ -119,7 +308,7 @@ jobs: steps: - name: Checkout source code on event ${{ github.event_name }} triggered by '${{ github.sha }}' if: github.event_name != 'release' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Create host data directory for volume mount run: | @@ -146,22 +335,26 @@ jobs: firebird_password: 'my_password' volumes: '/tmp/firebird-data:/var/lib/firebird/data' - - name: Install FirebirdSQL clients + - name: Install FirebirdSQL client tools run: | - sudo apt-get update + sudo apt-get update -qq sudo apt-get install -y --no-install-recommends firebird3.0-utils libfbclient2 - - name: Testing Connection and Query to ${{ matrix.target }} with mapped volume + - name: Wait for Firebird ${{ matrix.target }} to accept connections + run: | + for i in {0..120}; do nc -z localhost 3050 && echo "Up after ${i}s" && break; sleep 1; done + + - name: Test connection with isql-fb and mapped volume run: | - for i in {0..120} ; do nc -z localhost 3050 && echo "Up: ${i} secs" && break; sleep 1; done - echo 'select * from rdb$database;' | isql-fb -bail -quiet -z -user my_user -password my_password 'localhost:/var/lib/firebird/data/my_database.fdb' + echo 'SELECT * FROM rdb$roles;' | isql-fb -bail -quiet -z -user my_user -password my_password 'localhost:/var/lib/firebird/data/my_database.fdb' - name: Verify database file exists on host volume run: | test -f /tmp/firebird-data/my_database.fdb && echo "Database file found on host volume." || (echo "Database file NOT found on host volume!" && exit 1) - name: Stop Container + if: always() run: | - docker rm --volumes --force firebirdsql + docker rm --volumes --force firebirdsql || true # end of file diff --git a/entrypoint.sh b/entrypoint.sh index 3931e52..14aaf76 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -84,10 +84,10 @@ if [ -n "${INPUT_EVENT_PORT:-}" ]; then event_port_arg="--publish ${INPUT_EVENT_PORT}:${INPUT_EVENT_PORT}" fi -echo "# Creating the FirebirdSQL Container: docker run --detach --name ${INPUT_CONTAINER_NAME:-firebirdsql} --publish ${INPUT_PORT:-3050}:3050 ${env_list} ${event_port_arg} ${volumes_arg} firebirdsql/firebird:${INPUT_VERSION:-latest}" +echo "# Creating the FirebirdSQL Container: docker run --detach --platform linux/amd64 --name ${INPUT_CONTAINER_NAME:-firebirdsql} --publish ${INPUT_PORT:-3050}:3050 ${env_list} ${event_port_arg} ${volumes_arg} firebirdsql/firebird:${INPUT_VERSION:-latest}" # shellcheck disable=SC2086 -if ! docker run --detach --name "${INPUT_CONTAINER_NAME:-firebirdsql}" --publish "${INPUT_PORT:-3050}:3050" ${network_arg} ${env_list} ${event_port_arg} ${volumes_arg} "firebirdsql/firebird:${INPUT_VERSION:-latest}" ; then +if ! docker run --detach --platform linux/amd64 --name "${INPUT_CONTAINER_NAME:-firebirdsql}" --publish "${INPUT_PORT:-3050}:3050" ${network_arg} ${env_list} ${event_port_arg} ${volumes_arg} "firebirdsql/firebird:${INPUT_VERSION:-latest}" ; then echo "## Failed to create the FirebirdSQL container! ##" exit 11 fi diff --git a/test_connection.py b/test_connection.py new file mode 100644 index 0000000..0dc0cd6 --- /dev/null +++ b/test_connection.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +# coding: utf-8 +"""Test connection to a Firebird database using a pure-Python driver. + +Uses the `firebirdsql` package which implements the Firebird wire protocol +directly, so no native Firebird client library is required on the runner. +Works on Linux, macOS (ARM64 and x86_64), and Windows. +""" + +import argparse +import socket +import sys +import time + + +def wait_for_port(host: str, port: int, timeout: int = 120) -> bool: + """Wait until a TCP port is accepting connections.""" + start = time.monotonic() + interval = 1 + while time.monotonic() - start < timeout: + try: + with socket.create_connection((host, port), timeout=1): + elapsed = int(time.monotonic() - start) + print(f"Port {port} on {host} is open after {elapsed}s") + return True + except (ConnectionRefusedError, TimeoutError, OSError): + time.sleep(interval) + return False + + +def test_firebird_connection( + host: str, + database: str, + user: str, + password: str, + retries: int = 5, +) -> bool: + """Connect to Firebird and run a test query, retrying on failure.""" + try: + import firebirdsql # type: ignore[import] + except ImportError: + print("ERROR: 'firebirdsql' package is not installed. Run: pip install firebirdsql", file=sys.stderr) + return False + + last_error: Exception | None = None + for attempt in range(retries): + try: + con = firebirdsql.connect( + host=host, + database=database, + user=user, + password=password, + ) + try: + cur = con.cursor() + cur.execute("SELECT rdb$role_name FROM rdb$roles") + rows = cur.fetchall() + print(f"Connected to {host}:{database}") + print(f"Query returned {len(rows)} row(s) from rdb$roles:") + for row in rows: + print(f" {row[0]}") + return True + finally: + con.close() + except Exception as exc: + last_error = exc + if attempt < retries - 1: + print(f"Attempt {attempt + 1}/{retries} failed: {exc} — retrying in 5s…") + time.sleep(5) + + print(f"All {retries} connection attempts failed. Last error: {last_error}", file=sys.stderr) + return False + + +def main() -> int: + parser = argparse.ArgumentParser(description="Test Firebird database connectivity") + parser.add_argument("database", help="Server-side database path, e.g. /var/lib/firebird/data/my.fdb") + parser.add_argument("--host", default="localhost", help="Firebird host (default: localhost)") + parser.add_argument("--user", default="sysdba", help="Database user (default: sysdba)") + parser.add_argument("--password", default="masterkey", help="Database password") + parser.add_argument("--port", type=int, default=3050, help="Firebird port (default: 3050)") + parser.add_argument("--wait", type=int, default=120, metavar="SECS", + help="Seconds to wait for the port to open (default: 120)") + parser.add_argument("--retries", type=int, default=5, + help="Connection attempts before giving up (default: 5)") + args = parser.parse_args() + + print(f"Waiting up to {args.wait}s for Firebird on {args.host}:{args.port}…") + if not wait_for_port(args.host, args.port, timeout=args.wait): + print(f"Timed out waiting for Firebird on {args.host}:{args.port}", file=sys.stderr) + return 1 + + if not test_firebird_connection( + host=args.host, + database=args.database, + user=args.user, + password=args.password, + retries=args.retries, + ): + return 1 + + print("Connection test PASSED āœ“") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/testing.sh b/testing.sh index ba6e935..07ee339 100755 --- a/testing.sh +++ b/testing.sh @@ -65,13 +65,13 @@ for INPUT_VERSION in latest 5 5.0.2 5-noble 5-jammy 4 4.0.5 3 3.0.12; do msg "Querying the FirebirdSQL server inside the docker container at [${IP_ADDRESS}]..." # shellcheck disable=SC2016 - if ! echo 'SELECT * FROM rdb$database;' | + if ! echo 'SELECT * FROM rdb$roles;' | docker run -i --rm --name "${INPUT_CONTAINER_NAME}-client2" \ --network "${INPUT_NETWORK_NAME}" --env IP_ADDRESS="${IP_ADDRESS}" \ "firebirdsql/firebird:${INPUT_VERSION:-}" \ - sh -c isql -bail -quiet -echo -merge -m2 -z \ + sh -c isql -bail -quiet -z \ -user "${INPUT_FIREBIRD_USER}" -password "${INPUT_FIREBIRD_PASSWORD}" \ - "${IP_ADDRESS}:${FIREBIRD_DATA}/${INPUT_FIREBIRD_DATABASE}" | ident; + "${IP_ADDRESS}:${FIREBIRD_DATA}/${INPUT_FIREBIRD_DATABASE}" | ident; then hr; remove_it; remove_net fail "error connecting with version: ${INPUT_VERSION:-}"; @@ -114,11 +114,11 @@ for INPUT_VERSION in latest 5 4 3; do msg "Querying the FirebirdSQL server (with volume) inside the docker container at [${IP_ADDRESS}]..." # shellcheck disable=SC2016 - if ! echo 'SELECT * FROM rdb$database;' | + if ! echo 'SELECT * FROM rdb$roles;' | docker run -i --rm --name "${INPUT_CONTAINER_NAME}-client3" \ --network "${INPUT_NETWORK_NAME}" --env IP_ADDRESS="${IP_ADDRESS}" \ "firebirdsql/firebird:${INPUT_VERSION:-}" \ - sh -c isql -bail -quiet -echo -merge -m2 -z \ + sh -c isql -bail -quiet -z \ -user "${INPUT_FIREBIRD_USER}" -password "${INPUT_FIREBIRD_PASSWORD}" \ "${IP_ADDRESS}:${VOLUME_CONTAINER_DIR}/${INPUT_FIREBIRD_DATABASE}" | ident; then