stoplightio / prism

Turn any OpenAPI2/3 and Postman Collection file into an API server with mocking, transformations and validations.
https://stoplight.io/open-source/prism
Apache License 2.0
4.25k stars 345 forks source link

How to run and maintain Prism mock server on Azure Devops pipeline (Linux agents) with powershell #2540

Closed MaciejReszotnik closed 3 months ago

MaciejReszotnik commented 3 months ago

Hello everyone.

This post is asking for advice rather than reporting any particular issue with prism.

My problem is specifically that I cannot reliably start a mock server in a step and keep it alive for the following steps. Either the server shuts down or the step never completes.

For a couple of days I have been struggling with running prism on Azure pipelines. I have developed a simple powershell script which reads contents of CSV file, which contains Port and Path columns. Then I create a number of prism mock servers for later use. Here's the script

foreach($pathAndPortPair in $pathsPortsDictionary.GetEnumerator()) {

  $key = $pathAndPortPair.Name
  $value = $pathAndPortPair.Value
  if (-Not $value.Contains($rootFolder)) {
    $value = Join-Path $rootFolder $value
  }

  if($IsWindows) {
    start-process pwsh.exe -ArgumentList "-noexit -command prism mock -d -p $key $value"
  }

  if($IsLinux) {
    ...
  }
}

where $ key is port and $value is path to api spec. It all works peachy on my Windows machine. But when I try to run the script on Azure pipeline I encounter a number of issues.

I tried the following commands to start the server:

  1. Start-Process -FilePath "npx" -ArgumentList "prism mock -d -p $key $value - doesn't work, npm error is displayed.

  2. Invoke-Expression "/bin/bash prism mock -d -p $key $value - doesn't work, bash scripting error: /usr/local/bin/npx: npx: line 3: syntax error near unexpected token(' /usr/local/bin/npx: npx: line 3: const cli = require('../lib/cli.js')

  3. Start-Job -ScriptBlock { prism mock -d -p $key $value } - the Jobs start... but then shut down, presumable just after the server starts. When I run Get-Job command, the Job status is marked as Complete, and no further operations on that server yield and desired results.

  4. Start-Process -FilePath "prism" -ArgumentList "mock -d -p $key $value- this actually starts servers, but because the process runs in foreground, the step never ends in azure pipeline. I also get an error message: "The STDIO streams did not close within 10 seconds of the exit event from process '/usr/bin/pwsh'. This may indicate a child process inherited the STDIO streams and has not yet exited."

  5. start-process pwsh.exe -ArgumentList "-noexit -command prism mock -d -p $key $value" - message is displayed: An error occurred trying to start process 'pwsh.exe' with working | directory '/home/vsts/work/1/s'. No such file or directory

Does anyone have any other ideas? I am completely at a loss. How to run those servers in the background so that the pipeline steps ends, and a new step starts, but the servers are not terminated?

MaciejReszotnik commented 3 months ago

I must admit I gave up on powershell and created a simple bash script that does the job. The key thing was using nohup prefix to prevent the process from being terminated once the step on Azure pipeline was complete. I also redirected outputs into null and set the process into background.

If there is a similar way to do this in powershell, I have no idea how to do it.

Anyway, I will share it here so that other people may benefit:

    #!/bin/bash
    # Get root folder of git repo
    rootFolder=$(git rev-parse --show-toplevel)

    # Set path to csv file and read it
    echo "Top-level directory: $rootFolder"
    fullPath="$rootFolder/testFiles/csvs/test_csv.csv"
    csv_file=$(cat $fullPath)

    # Initialize an empty associative array (dictionary)
    declare -A port_path_dict

    # Split the CSV file into lines
    lines=($csv_file)

    # Skip the header line
    for ((i=1; i<${#lines[@]}; i++)); do
        # Split each line into port and path
        line="${lines[$i]}"
        IFS=',' read -r port path <<< "$line"
        # Remove quotes from port and path
        port="${port//\"}"
        path="${path//\"}"
        # Add to the dictionary
        port_path_dict["$port"]="$path"
    done

    # Iterate over values in the dictionary and start servers
    for port in "${!port_path_dict[@]}"; do
        path=${port_path_dict[$port]}
        # Run mock server but disable terminating it after terminal is closed
        nohup $(npx prism mock -d -p $port ${port_path_dict[$port]}) >/dev/null 2>&1 &
    done

Anyway, I think this issue can be closed.