Skip to content
This repository was archived by the owner on Jan 29, 2026. It is now read-only.

Commit 74e6376

Browse files
committed
initial commit
0 parents  commit 74e6376

12 files changed

Lines changed: 492 additions & 0 deletions

.github/workflows/linter.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
#################################
3+
#################################
4+
## Super Linter GitHub Actions ##
5+
#################################
6+
#################################
7+
name: Lint Code Base
8+
9+
#
10+
# Documentation:
11+
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
12+
#
13+
14+
on: push
15+
16+
###############
17+
# Set the Job #
18+
###############
19+
jobs:
20+
build:
21+
# Name the Job
22+
name: Lint Code Base
23+
# Set the agent to run on
24+
runs-on: ubuntu-latest
25+
26+
############################################
27+
# Grant status permission for MULTI_STATUS #
28+
############################################
29+
permissions:
30+
contents: read
31+
packages: read
32+
statuses: write
33+
34+
##################
35+
# Load all steps #
36+
##################
37+
steps:
38+
##########################
39+
# Checkout the code base #
40+
##########################
41+
- name: Checkout Code
42+
uses: actions/checkout@v3
43+
with:
44+
# Full git history is needed to get a proper
45+
# list of changed files within `super-linter`
46+
fetch-depth: 0
47+
48+
################################
49+
# Run Linter against code base #
50+
################################
51+
- name: Lint Code Base
52+
uses: super-linter/super-linter/slim@v5
53+
env:
54+
VALIDATE_ALL_CODEBASE: false
55+
DEFAULT_BRANCH: main
56+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57+
FILTER_REGEX_EXCLUDE: testing/.*

.github/workflows/tests.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Running scans using latest library and the gh action on testing config and checks files.
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
workflow_dispatch:
9+
10+
jobs:
11+
soda_scan_test:
12+
runs-on: ubuntu-latest
13+
name: Test ${{ matrix.name }}
14+
env:
15+
CLOUD_API_KEY_ID: ${{ secrets.CLOUD_API_KEY_ID }}
16+
CLOUD_API_KEY_SECRET: ${{ secrets.CLOUD_API_KEY_SECRET }}
17+
SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
18+
SNOWFLAKE_PASS: ${{ secrets.SNOWFLAKE_PASS }}
19+
strategy:
20+
matrix:
21+
include:
22+
- name: passing scan
23+
data_source: reporting_api__marts
24+
checks: ./testing/checks_p*.yaml
25+
expected_exit_code: 0
26+
- name: failing scan on check
27+
data_source: reporting_api__marts
28+
checks: ./testing/checks_fail_on_check.yaml
29+
expected_exit_code: 2
30+
- name: failing scan on error
31+
data_source: MISSING_DS
32+
checks: ./testing/checks_pass.yaml
33+
expected_exit_code: 1
34+
steps:
35+
- name: Checkout
36+
uses: actions/checkout@v3
37+
- name: Perform Soda Scan
38+
id: soda_scan
39+
continue-on-error: true
40+
uses: ./
41+
with:
42+
# should be latest, but it is not published yet
43+
soda_library_version: v1.0.4
44+
configuration: ./testing/configuration.yaml
45+
data_source: ${{ matrix.data_source }}
46+
checks: ${{ matrix.checks }}
47+
- name: Assert scan exit code
48+
run: |
49+
if [ "${{ env.SCAN_EXIT_CODE }}" == "${{ matrix.expected_exit_code }}" ]; then
50+
echo "The Scan exited as expected."
51+
else
52+
echo "The Scan did not exit as expected."
53+
exit 1
54+
fi

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
soda_scan_results.json
2+
soda_scan_results_raw.json
3+
*.DS_store
4+
.env_file
5+
testing/configuration_local.yaml

Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This should be sodadata/soda-library:xxx
2+
# The version should be fixed and aligned with the version of this action.
3+
ARG SODA_LIBRARY_VERSION=latest
4+
FROM sodadata/soda-library:$SODA_LIBRARY_VERSION
5+
6+
COPY entrypoint.sh /entrypoint.sh
7+
8+
RUN chmod +x /entrypoint.sh
9+
10+
ENTRYPOINT ["/entrypoint.sh"]

README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# soda-github-action
2+
[![GitHub Super-Linter](https://github.com/sodadata/soda-github-action/actions/workflows/linter.yml/badge.svg)](https://github.com/marketplace/actions/super-linter)
3+
[![.github/workflows/tests.yaml](https://github.com/sodadata/soda-github-action/actions/workflows/tests.yaml/badge.svg)](https://github.com/sodadata/soda-github-action/actions/workflows/tests.yaml)
4+
5+
## Example usage
6+
7+
```yaml
8+
- name: Soda scan
9+
uses: sodadata/soda-github-action@v1
10+
env:
11+
SODA_CLOUD_API_KEY: ${{ secrets.SODA_CLOUD_API_KEY }}
12+
SODA_CLOUD_API_SECRET: ${{ secrets.SODA_CLOUD_API_SECRET }}
13+
SNOWFLAKE_USERNAME: ${{ secrets.SNOWFLAKE_USERNAME }}
14+
SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
15+
with:
16+
soda_library_version: v1.0.4
17+
data_source: snowflake
18+
configuration: ./configuration.yaml
19+
checks: ./checks.yaml
20+
```
21+
Also refer to [testing files](https://github.com/sodadata/soda-github-action/tree/main/testing) and the [test workflow](https://github.com/sodadata/soda-github-action/blob/main/.github/workflows/tests.yaml) for complete example of usage.
22+
23+
24+
### Action inputs
25+
| Name | Description | Required | Default |
26+
| --- | --- | --- | --- |
27+
| `soda_library_version` | Version of the Soda Library used to run the scan. Either specific version like `v1.0.4` or `latest`. See [soda-library](https://hub.docker.com/r/sodadata/soda-library/tags) docker images for possible versions. Versions lower than 1.0.4 are not supported. | ✅ | - |
28+
| `data_source` | Data Source name to be used for the scan | ✅ | - |
29+
| `configuration` | Configuration file path. See [docs](https://docs.soda.io/soda-core/configuration.html) | ✅ | - |
30+
| `checks` | Checks file path. See [docs](https://docs.soda.io/soda-core/scan-core.html#anatomy-of-a-scan-command). Allows for using shell filename extensions. You can match multiple check files, for example: `checks: ./checks_*.yaml` or `checks: ./{check1.yaml,check2.yaml}` | ✅ | - |
31+
32+
33+
### Permissions
34+
When using the action in `pull_request` event, it is required to specify step's permissions as follows:
35+
```yaml
36+
permissions:
37+
pull-requests: write
38+
```
39+
as the action posts a comment with the scan results to the PR.
40+
Note the comment is only created for workflows run by `pull_request` event.
41+
42+
### Self-hosted runners caveats
43+
When running this action on self-hosted runners, there are some additional caveats:
44+
45+
- Windows runners are not supported. This also means using official Windows-based images like `windows-latest` is not allowed.
46+
- Mac runners require Docker to be installed additionally. In other words, `macos-latest` does not come with Docker pre-installed.

action.yaml

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
name: 'Soda Library Github Action'
3+
description: 'GitHub action to run soda-library scan'
4+
branding:
5+
icon: 'circle'
6+
color: 'green'
7+
inputs:
8+
soda_library_version:
9+
description: 'Version of the Soda Library to run the scan on'
10+
required: true
11+
12+
data_source:
13+
description: 'Data Source name'
14+
required: true
15+
16+
configuration:
17+
description: 'Configuration file'
18+
required: true
19+
20+
checks:
21+
description: 'Checks file'
22+
required: true
23+
24+
runs:
25+
using: "composite"
26+
steps:
27+
# 0. Check if required inputs are set
28+
- name: Check required inputs
29+
run: |
30+
[[ "${{ inputs.soda_library_version }}" ]] || { echo -e "\033[31;1;4m[Soda Library Github Action] Input: 'soda_library_version' is required\033[0m" ; exit 1; }
31+
[[ "${{ inputs.data_source }}" ]] || { echo -e "\033[31;1;4m[Soda Library Github Action] Input: 'data_source' is required\033[0m" ; exit 1; }
32+
[[ "${{ inputs.configuration }}" ]] || { echo -e "\033[31;1;4m[Soda Library Github Action] Input: 'configuration' is required\033[0m" ; exit 1; }
33+
[[ "${{ inputs.checks }}" ]] || { echo -e "\033[31;1;4m[Soda Library Github Action] Input: 'checks' is required\033[0m" ; exit 1; }
34+
shell: bash
35+
36+
# 1. Build docker image with a specific soda-library version for the base image
37+
- name: Build the Docker image
38+
run: |
39+
docker build \
40+
${GITHUB_ACTION_PATH} \
41+
--file ${GITHUB_ACTION_PATH}/Dockerfile \
42+
-t soda_action_${{ github.sha }} \
43+
--build-arg="SODA_LIBRARY_VERSION=${{ inputs.soda_library_version }}"
44+
shell: bash
45+
46+
# 2. Need to expand the environment variables to pass to the docker run command
47+
# as these variables can be configured in the workflow file and contain secrets etc.
48+
- name: Expand environment variables
49+
id: expand_envs
50+
env:
51+
BRANCH_NAME: ${{ github.event.pull_request.head.ref }}
52+
PR_TITLE: ${{ github.event.pull_request.title }}
53+
PR_URL: ${{ github.event.pull_request.html_url }}
54+
PR_NUMBER: ${{ github.event.pull_request.number }}
55+
run: |
56+
env > .env_file
57+
shell: bash
58+
59+
# 3. Run built image to trigger the actual scan
60+
- name: Run your Docker Action
61+
id: soda_scan
62+
run: |
63+
docker run \
64+
--workdir ${GITHUB_ACTION_PATH} \
65+
--env-file .env_file \
66+
-e "HOME" \
67+
-e "GITHUB_JOB" \
68+
-e "GITHUB_REF" \
69+
-e "GITHUB_SHA" \
70+
-e "GITHUB_REPOSITORY" \
71+
-e "GITHUB_REPOSITORY_OWNER" \
72+
-e "GITHUB_REPOSITORY_OWNER_ID" \
73+
-e "GITHUB_RUN_ID" \
74+
-e "GITHUB_RUN_NUMBER" \
75+
-e "GITHUB_RETENTION_DAYS" \
76+
-e "GITHUB_RUN_ATTEMPT" \
77+
-e "GITHUB_REPOSITORY_ID" \
78+
-e "GITHUB_ACTOR_ID" \
79+
-e "GITHUB_ACTOR" \
80+
-e "GITHUB_TRIGGERING_ACTOR" \
81+
-e "GITHUB_HEAD_REF" \
82+
-e "GITHUB_BASE_REF" \
83+
-e "GITHUB_EVENT_NAME" \
84+
-e "GITHUB_SERVER_URL" \
85+
-e "GITHUB_API_URL" \
86+
-e "GITHUB_GRAPHQL_URL" \
87+
-e "GITHUB_REF_NAME" \
88+
-e "GITHUB_REF_PROTECTED" \
89+
-e "GITHUB_REF_TYPE" \
90+
-e "GITHUB_WORKFLOW_REF" \
91+
-e "GITHUB_WORKFLOW_SHA" \
92+
-e "GITHUB_WORKSPACE" \
93+
-e "GITHUB_ACTION" \
94+
-e "GITHUB_EVENT_PATH" \
95+
-e "GITHUB_ACTION_REPOSITORY" \
96+
-e "GITHUB_ACTION_REF" \
97+
-e "GITHUB_PATH" \
98+
-e "GITHUB_ENV" \
99+
-e "GITHUB_STEP_SUMMARY" \
100+
-e "GITHUB_STATE" \
101+
-e "GITHUB_OUTPUT" \
102+
-e "GITHUB_ACTION_PATH" \
103+
-e "RUNNER_OS" \
104+
-e "RUNNER_ARCH" \
105+
-e "RUNNER_NAME" \
106+
-e "RUNNER_TOOL_CACHE" \
107+
-e "RUNNER_TEMP" \
108+
-e "RUNNER_WORKSPACE" \
109+
-e "ACTIONS_RUNTIME_URL" \
110+
-e "ACTIONS_RUNTIME_TOKEN" \
111+
-e "ACTIONS_CACHE_URL" \
112+
-e GITHUB_ACTIONS=true \
113+
-e CI=true \
114+
--rm \
115+
-v ${{ github.env}}:${{ github.env}} \
116+
-v ${GITHUB_ACTION_PATH}:/tmp/action_path \
117+
-v ${{ github.workspace }}:/tmp/workspace \
118+
soda_action_${{ github.sha }} \
119+
${{ inputs.data_source }} \
120+
"${{ inputs.configuration }}" \
121+
"${{ inputs.checks }}" || true
122+
shell: bash
123+
124+
- name: Scan results link
125+
if: env.SCAN_EXIT_CODE == 0 || env.SCAN_EXIT_CODE == 2
126+
run: |
127+
echo -e "\033[36;1m-----------------------------\033[0m"
128+
echo -e "\033[36;1m View the full scan results -> \033[0m ${{ env.SCAN_CLOUD_LINK }}"
129+
echo -e "\033[36;1m-----------------------------\033[0m"
130+
shell: bash
131+
132+
# 4. The soda-library scan results are converted to a markdown table
133+
# Using newest hash from 1.0.0 version.
134+
- uses: buildingcash/json-to-markdown-table-action@ce128b72e0c93612c8f02b85e0672bcb16fd9bf9
135+
id: table
136+
if: ${{ env.SCAN_RESULTS }}
137+
with:
138+
json: ${{ env.SCAN_RESULTS }}
139+
140+
# 5. Create the PR comment
141+
# Using newest hash from 2.4.0 version.
142+
- name: Comment PR on success
143+
uses: thollander/actions-comment-pull-request@8c77f42bbcc27c832a3a5962c8f9a60e34b594f3
144+
continue-on-error: true
145+
if: env.SCAN_EXIT_CODE == 0
146+
with:
147+
message: |
148+
🟢 Soda scan completed successfully with the following results:
149+
150+
${{ steps.table.outputs.table }}
151+
152+
[View the full scan results](${{ env.SCAN_CLOUD_LINK }})
153+
154+
- name: Comment PR on failure with results
155+
uses: thollander/actions-comment-pull-request@8c77f42bbcc27c832a3a5962c8f9a60e34b594f3
156+
continue-on-error: true
157+
if: env.SCAN_EXIT_CODE == 2
158+
with:
159+
message: |
160+
🔴 Soda scan completed with the following results:
161+
162+
${{ steps.table.outputs.table }}
163+
164+
[View the full scan results](${{ env.SCAN_CLOUD_LINK }})
165+
166+
- name: Comment PR on fatal failure
167+
uses: thollander/actions-comment-pull-request@8c77f42bbcc27c832a3a5962c8f9a60e34b594f3
168+
continue-on-error: true
169+
if: env.SCAN_EXIT_CODE == 1 || env.SCAN_EXIT_CODE == 3
170+
with:
171+
message: |
172+
🔴 Soda scan failed. Check logs for more details.
173+
174+
175+
# 6. Post additional message to make it clear scan failed or not
176+
- name: Fail Job if Soda Scan Failed
177+
shell: bash
178+
if: env.SCAN_EXIT_CODE != 0
179+
run: |
180+
echo -e "\033[31;1;4mSoda Scan failed\033[0m" && exit ${{ env.SCAN_EXIT_CODE }}
181+
182+
- name: Fail Job if Soda Scan Succeeded
183+
shell: bash
184+
if: env.SCAN_EXIT_CODE == 0
185+
run: |
186+
echo -e "\33[32;1;4mSoda Scan succeeded\033[0m"

entrypoint.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/sh
2+
3+
python3 /tmp/action_path/scripts/create_ci_info_json.py
4+
5+
# shellcheck disable=SC2086
6+
soda scan \
7+
-d "$1" \
8+
-c /tmp/workspace/$2 \
9+
/tmp/workspace/$3 \
10+
-srf soda_scan_results_raw.json \
11+
--scan-type cicd \
12+
-cif soda_scan_ci_info.json
13+
14+
exit_status=$?
15+
16+
scan_cloud_link=$(python3 /tmp/action_path/scripts/reformat_json.py soda_scan_results_raw.json)
17+
18+
{
19+
echo "SCAN_RESULTS=$(cat soda_scan_results.json)"
20+
echo "SCAN_EXIT_CODE=$exit_status"
21+
echo "SCAN_CLOUD_LINK=$scan_cloud_link"
22+
} >> "$GITHUB_ENV"
23+
24+
exit $exit_status

0 commit comments

Comments
 (0)