diff --git a/.github/workflows/npm-test.yml b/.github/workflows/npm-test.yml
new file mode 100644
index 0000000..e62b885
--- /dev/null
+++ b/.github/workflows/npm-test.yml
@@ -0,0 +1,16 @@
+name: 'npm test'
+on:
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v6
+ - name: Setup Node.js environment
+ uses: actions/setup-node@v6
+ with:
+ node-version: 24
+ - run: npm ci
+ - run: npm test
\ No newline at end of file
diff --git a/.github/workflows/stackql-exec-test.yml b/.github/workflows/stackql-exec-test.yml
new file mode 100644
index 0000000..b71cb4c
--- /dev/null
+++ b/.github/workflows/stackql-exec-test.yml
@@ -0,0 +1,383 @@
+name: 'stackql-exec tests'
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+jobs:
+ unit-tests:
+ strategy:
+ fail-fast: false
+ matrix:
+ target:
+ - { os: ubuntu-24.04, arch: x64 }
+ - { os: ubuntu-24.04-arm, arch: arm64 }
+ - { os: windows-2025, arch: x64 }
+ - { os: windows-11-arm, arch: arm64 }
+ - { os: macos-15-intel, arch: x64 }
+ - { os: macos-15, arch: arm64 }
+ runs-on: ${{ matrix.target.os }}
+ steps:
+ - uses: actions/checkout@v6
+ - uses: actions/setup-node@v6
+ with:
+ node-version: '24'
+ architecture: ${{ matrix.target.arch }}
+ - name: Verify native Node architecture
+ env:
+ EXPECTED_ARCH: ${{ matrix.target.arch }}
+ run: node -e "const assert = require('assert/strict'); assert.equal(process.arch, process.env.EXPECTED_ARCH); assert.equal(process.env.RUNNER_ARCH.toLowerCase(), process.env.EXPECTED_ARCH);"
+ - run: npm ci --ignore-scripts
+ - run: npm test -- --runInBand
+
+ smoke-tests:
+ name: Smoke (${{ matrix.target.os }}, ${{ matrix.install }})
+ runs-on: ${{ matrix.target.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ target:
+ - { os: ubuntu-24.04, arch: X64 }
+ - { os: ubuntu-24.04-arm, arch: ARM64 }
+ - { os: windows-2025, arch: X64 }
+ - { os: windows-11-arm, arch: ARM64 }
+ - { os: macos-15-intel, arch: X64 }
+ - { os: macos-15, arch: ARM64 }
+ install: [automatic, wrapped, plain]
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Verify runner and clean installation
+ env:
+ EXPECTED_ARCH: ${{ matrix.target.arch }}
+ run: |
+ test "$RUNNER_ARCH" = "$EXPECTED_ARCH"
+ if command -v stackql; then
+ echo 'Expected a runner without StackQL installed'
+ exit 1
+ fi
+
+ - name: Preinstall StackQL
+ if: matrix.install != 'automatic'
+ uses: stackql/setup-stackql@v2
+ with:
+ use_wrapper: ${{ matrix.install == 'wrapped' }}
+
+ - name: Exercise a Windows wrapper path containing spaces
+ if: runner.os == 'Windows' && matrix.install == 'wrapped'
+ uses: actions/github-script@v8
+ with:
+ script: |
+ const fs = require('fs');
+ const path = require('path');
+ const target = path.join(process.env.RUNNER_TEMP, 'StackQL Tools');
+ fs.mkdirSync(target);
+ for (const name of ['stackql', 'stackql-bin.exe']) {
+ fs.copyFileSync(path.join(process.env.STACKQL_CLI_PATH, name), path.join(target, name));
+ }
+ core.exportVariable('STACKQL_CLI_PATH', target);
+ core.addPath(target);
+
+ - name: Execute a multiline query
+ id: inline
+ uses: ./
+ with:
+ query: |
+ SELECT
+ 'stackql smoke' AS result;
+
+ - name: Verify installation mode
+ env:
+ INSTALL_MODE: ${{ matrix.install }}
+ run: |
+ if [[ "$RUNNER_OS" == 'macOS' || "$INSTALL_MODE" == 'plain' ]]; then
+ test -z "${STACKQL_CLI_PATH:-}"
+ else
+ test -n "${STACKQL_CLI_PATH:-}"
+ fi
+
+ - name: Verify native Windows binary architecture
+ if: runner.os == 'Windows'
+ shell: pwsh
+ run: |
+ $binary = if ($env:STACKQL_CLI_PATH) {
+ Join-Path $env:STACKQL_CLI_PATH 'stackql-bin.exe'
+ } else {
+ (Get-Command stackql.exe).Source
+ }
+ $bytes = [IO.File]::ReadAllBytes($binary)
+ $pe = [BitConverter]::ToInt32($bytes, 0x3c)
+ $machine = [BitConverter]::ToUInt16($bytes, $pe + 4)
+ $expected = if ($env:RUNNER_ARCH -eq 'ARM64') { 0xaa64 } else { 0x8664 }
+ if ($machine -ne $expected) { throw 'Installed binary does not match runner architecture' }
+
+ - name: Verify native Linux or macOS binary architecture
+ if: runner.os != 'Windows'
+ run: |
+ binary="$(command -v stackql)"
+ if [[ -n "${STACKQL_CLI_PATH:-}" ]]; then
+ binary="$STACKQL_CLI_PATH/stackql-bin"
+ fi
+ if [[ "$RUNNER_OS" == 'macOS' ]]; then
+ arch=x86_64
+ if [[ "$RUNNER_ARCH" == 'ARM64' ]]; then arch=arm64; fi
+ lipo "$binary" -verify_arch "$arch"
+ else
+ arch='x86-64'
+ if [[ "$RUNNER_ARCH" == 'ARM64' ]]; then arch='ARM aarch64'; fi
+ file "$binary" | grep -E "ELF 64-bit.*$arch"
+ fi
+
+ - name: Create query and data files in a path containing spaces
+ id: fixtures
+ uses: actions/github-script@v8
+ with:
+ script: |
+ const fs = require('fs');
+ const path = require('path');
+ const dir = path.join(process.env.RUNNER_TEMP, 'StackQL queries');
+ fs.mkdirSync(dir);
+ const query = path.join(dir, 'query file.iql');
+ const data = path.join(dir, 'query data.jsonnet');
+ fs.writeFileSync(query, "SELECT '{{ .value }}' AS result;");
+ fs.writeFileSync(data, '{value: std.extVar("VALUE")}');
+ core.setOutput('query', query);
+ core.setOutput('data', data);
+
+ - name: Execute a query file with data and variables
+ id: file
+ uses: ./
+ with:
+ query_file_path: ${{ steps.fixtures.outputs.query }}
+ data_file_path: ${{ steps.fixtures.outputs.data }}
+ vars: VALUE=stackql smoke
+
+ - name: Dry run a query file with data and variables
+ id: dryrun
+ uses: ./
+ with:
+ query_file_path: ${{ steps.fixtures.outputs.query }}
+ data_file_path: ${{ steps.fixtures.outputs.data }}
+ vars: VALUE=stackql smoke
+ dry_run: true
+
+ - name: Execute a CSV query
+ id: csv
+ uses: ./
+ with:
+ query: SELECT 'stackql smoke' AS result;
+ query_output: csv
+
+ - name: Execute a table query
+ id: table
+ uses: ./
+ with:
+ query: SELECT 'stackql smoke' AS result;
+ query_output: table
+
+ - name: Execute a text query
+ id: text
+ uses: ./
+ with:
+ query: SELECT 'stackql smoke' AS result;
+ query_output: text
+
+ - name: Assert action outputs
+ uses: actions/github-script@v8
+ env:
+ RESULTS: ${{ toJSON(steps) }}
+ with:
+ script: |
+ const assert = require('assert/strict');
+ const steps = JSON.parse(process.env.RESULTS);
+ const output = id => steps[id].outputs['stackql-query-results'];
+ for (const id of ['inline', 'file', 'dryrun', 'csv', 'table', 'text']) {
+ assert.ok(output(id), `${id} returned no results`);
+ assert.ok(!steps[id].outputs['stackql-query-error'], `${id} returned an error`);
+ }
+ for (const id of ['inline', 'file']) {
+ const rows = JSON.parse(output(id));
+ assert.equal(rows.length, 1);
+ const value = rows[0].result;
+ if (value !== null && typeof value === 'object') {
+ assert.deepEqual(value, {String: 'stackql smoke', Valid: true});
+ } else {
+ assert.equal(value, 'stackql smoke');
+ }
+ }
+ assert.deepEqual(JSON.parse(output('dryrun')), [{query: "SELECT 'stackql smoke' AS result;"}]);
+ for (const id of ['csv', 'text']) {
+ assert.equal(output(id).replace(/\r\n/g, '\n').trim(), 'result\nstackql smoke');
+ }
+ assert.match(output('table'), /\|\s*result\s*\|/);
+ assert.match(output('table'), /\|\s*stackql smoke\s*\|/);
+
+ stackql-exec-google-example:
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2025, windows-11-arm, macos-15-intel, macos-15]
+ runs-on: ${{matrix.os}}
+ name: 'StackQL exec Google '
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ #
+ # run a query that does not return data (using the `is_command` input)
+ #
+ - name: pull providers
+ id: stackql-command
+ uses: ./
+ with:
+ is_command: true
+ query: "REGISTRY PULL github;
+ REGISTRY PULL google;"
+
+ #
+ # run a query using the `query` input
+ #
+ - name: github query example using the query input
+ id: stackql-query
+ uses: ./
+ with:
+ query: |
+ select visibility, count(*) as number_of_repos
+ from github.repos.repos
+ where org = 'stackql'
+ group by visibility
+ env:
+ STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
+ STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
+
+ # `csv` output
+ - name: github query example using the query input (csv output)
+ id: stackql-query-csv-output
+ uses: ./
+ with:
+ query_output: csv
+ query: |
+ select visibility, count(*) as number_of_repos
+ from github.repos.repos
+ where org = 'stackql'
+ group by visibility
+ env:
+ STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
+ STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
+
+ # `table` output
+ - name: github query example using the query input (table output)
+ id: stackql-query-table-output
+ uses: ./
+ with:
+ query_output: table
+ query: |
+ select visibility, count(*) as number_of_repos
+ from github.repos.repos
+ where org = 'stackql'
+ group by visibility
+ env:
+ STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
+ STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
+
+ # `text` output
+ - name: github query example using the query input (text output)
+ id: stackql-query-text-output
+ uses: ./
+ with:
+ query_output: text
+ query: |
+ select visibility, count(*) as number_of_repos
+ from github.repos.repos
+ where org = 'stackql'
+ group by visibility
+ env:
+ STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
+ STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
+
+ #
+ # run a query using the `query_file_path` input
+ #
+ - name: google query example with query file
+ id: stackql-query-file
+ uses: ./
+ with:
+ query_file_path: './stackql_scripts/google-instances-by-status.iql'
+ env:
+ GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
+
+ #
+ # run a query using the `query_file_path` and `vars` inputs
+ #
+ - name: google query example with query file using vars
+ id: stackql-query-file-with-vars
+ uses: ./
+ with:
+ query_file_path: './stackql_scripts/google-instances-by-status-with-inline-jsonnet-block.iql'
+ vars: GOOGLE_PROJECT=${{ env.GOOGLE_PROJECT }},GOOGLE_ZONE=${{ env.GOOGLE_ZONE }}
+ env:
+ GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
+ GOOGLE_PROJECT: ${{ vars.GOOGLE_PROJECT }}
+ GOOGLE_ZONE: ${{ vars.GOOGLE_ZONE }}
+
+ #
+ # run a query using the `query_file_path`, `data_file_path` and `vars` inputs (dry-run)
+ #
+ - name: google query example with query file and data file using vars (dry-run)
+ id: stackql-query-file-with-data-file-and-vars-dry-run
+ uses: ./
+ with:
+ query_file_path: './stackql_scripts/google-instances-by-status-with-external-data-file.iql'
+ data_file_path: './stackql_scripts/google-instances-by-status-with-external-data-file.jsonnet'
+ vars: GOOGLE_PROJECT=${{ env.GOOGLE_PROJECT }},GOOGLE_ZONE=${{ env.GOOGLE_ZONE }}
+ dry_run: true
+ env:
+ GOOGLE_PROJECT: ${{ vars.GOOGLE_PROJECT }}
+ GOOGLE_ZONE: ${{ vars.GOOGLE_ZONE }}
+
+ #
+ # run a query using the `query_file_path`, `data_file_path` and `vars` inputs
+ #
+ - name: google query example with query file and data file using vars
+ id: stackql-query-file-with-data-file-and-vars
+ uses: ./
+ with:
+ query_file_path: './stackql_scripts/google-instances-by-status-with-external-data-file.iql'
+ data_file_path: './stackql_scripts/google-instances-by-status-with-external-data-file.jsonnet'
+ vars: GOOGLE_PROJECT=${{ env.GOOGLE_PROJECT }},GOOGLE_ZONE=${{ env.GOOGLE_ZONE }}
+ env:
+ GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
+ GOOGLE_PROJECT: ${{ vars.GOOGLE_PROJECT }}
+ GOOGLE_ZONE: ${{ vars.GOOGLE_ZONE }}
+
+ - name: validate stackql outputs
+ shell: bash
+ run: |
+ echo "stackql-command:"
+ echo "${{ steps.stackql-command.outputs.stackql-command-output }}"
+
+ echo "stackql-query:"
+ echo "${{ steps.stackql-query.outputs.stackql-query-results }}"
+
+ echo "stackql-query-csv-output:"
+ echo "${{ steps.stackql-query-csv-output.outputs.stackql-query-results }}"
+
+ echo "stackql-query-table-output:"
+ echo "${{ steps.stackql-query-table-output.outputs.stackql-query-results }}"
+
+ echo "stackql-query-text-output:"
+ echo "${{ steps.stackql-query-text-output.outputs.stackql-query-results }}"
+
+ echo "stackql-query-file:"
+ echo "${{ steps.stackql-query-file.outputs.stackql-query-results }}"
+
+ echo "stackql-query-file-with-vars:"
+ echo "${{ steps.stackql-query-file-with-vars.outputs.stackql-query-results }}"
+
+ echo "stackql-query-file-with-data-file-and-vars:"
+ echo "${{ steps.stackql-query-file-with-data-file-and-vars.outputs.stackql-query-results }}"
diff --git a/.github/workflows/stackql-exec.yml b/.github/workflows/stackql-exec.yml
deleted file mode 100644
index f86b411..0000000
--- a/.github/workflows/stackql-exec.yml
+++ /dev/null
@@ -1,106 +0,0 @@
-name: 'StackQL Exec Test'
-
-on:
- push:
- branches:
- - main
- pull_request:
-jobs:
- stackql-exec-google-example:
- strategy:
- matrix:
- os: [ubuntu-latest, windows-latest, macos-latest]
- runs-on: ${{matrix.os}}
- name: 'StackQL exec Google '
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- #
- # query no auth
- #
- - name: pull providers
- id: stackql-exec-string-noauth
- uses: ./
- with:
- query: "REGISTRY PULL github;
- REGISTRY PULL google;"
-
- #
- # authenticated query
- #
- - name: exec github example with query string
- id: stackql-exec-string
- uses: ./
- with:
- query: "select total_private_repos
- from github.orgs.orgs
- where org = 'stackql';"
- env:
- STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
- STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
-
- #
- # query_file_path
- #
- - name: exec google example with query file
- id: stackql-exec-file
- uses: ./
- with:
- query_file_path: './stackql_scripts/google-instances-by-status.iql'
- env:
- GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
-
- #
- # query_file_path with jsonnet code block using external vars
- #
- - name: exec google example with query file using vars
- id: stackql-exec-file-with-vars
- uses: ./
- with:
- query_file_path: './stackql_scripts/google-instances-by-status-with-inline-jsonnet-block.iql'
- vars: GOOGLE_PROJECT=${{ env.GOOGLE_PROJECT }},GOOGLE_ZONE=${{ env.GOOGLE_ZONE }}
- env:
- GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
- GOOGLE_PROJECT: ${{ vars.GOOGLE_PROJECT }}
- GOOGLE_ZONE: ${{ vars.GOOGLE_ZONE }}
-
- #
- # query_file_path with jsonnet data file using external vars
- #
- - name: exec google example with query file and data file using vars
- id: stackql-exec-file-with-data-file-and-vars
- uses: ./
- with:
- query_file_path: './stackql_scripts/google-instances-by-status-with-external-data-file.iql'
- data_file_path: './stackql_scripts/google-instances-by-status-with-external-data-file.jsonnet'
- vars: GOOGLE_PROJECT=${{ env.GOOGLE_PROJECT }},GOOGLE_ZONE=${{ env.GOOGLE_ZONE }}
- env:
- GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
- GOOGLE_PROJECT: ${{ vars.GOOGLE_PROJECT }}
- GOOGLE_ZONE: ${{ vars.GOOGLE_ZONE }}
-
- - name: validate stackql-exec output
- shell: bash
- run: |
- if [ -z '${{ steps.stackql-exec-string-noauth.outputs.exec-result }}' ]; then
- echo "exec-stackql output does not contain expected result"
- exit 1
- fi
- if [ -z '${{ steps.stackql-exec-string.outputs.exec-result }}' ]; then
- echo "exec-stackql output does not contain expected result"
- exit 1
- fi
- if [ -z '${{ steps.stackql-exec-file.outputs.exec-result }}' ]; then
- echo "exec-stackql output does not contain expected result"
- exit 1
- fi
- if [ -z '${{ steps.stackql-exec-file-with-vars.outputs.exec-result }}' ]; then
- echo "exec-stackql output does not contain expected result"
- exit 1
- fi
- if [ -z '${{ steps.stackql-exec-file-with-data-file-and-vars.outputs.exec-result }}' ]; then
- echo "exec-stackql output does not contain expected result"
- exit 1
- fi
\ No newline at end of file
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index 74d2cab..0000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: 'Build and Test'
-on:
- pull_request:
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v3
- - name: Use Node.js 16
- uses: actions/setup-node@v3
- with:
- node-version: 16.x
- - run: npm ci
- - run: npm test
-
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..3c1ab27
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,41 @@
+# Contributing
+
+Before contributing, read [README.md](./README.md) for project scope.
+
+## Setup
+
+1. Fork and clone the repository, then create a branch for your change.
+2. Install Node.js 24, matching CI.
+3. From the repository root, install dependencies and run the unit tests:
+
+ ```sh
+ npm ci --ignore-scripts
+ npm test -- --runInBand
+ ```
+
+The unit tests use Jest and mock StackQL execution. They do not require a StackQL installation or cloud credentials.
+
+## Project layout
+
+- [action.yml](./action.yml): composite action inputs, outputs, and steps.
+- [lib/utils.js](./lib/utils.js): authentication setup, command construction, and execution.
+- [lib/tests](./lib/tests): unit tests, including platform-specific behavior.
+- [stackql_scripts](./stackql_scripts): query and data files used by provider integration tests.
+
+## CI tests
+
+The [test workflow](./.github/workflows/stackql-exec-test.yml) runs unit tests and smoke tests on Linux, Windows, and macOS, for both x64 and ARM64. Smoke tests require no cloud credentials and cover automatic setup, preinstalled wrapped binaries, and preinstalled plain binaries. On macOS, setup uses Homebrew without a wrapper.
+
+Provider integration tests additionally require the `STACKQL_GITHUB_USERNAME`, `STACKQL_GITHUB_PASSWORD`, and `GOOGLE_CREDENTIALS` repository secrets, plus the `GOOGLE_PROJECT` and `GOOGLE_ZONE` repository variables. Repository secrets are unavailable to [pull request workflows from forks](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#workflows-in-forked-repositories), so provider tests may fail there because credentials are missing.
+
+## Pull requests
+
+- Keep changes focused on one feature or fix.
+- Include tests with functional changes, including platform-specific cases where relevant.
+- Update [README.md](./README.md) when changing inputs, outputs, usage, or supported platforms.
+- Describe the change and the tests run, including any CI failures caused by unavailable credentials.
+- Preserve input validation and authentication isolation between action invocations.
+
+## Security reports
+
+Follow [SECURITY.md](./SECURITY.md) to report suspected vulnerabilities privately. Do not include credentials in issues, pull requests, or test fixtures.
diff --git a/LICENSE b/LICENSE
index a57858b..aa75be6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2023 StackQL Studios
+Copyright (c) 2026 StackQL Studios
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 6606fb8..12503b9 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,22 @@
+[stars]: https://img.shields.io/github/stars/stackql/stackql?style=flat-square "GitHub Stars"
+[logo]: https://stackql.io/img/stackql-logo-bold.png "stackql logo"
+[stackql]: https://github.com/stackql/stackql
+[homepage]: https://stackql.io/
+[downloads]: https://img.shields.io/github/downloads/stackql/stackql/total?label=github%20downloads
+
+
+
+[![logo]][homepage]
+
+[](https://github.com/marketplace/actions/stackql-exec)
+[](https://github.com/stackql/stackql-exec/releases)
+[](https://github.com/stackql/stackql-exec/actions/workflows/stackql-exec-test.yml)
+[](LICENSE)
+![downloads]
+[![stars]][stackql]
+
+
+
# stackql-exec
Github Action as a wrapper for executing a single command in stackql, maps all stackql exec args to actions args
@@ -6,25 +25,75 @@ Github Action as a wrapper for executing a single command in stackql, maps all s
## Provider Authentication
Authentication to StackQL providers is done via environment variables source from GitHub Actions Secrets. To learn more about authentication, see the setup instructions for your provider or providers at the [StackQL Provider Registry Docs](https://stackql.io/registry).
-# Examples
-## Query Example
-```
+## Inputs
+- **`query`** - stackql query to execute *(need to supply either __`query`__ or __`query_file_path`__)*
+- **`query_file_path`** - stackql query file to execute *(need to supply either __`query`__ or __`query_file_path`__)*
+- **`data_file_path`** - (optional) path to data file to pass to the stackql query preprocessor (`json` or `jsonnet`)
+- **`dry_run`** - (optional) set to `true` to print the query that would be executed without actually executing it (default is `false`)
+- **`vars`** - (optional) comma delimited list of variables to pass to the stackql query preprocessor (supported with `jsonnet` config blocks or `jsonnet` data files only), accepts `var1=val1,var2=val2`, can be used to source environment variables into stackql queries
+- **`query_output`** - (optional) output format of the stackql exec result, accepts `table`, `csv`, `json` and `text`, defaults to `json`
+- **`auth_obj_path`** - (optional) the path of json file that stores stackql AUTH string *(only required when using non-standard environment variable names)*
+- **`auth_str`** - (optional) stackql AUTH string *(only required when using non-standard environment variable names)*
+- **`is_command`** - (optional) set to `true` if the stackql execution is a command that does not return data (defaults to `false`)
+- **`on_failure`** - (optional) behavior on a failure in query, supported values are `exit` (default) and `continue`
+
+## Outputs
+
+- **`stackql-query-results`** - results from a stackql query (in the format specified)
+- **`stackql-command-output`** - text output from a stackql command (a query that does not return data)
+- **`stackql-query-error`** - error from a stackql query
+
+> This action uses [setup-stackql](https://github.com/marketplace/actions/setup-stackql)
+
+Windows ARM64 runners use the native binary installed by `setup-stackql`. Existing plain `stackql.exe` installations on `PATH` and wrapped installations are both supported.
+
+## Supported platforms
+
+| Platform | x64 runner | ARM64 runner |
+| --- | --- | --- |
+| Linux | `ubuntu-24.04` | `ubuntu-24.04-arm` |
+| Windows | `windows-2025` | `windows-11-arm` |
+| macOS | `macos-15-intel` | `macos-15` |
+
+CI runs unit tests and integration tests on all six combinations. Smoke tests need no cloud credentials and cover automatic setup, preinstalled wrapped binaries, and preinstalled plain binaries. On macOS, `setup-stackql` uses Homebrew and does not install a wrapper.
+
+Smoke tests verify the native binary architecture, multiline queries, query and data paths containing spaces, variables, dry runs, and all four output formats. Provider integration tests additionally use the repository's GitHub and Google credentials.
+
+## Examples
+
+### Inline `stackql` query example
+
+this is an example of a command (that does not return data):
+
+```yaml
- name: exec github example
uses: ./
with:
+ is_command: 'true'
query: "REGISTRY PULL github;
- SHOW PROVIDERS;
- select total_private_repos
- from github.orgs.orgs
- where org = 'stackql';"
env:
STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
```
+this is an example of a query that returns data:
-## Query File example
-- `google-example.iql`
+```yaml
+ - name: exec github example
+ uses: ./
+ with:
+ query: |
+ select total_private_repos
+ from github.orgs.orgs
+ where org = 'stackql'"
+ env:
+ STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
+ STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
+```
+
+### Query file example using an inline `jsonnet` variable block and external variables
+
+`google-example.iql`
```
<<
+ ['x64', 'arm64'].map(arch => [platform, arch]));
+const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
+const originalArch = Object.getOwnPropertyDescriptor(process, 'arch');
+const originalEnv = process.env;
+
+describe.each(platforms)('%s/%s', (platform, arch) => {
+ let core;
+ let utils;
+ let execute;
+ const executable = platform === 'win32' ? 'stackql.exe' : 'stackql';
+
+ beforeEach(() => {
+ process.env = { ...originalEnv };
+ for (const name of ['QUERY', 'QUERY_FILE_PATH', 'DATA_FILE_PATH', 'DRY_RUN', 'AUTH', 'VARS', 'STACKQL_CLI_PATH']) {
+ delete process.env[name];
+ }
+ process.env.OUTPUT = 'json';
+ Object.defineProperty(process, 'platform', { value: platform });
+ Object.defineProperty(process, 'arch', { value: arch });
+ core = Object.fromEntries(['debug', 'info', 'error', 'warning', 'setFailed', 'setOutput'].map(name => [name, jest.fn()]));
+ execute = jest.fn();
+ jest.spyOn(childProcess, 'exec')[promisify.custom] = execute;
+ jest.resetModules();
+ utils = require('../utils');
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ Object.defineProperty(process, 'platform', originalPlatform);
+ Object.defineProperty(process, 'arch', originalArch);
+ process.env = originalEnv;
+ jest.resetModules();
+ });
+
+ it.each(['json', 'csv', 'table', 'text'])('builds a multiline %s query for the platform shell', async format => {
+ process.env.QUERY = "SELECT\n 'stackql smoke' AS result;";
+ process.env.OUTPUT = format;
+ await utils.getStackqlCommand(core);
+ const query = platform === 'win32' ? "SELECT 'stackql smoke' AS result;" : process.env.QUERY;
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command', `${executable} exec "${query}" --output ${format}`);
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it('quotes query and data paths and includes variables and dry-run flags', async () => {
+ process.env.QUERY_FILE_PATH = 'queries with spaces/query.iql';
+ process.env.DATA_FILE_PATH = 'queries with spaces/data.jsonnet';
+ process.env.VARS = 'VALUE=stackql smoke';
+ process.env.DRY_RUN = 'true';
+ jest.spyOn(fs, 'existsSync').mockImplementation(file =>
+ [process.env.QUERY_FILE_PATH, process.env.DATA_FILE_PATH].includes(file));
+ jest.resetModules();
+ await require('../utils').getStackqlCommand(core);
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command',
+ `${executable} exec -i "queries with spaces/query.iql" --iqldata "queries with spaces/data.jsonnet" --output json --dryrun --var "VALUE=stackql smoke"`);
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ if (platform !== 'win32') {
+ it('uses PATH for both plain and wrapped Unix installations', async () => {
+ process.env.STACKQL_CLI_PATH = '/tmp/StackQL Tools';
+ process.env.QUERY = 'SELECT 1';
+ await utils.getStackqlCommand(core);
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command', 'stackql exec "SELECT 1" --output json');
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+ }
+
+ it.each(['json', 'csv', 'table', 'text'])('preserves raw %s query output', async format => {
+ const outputs = {
+ json: '[{"result":"stackql smoke"}]',
+ csv: 'result\nstackql smoke\n',
+ table: '| result |\n| stackql smoke |\n',
+ text: 'result\nstackql smoke\n',
+ };
+ execute.mockResolvedValue({ stdout: outputs[format], stderr: '' });
+ await utils.execStackQLQuery(core, 'test command', false, 'exit', false);
+ expect(execute).toHaveBeenCalledWith('test command');
+ expect(core.setOutput).toHaveBeenCalledWith('stackql-query-results', outputs[format]);
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ if (platform !== 'win32') {
+ it('extracts query output from the setup-stackql wrapper', async () => {
+ const result = '[\n{"result":"stackql smoke"}\n]';
+ execute.mockResolvedValue({
+ stdout: `[command]/tmp/stackql-bin exec query\n${result}\n::debug::stdout: ${result.replace(/\n/g, '%0A')}\n::debug::stderr: \n`,
+ stderr: '',
+ });
+ await utils.execStackQLQuery(core, 'test command', false, 'exit', false);
+ expect(core.setOutput).toHaveBeenCalledWith('stackql-query-results', result);
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it('extracts command output from the setup-stackql wrapper', async () => {
+ execute.mockResolvedValue({ stdout: '::debug::stdout: \n::debug::stderr: provider installed%0A\n', stderr: 'provider installed\n' });
+ await utils.execStackQLQuery(core, 'test command', true, 'exit', false);
+ expect(core.setOutput).toHaveBeenCalledWith('stackql-command-output', 'provider installed');
+ expect(core.setOutput).not.toHaveBeenCalledWith('stackql-query-results', expect.anything());
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+ }
+
+ it('captures native command output from stderr', async () => {
+ execute.mockResolvedValue({ stdout: '', stderr: 'provider installed\n' });
+ await utils.execStackQLQuery(core, 'test command', true, 'exit', false);
+ expect(core.setOutput).toHaveBeenCalledWith('stackql-command-output', 'provider installed\n');
+ expect(core.setOutput).not.toHaveBeenCalledWith('stackql-query-results', expect.anything());
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it('returns the rendered query during a dry run', async () => {
+ const stdout = '[{"query":"SELECT 1;"}]';
+ execute.mockResolvedValue({ stdout, stderr: '' });
+ await utils.execStackQLQuery(core, 'test command --dryrun', false, 'exit', true);
+ expect(execute).toHaveBeenCalledWith('test command --dryrun');
+ expect(core.setOutput).toHaveBeenCalledWith('stackql-query-results', stdout);
+ expect(core.info).toHaveBeenCalledWith('dry-run query:\nSELECT 1;');
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it('fails the action when the executable fails', async () => {
+ execute.mockRejectedValue(new Error('process exited with code 1'));
+ await utils.execStackQLQuery(core, 'test command', false, 'exit', false);
+ expect(core.setFailed).toHaveBeenCalledWith('stackql command failed with error: process exited with code 1');
+ expect(core.setOutput).not.toHaveBeenCalled();
+ });
+});
diff --git a/lib/tests/success-result.json b/lib/tests/success-result.json
deleted file mode 100644
index 030276f..0000000
--- a/lib/tests/success-result.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"name":"stackql-demo-001","status":"TERMINATED"}]
\ No newline at end of file
diff --git a/lib/tests/test-auth.json b/lib/tests/test-auth.json
deleted file mode 100644
index d8de066..0000000
--- a/lib/tests/test-auth.json
+++ /dev/null
@@ -1 +0,0 @@
-{ "google": { "type": "service_account", "credentialsfilepath": "sa-key.json" }}
\ No newline at end of file
diff --git a/lib/tests/utils.test.js b/lib/tests/utils.test.js
index 4f32bbc..34e96fc 100644
--- a/lib/tests/utils.test.js
+++ b/lib/tests/utils.test.js
@@ -1,70 +1,167 @@
-const { getStackqlCommand, setOutput } = require("../utils");
+const { getStackqlCommand, setupAuth } = require("../utils");
+const fs = require('fs');
-describe("util", () => {
+const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
+const originalArch = Object.getOwnPropertyDescriptor(process, 'arch');
+
+describe("Utils Functions Tests", () => {
let core;
beforeEach(() => {
+ Object.defineProperty(process, 'platform', { value: 'linux' });
+
core = {
- setFailed: jest.fn().mockImplementation((message) => {
- console.error(message);
- }),
- info: jest.fn().mockImplementation((message) => {
- console.log(message);
- }),
+ debug: jest.fn().mockImplementation((message) => console.log(`DEBUG: ${message}`)),
+ setFailed: jest.fn().mockImplementation((message) => console.error(message)),
+ info: jest.fn().mockImplementation((message) => console.log(message)),
exportVariable: jest.fn(),
- error: jest.fn().mockImplementation((message) => {
- console.error(message);
- }),
+ setOutput: jest.fn(),
+ error: jest.fn().mockImplementation((message) => console.error(message)),
};
+ jest.spyOn(core, 'setOutput').mockImplementation((name, value) => {
+ core[name] = value;
+ });
+ // set defaults for env vars
+ delete process.env.QUERY;
+ delete process.env.QUERY_FILE_PATH;
+ delete process.env.DATA_FILE_PATH;
+ delete process.env.VARS;
+ delete process.env.AUTH;
+ delete process.env.STACKQL_CLI_PATH;
+ process.env.OUTPUT = 'json';
});
- describe("getStackqlCommand", () => {
- const EXECUTE_ENV = {
- QUERY: "test",
- QUERY_FILE_PATH: "test-query.json",
- };
+ afterEach(() => {
+ jest.restoreAllMocks();
+ Object.defineProperty(process, 'platform', originalPlatform);
+ Object.defineProperty(process, 'arch', originalArch);
+ delete process.env.STACKQL_CLI_PATH;
+ });
+
+ it("should handle a stackql query", () => {
+ // Simulate setting the QUERY variable as it would be from a YAML file using Folded Block Style
+ process.env.QUERY = "SELECT status, count(*) as num_instances FROM google.compute.instances WHERE project = 'stackql-demo' GROUP BY status";
- beforeEach(() => {
- jest.resetModules();
- process.env = { ...EXECUTE_ENV };
- });
+ // Execute the function that processes the command
+ getStackqlCommand(core);
- afterEach(() => {
- process.env = EXECUTE_ENV;
- jest.clearAllMocks();
- });
+ // Prepare the expected full command
+ const expectedCommand = 'stackql exec "SELECT status, count(*) as num_instances FROM google.compute.instances WHERE project = \'stackql-demo\' GROUP BY status" --output json';
+
+ // Verify that the full command is set correctly
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command', expectedCommand);
+
+ // Optionally, check for no errors
+ expect(core.error).not.toHaveBeenCalled();
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ // Test for non-existent query file
+ it('should handle non-existent query file', () => {
+ process.env.QUERY_FILE_PATH = 'path/to/nonexistent/file.iql';
+ getStackqlCommand(core);
+ // Use RegExp for case insensitive comparison
+ expect(core.setFailed).toHaveBeenCalledWith(expect.stringMatching(new RegExp(`query file path does not exist: ${process.env.QUERY_FILE_PATH}`, 'i')));
+ expect(core.setOutput).not.toHaveBeenCalledWith('stackql_command', expect.any(String));
+ });
+
+ // Test for unsupported output formats
+ it('should handle unsupported output formats', () => {
+ process.env.OUTPUT = 'unsupported_format';
+ getStackqlCommand(core);
+ // Use RegExp for case insensitive comparison
+ expect(core.setFailed).toHaveBeenCalledWith(expect.stringMatching(new RegExp(`output format not supported: ${process.env.OUTPUT}`, 'i')));
+ expect(core.setOutput).not.toHaveBeenCalled();
+ });
- it("should return error when there is neither query or query file path", () => {
- process.env.QUERY = undefined;
- process.env.QUERY_FILE_PATH = undefined;
+ it("should handle query execution from an existing file", () => {
+ // Setup environment variables
+ process.env.QUERY_FILE_PATH = "stackql_scripts/google-instances-by-status.iql";
- getStackqlCommand(core);
+ // Execute the function
+ getStackqlCommand(core);
- expect(core.setFailed).toBeCalledWith(
- "Either query or query_file_path need to be set"
- );
+ // Prepare the expected full command
+ const expectedCommand = 'stackql exec -i "stackql_scripts/google-instances-by-status.iql" --output json';
+
+ // Verify that the command is set correctly
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command', expectedCommand);
+
+ // Optionally, check for no errors
+ expect(core.error).not.toHaveBeenCalled();
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+ it("should handle query execution from a file with a data file", () => {
+ // Setup environment variables
+ process.env.QUERY_FILE_PATH = "stackql_scripts/google-instances-by-status-with-external-data-file.iql";
+ process.env.DATA_FILE_PATH = "stackql_scripts/google-instances-by-status-with-external-data-file.jsonnet";
+
+ // Execute the function
+ getStackqlCommand(core);
+
+ // Prepare the expected full command
+ const expectedCommand = 'stackql exec -i "stackql_scripts/google-instances-by-status-with-external-data-file.iql" --iqldata "stackql_scripts/google-instances-by-status-with-external-data-file.jsonnet" --output json';
+
+ // Verify that the command is set correctly
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command', expectedCommand);
+
+ // Optionally, check for no errors
+ expect(core.error).not.toHaveBeenCalled();
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
+
+
+ describe.each(['x64', 'arm64'])('Windows %s installs', arch => {
+ beforeEach(() => {
+ Object.defineProperty(process, 'platform', { value: 'win32' });
+ Object.defineProperty(process, 'arch', { value: arch });
+ process.env.QUERY = 'SELECT 1 AS result';
});
- it("should execute stackql with query file path", () => {
- process.env.QUERY = undefined;
+ it('uses a plain installation on PATH', async () => {
+ await getStackqlCommand(core);
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command', 'stackql.exe exec "SELECT 1 AS result" --output json');
+ expect(core.setFailed).not.toHaveBeenCalled();
+ });
- getStackqlCommand(core);
+ it('quotes the wrapped binary path', async () => {
+ process.env.STACKQL_CLI_PATH = 'C:\\StackQL Tools';
+ jest.spyOn(fs, 'existsSync').mockImplementation(file => file === 'C:\\StackQL Tools\\stackql-bin.exe');
+ jest.resetModules();
+ await require('../utils').getStackqlCommand(core);
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command', '"C:\\StackQL Tools\\stackql-bin.exe" exec "SELECT 1 AS result" --output json');
+ });
- const receivedValue = core.exportVariable.mock.calls[0][1];
- expect(receivedValue).toContain("stackql exec -i test-query.json");
- expect(receivedValue).toContain("--output='json'");
- // Add further expectations here, such as vars and auth
+ it('falls back to PATH when wrapper metadata is stale', async () => {
+ process.env.STACKQL_CLI_PATH = 'C:\\missing';
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+ jest.resetModules();
+ await require('../utils').getStackqlCommand(core);
+ expect(core.setOutput).toHaveBeenCalledWith('stackql_command', 'stackql.exe exec "SELECT 1 AS result" --output json');
});
+ });
- it("should execute stackql with query", () => {
- process.env.QUERY_FILE_PATH = undefined;
+ // auth is emitted as a scoped step output, never exported to GITHUB_ENV,
+ // so it cannot carry over between steps/actions in a job.
+ describe("setupAuth", () => {
+ afterEach(() => {
+ delete process.env.AUTH_STR;
+ delete process.env.AUTH_FILE_PATH;
+ });
- getStackqlCommand(core);
+ it("emits the provided auth string as the 'auth' output", () => {
+ process.env.AUTH_STR = '{ "cloudflare": { "type": "bearer", "credentialsenvvar": "CLOUDFLARE_API_TOKEN" } }';
+ setupAuth(core);
+ expect(core.setOutput).toHaveBeenCalledWith('auth', process.env.AUTH_STR);
+ expect(core.exportVariable).not.toHaveBeenCalled();
+ });
- const receivedValue = core.exportVariable.mock.calls[0][1];
- expect(receivedValue).toContain("stackql exec \"test\"");
- expect(receivedValue).toContain("--output='json'");
- // Add further expectations here, such as vars and auth
+ it("emits an empty 'auth' output when no auth is supplied (no carry-over)", () => {
+ setupAuth(core);
+ expect(core.setOutput).toHaveBeenCalledWith('auth', '');
+ expect(core.exportVariable).not.toHaveBeenCalled();
});
});
+
});
diff --git a/lib/utils.js b/lib/utils.js
index 1f12488..646bd61 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -1,9 +1,13 @@
-const fs = require("fs");
+const { readFileSync, existsSync } = require('fs');
+const { promisify } = require('util');
+const execAsync = promisify(require('child_process').exec);
/**
* Sets up authentication by reading from either a file or a string.
- * The AUTH environment variable is set with the authentication details.
- * @param {*} core - GitHub core library for setting outputs and environment variables.
+ * The resolved auth is emitted as this step's `auth` output (NOT exported to
+ * GITHUB_ENV), so it is scoped to this action invocation and cannot leak into
+ * later steps/actions in the same job.
+ * @param {*} core - GitHub core library for setting outputs.
*/
function setupAuth(core) {
let auth;
@@ -12,16 +16,19 @@ function setupAuth(core) {
// Check if any authentication method is provided
if (!checkEnvVarValid(fileName) && !checkEnvVarValid(authStr)) {
- // core.info("Neither AUTH_FILE_PATH nor AUTH_STR is set. Proceeding using default provider environment variable names.");
+ core.info("using default provider environment variable variables as AUTH_FILE_PATH or AUTH_STR are not set...");
+ // Emit an empty auth output so downstream steps receive a clean value for
+ // this invocation rather than anything carried over from a previous one.
+ core.setOutput("auth", "");
return;
}
if (checkEnvVarValid(fileName)) {
try {
- auth = fs.readFileSync(fileName, "utf-8");
+ auth = readFileSync(fileName, "utf-8");
} catch (error) {
core.error(error);
- core.setFailed(`Cannot find auth file ${fileName}`);
+ core.setFailed(`cannot find auth file ${fileName}`);
return;
}
}
@@ -30,67 +37,98 @@ function setupAuth(core) {
auth = authStr;
}
- core.info("Setting AUTH environment variable...");
- core.exportVariable("AUTH", auth);
+ core.info("setting auth output...");
+ core.setOutput("auth", auth);
}
async function getStackqlCommand(core) {
- // if (!checkEnvVarValid(process.env.AUTH)) {
- // core.info("Cannot find AUTH environment variable when executing stackql. Proceeding using default provider environment variable names.");
- // }
- const [query, queryFilePath, auth, output = "json", vars, dataFilePath] = [
+ const [query, queryFilePath, dry_run, auth, output = "json", vars, dataFilePath] = [
process.env.QUERY,
process.env.QUERY_FILE_PATH,
+ process.env.DRY_RUN,
process.env.AUTH,
process.env.OUTPUT,
process.env.VARS,
process.env.DATA_FILE_PATH,
];
+ const isWindows = process.platform === "win32";
+
+ // output supports: json, csv, table, text only, fail if not supported
+ if (!["json", "csv", "table", "text"].includes(output)) {
+ core.setFailed(`output format not supported: ${output}`);
+ return;
+ }
+
if (!checkEnvVarValid(query) && !checkEnvVarValid(queryFilePath)) {
- core.setFailed("Either query or query_file_path need to be set");
+ core.setFailed("either query or query_file_path need to be set");
return;
}
let args = [];
- if (queryFilePath) {
+ if (query) {
+ let formattedQuery = query;
+ if (isWindows) {
+ // Replace newlines with a space for Windows command line compatibility
+ formattedQuery = formattedQuery.replace(/\n/g, " ");
+ }
+ args = [
+ "exec",
+ `"${formattedQuery}"`,
+ ];
+ } else if (queryFilePath) {
+ if (!existsSync(queryFilePath)) {
+ core.setFailed(`query file path does not exist: ${queryFilePath}`);
+ return;
+ }
args = [
"exec",
"-i",
- queryFilePath,
- `--output='${output}'`,
+ `"${queryFilePath}"`,
];
}
- if (query) {
- args = [
- "exec",
- `"${query}"`,
- `--output='${output}'`,
- ];
- }
+ if (checkEnvVarValid(dataFilePath)) {
+ if (!existsSync(dataFilePath)) {
+ core.setFailed(`data file path does not exist: ${dataFilePath}`);
+ return;
+ }
+ args.push(`--iqldata "${dataFilePath}"`);
+ }
- if (checkEnvVarValid(vars)) {
- args.push(`--var="${vars}"`);
- }
+ args.push(`--output ${output}`);
+ if (checkEnvVarValid(dry_run)) {
+ if(dry_run === "true"){
+ args.push(`--dryrun`);
+ }
+ }
+
if (checkEnvVarValid(auth)) {
- args.push(`--auth="${auth}"`);
+ args.push(`--auth "${auth}"`);
}
- if (checkEnvVarValid(dataFilePath)) {
- args.push(`--iqldata="${dataFilePath}"`);
+ if (checkEnvVarValid(vars)) {
+ args.push(`--var "${vars}"`);
}
+
+ const wrappedBinary = process.env.STACKQL_CLI_PATH && `${process.env.STACKQL_CLI_PATH}\\stackql-bin.exe`;
+ const stackQLExecutable = isWindows
+ ? (wrappedBinary && existsSync(wrappedBinary) ? `"${wrappedBinary}"` : 'stackql.exe')
+ : 'stackql';
try {
- const stackQLCommand = `stackql ${args.join(" ")}`;
- core.exportVariable('STACKQL_COMMAND', `${stackQLCommand}`);
- // core.info(`STACKQL_COMMAND: ${stackQLCommand}`);
+ const stackQLCommand = `${stackQLExecutable} ${args.join(" ")}`;
+ // Emit as a step output (scoped to this invocation) rather than exporting to
+ // GITHUB_ENV, so the assembled command - which may embed auth/secrets - does
+ // not persist into later steps or actions in the same job.
+ core.setOutput('stackql_command', `${stackQLCommand}`);
+ core.debug(`STACKQL_COMMAND: ${stackQLCommand}`);
} catch (error) {
core.error(error);
- core.setFailed("Error when executing stackql");
+ core.setFailed("error when executing stackql");
}
}
@@ -98,7 +136,90 @@ const checkEnvVarValid = (variable) => {
return variable !== null && variable !== undefined && variable !== "";
};
+/**
+ * Executes a StackQL command and handles the output and errors based on the command type.
+ * @param {Object} core - The core library from GitHub Actions for interacting with the action environment.
+ * @param {string} command - The StackQL command to be executed.
+ * @param {boolean} isCommand - Indicates if the operation is a command (true) or query (false).
+ * @param {string} onFailure - The action to take if the command fails. Either 'exit' or 'continue'.
+ * @param {boolean} dryRun - Indicates if the operation is a dry run only.
+ */
+async function execStackQLQuery(core, command, isCommand, onFailure, dryRun) {
+
+ if (dryRun) {
+ // dry run
+ core.info(`dry-run enabled, skipping stackql query execution`);
+ } else {
+ // real query
+ if (onFailure !== 'exit' && onFailure !== 'continue') {
+ core.setFailed(`onFailure must be 'exit' or 'continue'. Received: ${onFailure}`);
+ return;
+ }
+ core.info(`executing stackql query (isCommand: ${isCommand}): ${command}`);
+ }
+
+ try {
+
+ let { stdout, stderr } = await execAsync(command);
+
+ if (process.platform != "win32"){
+ // crazy required hack for linux and mac runners....
+ for (const line of stdout.split('\n')) {
+ const decodedLine = decodeURIComponent(line.replace(/%0A/g, '\n')).trim();
+ if (decodedLine.startsWith('::debug::stdout:')) {
+ stdout = decodedLine.substring('::debug::stdout:'.length).trim();
+ };
+ if (decodedLine.startsWith('::debug::stderr:')) {
+ stderr = decodedLine.substring('::debug::stderr:'.length).trim();
+ };
+ }
+ }
+
+ if (stdout) {
+ // queries should return data to stdout
+ core.debug(`STDOUT: ${stdout}`);
+ if (!isCommand) {
+ core.setOutput('stackql-query-results', stdout);
+ if(dryRun){
+ const json = JSON.parse(stdout);
+ core.info(`dry-run query:\n${json[0].query}`);
+ } else {
+ core.info(`query output:\n${stdout}`);
+ }
+ }
+ } else {
+ core.debug('STDOUT: ');
+ }
+
+ if (stderr) {
+ // commands should return data to stderr
+ // stderr for queries indicates an error
+ core.debug(`STDERR: ${stderr}`);
+ if (!isCommand) {
+ // we shouldnt have seen an error here...
+ core.setOutput('stackql-query-error', stderr);
+ if(onFailure){
+ core.setFailed(`stackql query reported an error: ${stderr}`);
+ } else {
+ core.warning(`stackql query reported an error: ${stderr}`);
+ }
+ } else {
+ // it was a command, return the message
+ core.setOutput('stackql-command-output', stderr);
+ core.info(`command output:\n${stderr}`);
+ }
+ } else {
+ core.debug('STDERR: ');
+ }
+
+ } catch (error) {
+ core.error(`error executing StackQL command: ${error.message}`);
+ core.setFailed(`stackql command failed with error: ${error.message}`);
+ }
+}
+
module.exports = {
setupAuth,
getStackqlCommand,
-};
+ execStackQLQuery
+};
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 35b4577..93abaa4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,12 +22,13 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
- "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+ "version": "7.24.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
+ "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.18.6"
+ "@babel/highlight": "^7.24.2",
+ "picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
@@ -79,13 +80,14 @@
"dev": true
},
"node_modules/@babel/generator": {
- "version": "7.20.14",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz",
- "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==",
+ "version": "7.24.4",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz",
+ "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.20.7",
- "@jridgewell/gen-mapping": "^0.3.2",
+ "@babel/types": "^7.24.0",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
},
"engines": {
@@ -93,14 +95,14 @@
}
},
"node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"dependencies": {
- "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
+ "@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
@@ -126,34 +128,34 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
- "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
- "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"dependencies": {
- "@babel/template": "^7.18.10",
- "@babel/types": "^7.19.0"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
- "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+ "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.18.6"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@@ -212,30 +214,30 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
- "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.18.6"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.19.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
- "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
+ "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
- "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -265,14 +267,15 @@
}
},
"node_modules/@babel/highlight": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
- "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "version": "7.24.2",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
+ "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.18.6",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
@@ -350,9 +353,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.20.15",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz",
- "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==",
+ "version": "7.24.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
+ "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -539,34 +542,34 @@
}
},
"node_modules/@babel/template": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
- "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz",
+ "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.18.6",
- "@babel/parser": "^7.20.7",
- "@babel/types": "^7.20.7"
+ "@babel/code-frame": "^7.23.5",
+ "@babel/parser": "^7.24.0",
+ "@babel/types": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.20.13",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz",
- "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.20.7",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.19.0",
- "@babel/helper-hoist-variables": "^7.18.6",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/parser": "^7.20.13",
- "@babel/types": "^7.20.7",
- "debug": "^4.1.0",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
+ "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.24.1",
+ "@babel/generator": "^7.24.1",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
+ "@babel/helper-hoist-variables": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.24.1",
+ "@babel/types": "^7.24.0",
+ "debug": "^4.3.1",
"globals": "^11.1.0"
},
"engines": {
@@ -574,13 +577,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
- "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
+ "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
"dev": true,
"dependencies": {
- "@babel/helper-string-parser": "^7.19.4",
- "@babel/helper-validator-identifier": "^7.19.1",
+ "@babel/helper-string-parser": "^7.23.4",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -919,9 +922,9 @@
}
},
"node_modules/@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"engines": {
"node": ">=6.0.0"
@@ -934,13 +937,13 @@
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.17",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
- "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"dependencies": {
- "@jridgewell/resolve-uri": "3.1.0",
- "@jridgewell/sourcemap-codec": "1.4.14"
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@sinclair/typebox": {
@@ -1565,29 +1568,6 @@
"node": ">=4"
}
},
- "node_modules/execa": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.0",
- "human-signals": "^2.1.0",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.1",
- "onetime": "^5.1.2",
- "signal-exit": "^3.0.3",
- "strip-final-newline": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
- }
- },
"node_modules/exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -1706,18 +1686,6 @@
"node": ">=8.0.0"
}
},
- "node_modules/get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -1780,15 +1748,6 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
- "node_modules/human-signals": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
- "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
- "dev": true,
- "engines": {
- "node": ">=10.17.0"
- }
- },
"node_modules/import-local": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@@ -1878,18 +1837,6 @@
"node": ">=0.12.0"
}
},
- "node_modules/is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -2001,6 +1948,107 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/jest-changed-files/node_modules/execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/jest-changed-files/node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/jest-changed-files/node_modules/human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/jest-changed-files/node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/jest-changed-files/node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jest-changed-files/node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-changed-files/node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/jest-changed-files/node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/jest-circus": {
"version": "29.4.3",
"resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.4.3.tgz",
@@ -2438,9 +2486,9 @@
}
},
"node_modules/jest-snapshot/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+ "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
@@ -2690,15 +2738,6 @@
"node": ">=8.6"
}
},
- "node_modules/mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -2744,18 +2783,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -2765,21 +2792,6 @@
"wrappy": "1"
}
},
- "node_modules/onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "dependencies": {
- "mimic-fn": "^2.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -3023,9 +3035,9 @@
}
},
"node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -3158,15 +3170,6 @@
"node": ">=8"
}
},
- "node_modules/strip-final-newline": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -3438,12 +3441,13 @@
}
},
"@babel/code-frame": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
- "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+ "version": "7.24.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
+ "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.18.6"
+ "@babel/highlight": "^7.24.2",
+ "picocolors": "^1.0.0"
}
},
"@babel/compat-data": {
@@ -3484,25 +3488,26 @@
}
},
"@babel/generator": {
- "version": "7.20.14",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz",
- "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==",
+ "version": "7.24.4",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz",
+ "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==",
"dev": true,
"requires": {
- "@babel/types": "^7.20.7",
- "@jridgewell/gen-mapping": "^0.3.2",
+ "@babel/types": "^7.24.0",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
},
"dependencies": {
"@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"requires": {
- "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
+ "@jridgewell/trace-mapping": "^0.3.24"
}
}
}
@@ -3521,28 +3526,28 @@
}
},
"@babel/helper-environment-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
- "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true
},
"@babel/helper-function-name": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
- "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"requires": {
- "@babel/template": "^7.18.10",
- "@babel/types": "^7.19.0"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
- "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+ "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"requires": {
- "@babel/types": "^7.18.6"
+ "@babel/types": "^7.22.5"
}
},
"@babel/helper-module-imports": {
@@ -3586,24 +3591,24 @@
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
- "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"requires": {
- "@babel/types": "^7.18.6"
+ "@babel/types": "^7.22.5"
}
},
"@babel/helper-string-parser": {
- "version": "7.19.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
- "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
+ "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
"dev": true
},
"@babel/helper-validator-identifier": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
- "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true
},
"@babel/helper-validator-option": {
@@ -3624,14 +3629,15 @@
}
},
"@babel/highlight": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
- "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "version": "7.24.2",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
+ "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.18.6",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
},
"dependencies": {
"ansi-styles": {
@@ -3693,9 +3699,9 @@
}
},
"@babel/parser": {
- "version": "7.20.15",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz",
- "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==",
+ "version": "7.24.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
+ "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
"dev": true
},
"@babel/plugin-syntax-async-generators": {
@@ -3825,42 +3831,42 @@
}
},
"@babel/template": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
- "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz",
+ "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.18.6",
- "@babel/parser": "^7.20.7",
- "@babel/types": "^7.20.7"
+ "@babel/code-frame": "^7.23.5",
+ "@babel/parser": "^7.24.0",
+ "@babel/types": "^7.24.0"
}
},
"@babel/traverse": {
- "version": "7.20.13",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz",
- "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.20.7",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.19.0",
- "@babel/helper-hoist-variables": "^7.18.6",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/parser": "^7.20.13",
- "@babel/types": "^7.20.7",
- "debug": "^4.1.0",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
+ "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.24.1",
+ "@babel/generator": "^7.24.1",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
+ "@babel/helper-hoist-variables": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.24.1",
+ "@babel/types": "^7.24.0",
+ "debug": "^4.3.1",
"globals": "^11.1.0"
}
},
"@babel/types": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
- "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
+ "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
"dev": true,
"requires": {
- "@babel/helper-string-parser": "^7.19.4",
- "@babel/helper-validator-identifier": "^7.19.1",
+ "@babel/helper-string-parser": "^7.23.4",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
@@ -4126,9 +4132,9 @@
"dev": true
},
"@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true
},
"@jridgewell/sourcemap-codec": {
@@ -4138,13 +4144,13 @@
"dev": true
},
"@jridgewell/trace-mapping": {
- "version": "0.3.17",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
- "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"requires": {
- "@jridgewell/resolve-uri": "3.1.0",
- "@jridgewell/sourcemap-codec": "1.4.14"
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@sinclair/typebox": {
@@ -4628,23 +4634,6 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
- "execa": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.0",
- "human-signals": "^2.1.0",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.1",
- "onetime": "^5.1.2",
- "signal-exit": "^3.0.3",
- "strip-final-newline": "^2.0.0"
- }
- },
"exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -4735,12 +4724,6 @@
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
"dev": true
},
- "get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true
- },
"glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -4788,12 +4771,6 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
- "human-signals": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
- "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
- "dev": true
- },
"import-local": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@@ -4859,12 +4836,6 @@
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
- "is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true
- },
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -4942,6 +4913,73 @@
"requires": {
"execa": "^5.0.0",
"p-limit": "^3.1.0"
+ },
+ "dependencies": {
+ "execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ }
+ },
+ "get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true
+ },
+ "human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true
+ },
+ "is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true
+ },
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ },
+ "npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.0.0"
+ }
+ },
+ "onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ },
+ "strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true
+ }
}
},
"jest-circus": {
@@ -5286,9 +5324,9 @@
}
},
"semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+ "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
@@ -5481,12 +5519,6 @@
"picomatch": "^2.3.1"
}
},
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
- },
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -5526,15 +5558,6 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
- "npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "requires": {
- "path-key": "^3.0.0"
- }
- },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -5544,15 +5567,6 @@
"wrappy": "1"
}
},
- "onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "requires": {
- "mimic-fn": "^2.1.0"
- }
- },
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -5725,9 +5739,9 @@
"dev": true
},
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
},
"shebang-command": {
@@ -5830,12 +5844,6 @@
"integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
"dev": true
},
- "strip-final-newline": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
- "dev": true
- },
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
diff --git a/stackql_scripts/google-instances-by-status.iql b/stackql_scripts/google-instances-by-status.iql
index 004316d..558abd2 100644
--- a/stackql_scripts/google-instances-by-status.iql
+++ b/stackql_scripts/google-instances-by-status.iql
@@ -1,4 +1,4 @@
SELECT status, count(*) as num_instances
FROM google.compute.instances
-WHERE project = 'stackql-demo'
+WHERE project = 'stackql-integration-tests'
GROUP BY status;
\ No newline at end of file