{"id":16461,"date":"2022-05-25T13:52:52","date_gmt":"2022-05-25T17:52:52","guid":{"rendered":"https:\/\/qxf2.com\/blog\/?p=16461"},"modified":"2022-05-25T13:52:52","modified_gmt":"2022-05-25T17:52:52","slug":"great-expectations-example-github-actions","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/great-expectations-example-github-actions\/","title":{"rendered":"Run Great Expectations workflow using GitHub Actions"},"content":{"rendered":"<p>In this post, we will help you run one <a href=\"https:\/\/greatexpectations.io\">Great Expectations<\/a> test as part of your CI\/CD pipeline using GitHub Actions. This post is second in our series to help testers implement useful tests with Great Expectations for data validation. If your instinct says that adding a single test to a CI\/CD pipeline should not be the next part, read on to find out why we think this is an important next step that a tester should fight for.<\/p>\n<p>My audience is software testers and those interested in testing. I have taken care to infuse this post with a lot of &#8220;tester-like&#8221; thinking. Also, shared my thought process to help you introduce test automation (not just using Great Expectations) within your team. You can find it in the section titled &#8216;Prepare your team&#8217; later in this post.<\/p>\n<p><b>Note 1:<\/b> I am choosing GitHub Actions and Slack for this blog post because they are popular with our clients.<br \/>\n<b>Note 2:<\/b> While working to get my test to CI, I came across <a href=\"https:\/\/github.com\/great-expectations\/great_expectations_action\">great_expectations_action<\/a>, a dedicated GitHub Action for Great Expectations. It helps in triggering a Checkpoint which will perform data validation on our data. However, when I started to use the action, I found it failing in the first step where a Docker image is built. Digging deeper, I saw that it was due to an incompatible Node.js version. Subsequently, I fixed the issue and raised a <a href=\"https:\/\/github.com\/great-expectations\/great_expectations_action\/pull\/80\">PR<\/a>. To get things going, I chose a simple <a href=\"https:\/\/docs.github.com\/en\/actions\/learn-github-actions\/understanding-github-actions\">GitHub Action<\/a> which will allow me to run a Python script.<br \/>\n<b>Note 3:<\/b> This post needs you to be setup with Great Expectations as a pre-requisite. It also assumes you are familiar with Great Expectations and the related <a href=\"https:\/\/docs.greatexpectations.io\/docs\/glossary\">terminology<\/a>. If you are not already setup and familiar with Great Expectations, please follow <a href=\"https:\/\/qxf2.com\/blog\/data-validation-great-expectations-real-example\/\">Great Expectations tutorial with a real-world scenario: Part 1<\/a>.<\/p>\n<p>Here is how we will be using GitHub Action for:<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/ge_github_actions_workflow-3.png\" data-rel=\"lightbox-image-0\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/ge_github_actions_workflow-3.png\" alt=\"Snapshot of steps of GitHub Action for running Great Expectation test\" width=\"300\" height=\"433\" class=\"aligncenter size-full wp-image-16538\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/ge_github_actions_workflow-3.png 300w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/ge_github_actions_workflow-3-208x300.png 208w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>We will be doing the above steps in this blog post. But before we go there, I want to talk a bit about why I feel CI is the next step.<\/p>\n<hr>\n<h3>A minimum viable test<\/h3>\n<p>The lean movement made the concept of a Minimum Viable Product (MVP) popular. It is the minimum set of features which, when presented to a real user, allows you to validate your hypotheses about the utility of your product. Think about rolling out your test automation efforts in terms of validating its value. When it works, this approach is a good way to put out your test automation efforts, keep the team focused on the value the tests deliver and not just relegate all test automation efforts to the infamous &#8220;catch up&#8221; mentality. The software product in this case is your test automation while your users are your team members &#8211; developers, product owners, support team, managers, other testers, etc. Our test have different value propositions for each of them.<\/p>\n<p>In our case, having one test run against historic data with every build is more than sufficient to start collecting information about how our different stakeholders can find our tests useful. And so, we end up proposing that adding test automation to the CI\/CD pipeline should happen right after the first test has been developed. <\/p>\n<hr>\n<h3>Overview<\/h3>\n<p>To recap, in the previous post we have written a test for date column of <a href=\"https:\/\/gist.github.com\/sravantit25\/2ce8cfacca5275091f05a8b6d37f9787\">github_stats<\/a> table to check if the date is according to required specification. Now, the next step is to use our test to perform regular checks on new data as it keeps coming in. To get our test working in a CI environment and receive Slack notifications after the run, we will be doing four main steps:<br \/>\n1. Get the data for the test<br \/>\n2. Run the test using GitHub Action<br \/>\n3. Report results to Slack<br \/>\n4. Store results <\/p>\n<p>Let us go through each of them:<\/p>\n<h4>1. Get the data for the test<\/h4>\n<p>In the earlier post, we created an Expectation Suite and ran it against historical data (the <a href=\"https:\/\/gist.github.com\/sravantit25\/2ce8cfacca5275091f05a8b6d37f9787\">github_stats CSV<\/a> file). Now, as testers we should first arrive at what amount of data do we need for our test. For instance, in my case, I am downloading the data from a Cloud based database table as a CSV file. Now, I do not want to download all the data daily but instead divide it as batches for my test. Say, I want to test if on each day statistics for all repos is being collected. Then, I would limit my data to a date range of getting only the before day&#8217;s data. Since my test would run daily, I can make sure that for that day all stats look fine. However, in this blog I will not go into those details but instead continue using the <a href=\"https:\/\/gist.github.com\/sravantit25\/2ce8cfacca5275091f05a8b6d37f9787\">github_stats CSV<\/a> file we have currently so that you can play along. <\/p>\n<h4>2. Run the test using GitHub Action<\/h4>\n<p>To run the Expectation Suite having the date format Expectation, we need a Checkpoint. It validates our Expectation Suite against the batch of data. Earlier, we used Checkpoint while creating and testing our Expectation Suite. Now, we will create a Checkpoint which we can save and configure to run on a schedule. To do that, we will perform the following steps:<\/p>\n<p>2.1) Create a Checkpoint<br \/>\n2.2) Generate Python script to trigger the Checkpoint<br \/>\n2.3) Run the Python script using GitHub Action<\/p>\n<h5>2.1) Create a Checkpoint<\/h5>\n<p>We can create a Checkpoint using the following Great Expectations CLI command. <\/p>\n<p><code><strong>great_expectations checkpoint new github_stats_checkpoint<\/strong><\/code><\/p>\n<p>It opens up a Jupyter Notebook (like we have seen with other commands) which has the boilerplate code for completing the task. Run all the cells in the notebook.<\/p>\n<p>The first step is to initialize Data Context which all supporting components that Great Expectations consists of. <\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/initialize_data_context_checkpoint-1.png\" data-rel=\"lightbox-image-1\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/initialize_data_context_checkpoint-1.png\" alt=\"This screenshot shows Jupyter notebook code snippet which initializes Data Context\" width=\"450\" height=\"169\" class=\"alignnone size-full wp-image-16481\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/initialize_data_context_checkpoint-1.png 450w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/initialize_data_context_checkpoint-1-300x113.png 300w\" sizes=\"auto, (max-width: 450px) 100vw, 450px\" \/><\/a><\/p>\n<p>Next, we will create a Checkpoint using SimpleCheckpoint (one of the Checkpoint classes provided by Great Expectations) which is good enough for our case for now. I changed the run_name_template to reflect github_stats<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/create_checkpoint_template_change-1.png\" data-rel=\"lightbox-image-2\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/create_checkpoint_template_change-1.png\" alt=\"This screenshot shows creation of a Checkpoint using SimpleCheckpoint class\" width=\"600\" height=\"317\" class=\"alignnone size-full wp-image-16482\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/create_checkpoint_template_change-1.png 600w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/create_checkpoint_template_change-1-300x159.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>Now, to test our Checkpoint, lets use test_yaml_config() which will run a check to verify if our Checkpoint configuration is correct.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/test_checkpoint_config-2.png\" data-rel=\"lightbox-image-3\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/test_checkpoint_config-2.png\" alt=\"his screenshot shows a check to verify if Checkpoint configuration is correct\" width=\"600\" height=\"201\" class=\"alignnone size-full wp-image-16484\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/test_checkpoint_config-2.png 600w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/test_checkpoint_config-2-300x101.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>After the above successful test, we will now save our Checkpoint. It is present as <strong>github_stats_checkpoint.yml<\/strong> under <strong>checkpoints<\/strong> folder.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/store_checkpoint-2.png\" data-rel=\"lightbox-image-4\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/store_checkpoint-2.png\" alt=\"\" width=\"591\" height=\"266\" class=\"alignnone size-full wp-image-16488\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/store_checkpoint-2.png 591w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/store_checkpoint-2-300x135.png 300w\" sizes=\"auto, (max-width: 591px) 100vw, 591px\" \/><\/a><\/p>\n<p>The last step is to run our Checkpoint and optionally view results in Data Docs. Uncomment the lines in the last cell and run it.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint-1.png\" data-rel=\"lightbox-image-5\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint-1.png\" alt=\"This screenshot shows how to run Checkpoint and open Data Docs\" width=\"570\" height=\"146\" class=\"alignnone size-full wp-image-16486\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint-1.png 570w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint-1-300x77.png 300w\" sizes=\"auto, (max-width: 570px) 100vw, 570px\" \/><\/a><\/p>\n<p>Running a Checkpoint opens Data Docs which is documentation generated by Great Expectations. We will talk about these little later.<\/p>\n<h5>2.2) Generate Python script to trigger the Checkpoint<\/h5>\n<p>In the above section, we saw how to run a Checkpoint using Great Expectations CLI command. We can also use Python to run a Checkpoint. This will be useful in our CI environment. Great Expectations provides a convenient way to generate a Python script using the below command:<\/p>\n<p><code><strong>great_expectations checkpoint script github_stats_checkpoint<\/strong><\/code><\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/generate_python_script_checkpoint.png\" data-rel=\"lightbox-image-6\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/generate_python_script_checkpoint.png\" alt=\"This screenshot shows how to generate Python Script for a Checkpoint\" width=\"800\" height=\"84\" class=\"alignnone size-full wp-image-16489\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/generate_python_script_checkpoint.png 800w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/generate_python_script_checkpoint-300x32.png 300w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/generate_python_script_checkpoint-768x81.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/p>\n<p>As observed in the screenshot, a script with the name &#8216;<strong>run_github_stats_checkpoint.py<\/strong>&#8216; is generated under <strong>uncommitted<\/strong> folder by default. We would want to move this script to checkpoints folder since files present under uncommitted are not checked into version control.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_script.png\" data-rel=\"lightbox-image-7\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_script.png\" alt=\"\" width=\"500\" height=\"355\" class=\"alignnone size-full wp-image-16502\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_script.png 500w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_script-300x213.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/a><\/p>\n<p>Looking at the script, we see that first DataContext is initialized which is then used to call run_checkpoint method. The context_root_dir is the location where the Great Expectations folder is present (the location will be by default specific to your local system). To make it run using GitHub action, we will update it as following:<\/p>\n<p><code><strong>context_root_dir=\"great_expectations\"<\/strong><\/code><\/p>\n<p>If you would like, refer the script <a href=\"https:\/\/gist.github.com\/sravantit25\/95660a6ca69da319783b30eca1cac665\">here<\/a>. Ensure that it is placed under great_expectations\/checkpoints folder.<\/p>\n<h5>2.3) Run the script using GitHub Action<\/h5>\n<p>Now that we have the script ready, we will create a GitHub workflow to run it. <\/p>\n<p>i) First, add a <a href=\"https:\/\/gist.github.com\/sravantit25\/6260263e6ad9acb1ddf85abf97682ea7\">requirements.txt<\/a> file in your github repository with <strong>great_expectations<\/strong> in it.<\/p>\n<p>ii) Then, create .github\/workflows directory (if not already present) to store our <a href=\"https:\/\/docs.github.com\/en\/actions\/learn-github-actions\/understanding-github-actions#workflows\">workflow<\/a> file.<\/p>\n<p>iii) Under the directory, create a file called <strong>github_stats_run.yml<\/strong> which will contain all the steps we want to run as part of our workflow.<\/p>\n<p>iv) In the workflow, we will create a <a href=\"https:\/\/docs.github.com\/en\/actions\/learn-github-actions\/understanding-github-actions#jobs\">job<\/a> which will have four steps:<br \/>\n * Install python<br \/>\n * Checkout our repository<br \/>\n * Install dependencies<br \/>\n * Run Checkpoint<\/p>\n<pre lang=\"python\">\r\nname: run-github-stats-checkpoint\r\n\r\njobs:\r\n  great_expectations_validation:\r\n    runs-on: ubuntu-latest\r\n    steps:\r\n    - name: Install python\r\n      uses: actions\/setup-python@v3\r\n\r\n    - name: Copy Repository contents\r\n      uses: actions\/checkout@main \r\n\r\n    - name: Install dependencies\r\n      run: |\r\n        python -m pip install --upgrade pip\r\n        pip install -r requirements.txt\r\n    \r\n    - name: Run Checkpoint\r\n      run: |\r\n        python great_expectations\/checkpoints\/run_github_stats_checkpoint.py\r\n<\/pre>\n<p>Refer the script <a href=\"https:\/\/gist.github.com\/sravantit25\/103447095dbef8bfb7f21d72c65b829b\">here<\/a>. Place this script as <strong>github_stats_run.yml<\/strong> in <strong>.github\/workflows<\/strong> folder.<\/p>\n<p>v) Test the action<br \/>\nWe will trigger the action manually and verify if the Checkpoint has run successfully. In your github repo, navigate to Actions tab. Under Workflows, you should fine <strong>run-github-stats-checkpoint<\/strong> workflow. This is the name we have provided for our workflow in the yml file. Select the workflow and click on &#8216;Run workflow&#8217;.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/github_run_workflow.png\" data-rel=\"lightbox-image-8\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/github_run_workflow.png\" alt=\"This screenshot shows manual trigger of GitHub Action\" width=\"800\" height=\"311\" class=\"alignnone size-full wp-image-16492\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/github_run_workflow.png 800w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/github_run_workflow-300x117.png 300w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/github_run_workflow-768x299.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/p>\n<p>The workflow is triggered which completes all the steps we listed above. <\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_github_step.png\" data-rel=\"lightbox-image-9\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_github_step.png\" alt=\"This screenshot shows the successful run of github workflow run-github-stats-checkpoint\" width=\"566\" height=\"455\" class=\"alignnone size-full wp-image-16523\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_github_step.png 566w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_github_step-300x241.png 300w\" sizes=\"auto, (max-width: 566px) 100vw, 566px\" \/><\/a><\/p>\n<p>The Checkpoint has run our test and performed validation for github_stats data.<\/p>\n<h4>3. Report results to Slack<\/h4>\n<p>We have so far automated our test run. Next, we want some sort of automatic notification about the test run. Great Expectations has integration with different communication channels like Email and Slack. In this blog I will show how to receive notifications in Slack because that is what majority of us use. At <a href=\"https:\/\/qxf2.com\/?utm_source=ge_github_action&#038;utm_medium=click&#038;utm_campaign=From%20blog\">Qxf2<\/a>, we use Skype as our means of communication. So, I added functionality to send to Skype too. But I will not be covering that here.<\/p>\n<p>To send notification to Slack, we will perform the following steps:<\/p>\n<p>3.1) Create a Slack Webhook<br \/>\n3.2) Add Slack notification action to Checkpoint<br \/>\n3.3) Create a GitHub Secret for the Webhook<br \/>\n3.4) Use the Webhook in GitHub Action<br \/>\n3.5) Test the notification<\/p>\n<p>Before we go into the steps in detail, make sure you have performed the following:<br \/>\n* <a href=\"https:\/\/slack.com\/intl\/en-in\/downloads\/windows\">Downloaded<\/a> Slack (or opened in browser)<br \/>\n* <a href=\"https:\/\/slack.com\/intl\/en-in\/help\/articles\/206845317-Create-a-Slack-workspace\">Created a workspace<\/a> or use an existing one<br \/>\n* <a href=\"https:\/\/slack.com\/intl\/en-in\/help\/articles\/201402297-Create-a-channel\">Created a Slack channel<\/a> or use an existing one<\/p>\n<h5>3.1) Create a Slack Webhook<\/h5>\n<p>Slack apps can automate many activities and have access to APIs and webhooks. We will use an Incoming Webhook which are useful to send messages from external sources to a Slack channel.<\/p>\n<p>i) Navigate to <a href=\"https:\/\/api.slack.com\/apps?new_app\">https:\/\/api.slack.com\/apps?new_app<\/a> and choose to create a new app from Scratch. You could also use an existing app you have. Provide a name and select your workspace.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Name_workspace_selection-2.png\" data-rel=\"lightbox-image-10\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Name_workspace_selection-2.png\" alt=\"This screenshot shows providing a Slack app name and choosing a workspace\" width=\"400\" height=\"384\" class=\"alignnone size-full wp-image-16493\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Name_workspace_selection-2.png 400w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Name_workspace_selection-2-300x288.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<p>ii) On the Basic Information page, click on Incoming Webhooks. Use the &#8216;Activate Incoming Webhooks&#8217; toggle button to enable posting messages feature.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Add_new_webhook-2.png\" data-rel=\"lightbox-image-11\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Add_new_webhook-2.png\" alt=\"This screenshot shows enabling the toggle button to allow incoming webhooks\" width=\"420\" height=\"138\" class=\"alignnone size-full wp-image-16494\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Add_new_webhook-2.png 420w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Add_new_webhook-2-300x99.png 300w\" sizes=\"auto, (max-width: 420px) 100vw, 420px\" \/><\/a><\/p>\n<p>iii) Scroll down to &#8216;Webhook URLs for Your Workspace&#8217; section and click on &#8216;Add New Webhook to Workspace&#8217; button. Choose the channel on which you want notifications to be received.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/provide_channel_info-1.png\" data-rel=\"lightbox-image-12\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/provide_channel_info-1.png\" alt=\"This screenshot shows selecting a Slack channel\" width=\"370\" height=\"233\" class=\"alignnone size-full wp-image-16495\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/provide_channel_info-1.png 370w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/provide_channel_info-1-300x189.png 300w\" sizes=\"auto, (max-width: 370px) 100vw, 370px\" \/><\/a><\/p>\n<p>iv) A new Webhook URL will be generated which can be used to post messages on the channel. Ensure that you do not share this with anyone. <\/p>\n<p>We will use this Webhook for in Slack notification action. Let us do that next. <\/p>\n<h5>3.2) Add Slack notification action to Checkpoint<\/h5>\n<p>To be able to trigger slack notifications after a Checkpoint run, we need to the associated action to the list of checkpoint actions. In the <strong>github_stats_checkpoint.yml<\/strong> present under Checkpoints folder, go to the action_list, and add the following code. The action uses SlackRender class provided by Great Expectations which has the Slack integration code. Here, we need to provide the Webhook we created earlier. We will use a placeholder text (Eg, SECRET_SLACK_WEBHOOK) for our secret here. And substitute this with our actual Webhook URL stored as GitHub secret. We will take a look at that next. <\/p>\n<pre lang=\"python\">\r\n  - name: send_slack_notification_on_validation_result\r\n    action:\r\n      class_name : SlackNotificationAction\r\n      slack_webhook: SECRET_SLACK_WEBHOOK\r\n      notify_on: all \r\n      notify_with: \r\n      renderer:\r\n        module_name: great_expectations.render.renderer.slack_renderer\r\n        class_name: SlackRenderer\r\n\r\n<\/pre>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/action_checkpoint_code_snippet.png\" data-rel=\"lightbox-image-13\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/action_checkpoint_code_snippet.png\" alt=\"\" width=\"600\" height=\"385\" class=\"alignnone size-full wp-image-16463\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/action_checkpoint_code_snippet.png 600w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/action_checkpoint_code_snippet-300x193.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<h5>3.3) Create a GitHub Secret for the Webhook<\/h5>\n<p>As we just discussed, we need to place our Webhook URL as a secret. To do that, in your GitHub repository, navigate to Settings -> Secrets -> Actions secrets and add a New repository secret. Place your Webhook URL here.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/new_action_repo_secret-2.png\" data-rel=\"lightbox-image-14\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/new_action_repo_secret-2.png\" alt=\"\" width=\"700\" height=\"96\" class=\"alignnone size-full wp-image-16496\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/new_action_repo_secret-2.png 700w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/new_action_repo_secret-2-300x41.png 300w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>I gave my secret name as &#8216;VALIDATION_NOTIFICATION_SLACK_WEBHOOK&#8217;<\/p>\n<h5>3.4) Use the Webhook in GitHub Action<\/h5>\n<p>Remember the placeholder variable (SECRET_SLACK_WEBHOOK) we used in our Checkpoint file earlier? We need to substitute it with our Webhook URL present as GitHub secret. To do that, I used <a href=\"https:\/\/www.gnu.org\/software\/sed\/manual\/sed.html#Introduction\">sed<\/a> to do a simple search and replace.<\/p>\n<pre lang=\"python\">\r\nreplace_webhook=$(printf '%s\\n' ${{ secrets.VALIDATION_NOTIFICATION_SLACK_WEBHOOK }} | sed -e 's\/[\\\/&]\/\\\\&\/g')\r\nsed -i \"s\/SECRET_SLACK_WEBHOOK\/$replace_webhook\/g\" great_expectations\/checkpoints\/github_stats_checkpoint.yml\r\n<\/pre>\n<p>Go to the GitHub workflow (<strong>github_stats_run.yml<\/strong> file) we defined earlier, and add the above code to the <strong>Run Checkpoint<\/strong> step.<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_with_slack_webhook.png\" data-rel=\"lightbox-image-15\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_with_slack_webhook.png\" alt=\"\" width=\"950\" height=\"142\" class=\"alignnone size-full wp-image-16505\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_with_slack_webhook.png 950w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_with_slack_webhook-300x45.png 300w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/run_checkpoint_with_slack_webhook-768x115.png 768w\" sizes=\"auto, (max-width: 950px) 100vw, 950px\" \/><\/a><\/p>\n<p>Refer to the complete <strong>github_stats_run.yml<\/strong> script <a href=\"https:\/\/gist.github.com\/sravantit25\/103447095dbef8bfb7f21d72c65b829b\">here<\/a>.  <\/p>\n<h5>3.5) Test the notification<\/h5>\n<p>After adding the Slack notification functionality, let us trigger the workflow again and verify if a notification has come up in Slack. Check the Slack channel which you have configured while creating the webhook. We can see summary of our validation run in the notification message:<\/p>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Slack_success_notification-1.png\" data-rel=\"lightbox-image-16\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Slack_success_notification-1.png\" alt=\"This screenshot shows the Success notification received in Slack Channel\" width=\"600\" height=\"343\" class=\"alignnone size-full wp-image-16498\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Slack_success_notification-1.png 600w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2022\/05\/Slack_success_notification-1-300x172.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>We will look at the Data Docs later. The link is the default location which we cannot access right now since it is run inside the GitHub Action runner.<\/p>\n<h4>4. Store Results<\/h4>\n<p>The results from Checkpoint run are shown in form of Data Docs. It is structured documentation consisting of information about the validation run. When we ran our Checkpoint using GitHub Action, the Data docs generated cannot be accessible outside. So, we need to host these on any static site such as <a href=\"https:\/\/www.netlify.com\/\">Netlify<\/a>. We will see how to do that in the next blog.<\/p>\n<hr>\n<h3>Preparing your team<\/h3>\n<p>SKIP THIS SECTION IF YOU ALREADY HAVE BUY-IN FROM YOUR TEAM!<br \/>\nJust having the technical capabilities to run your tests in the CI\/CD pipeline is not enough to ensure your test automation efforts with Great Expectations are going to succeed. In my experience, most teams resist having to do the work needed to roll out test automation properly. In fact, this resistance is so common that I think it is worth dedicating a section to help you plan this stage out! <\/p>\n<p>The number one reason we fail to introduce this kind of thinking into our teams, even when we try, is because we are poorly prepared to make a case for it. We do not take time to lay the groundwork for your team to accept a new idea. Neither do we prepare arguments required to convince the various stakeholders that adding one small test to the CI\/CD pipeline is the best use of the team&#8217;s time. <\/p>\n<p>From a tester&#8217;s perspective, before we start writing out more tests, it makes sense to get our first test up and running with the CI\/CD pipeline. But that is far easier said than done because this is a truly collaborative step in the process. As testers, we would most probably have limited to no access to different environments. So, we need to rely on developers, DevOps to help us along the way. Also, we might want input about the tests from our product owners. So, there is some preparatory work we need to do before adding our tests in the deployment pipeline. <\/p>\n<p>Here are some things you can try to prepare for before you propose this idea. I might not have the answer for all these as they are highly contextual. But I am listing out some considerations and my thoughts about them just in case they apply to you as well.<\/p>\n<h5>a) Prepare to defend the use Great Expectations as a tool<\/h5>\n<p>Some folks might point to other kinds of alerting and monitoring that could be used &#8211; why put in so much effort? For example, even within Qxf2, we use CloudWatch alerts as part of our data collection process. In my opinion, Great Expectations can be extended to go beyond just the surface level checks that are usually applied on data, say in form of constraints. It provides a good platform to try out different kinds fuzzy checks as well. In addition, it allows us to democratize our tests and get more people involved in testing. When speaking to your managers or engineering leaders, do not fail to stress the last point! They love hearing ideas for making more people within the team write tests.<\/p>\n<h5>b) Set expectations within the team<\/h5>\n<p>You are going to be introducing a new check into the CI\/CD pipeline. Most folks within your team are NOT going to have context about it. They are likely to ignore failures and think it is your responsibility alone. Make sure you tell your team what to expect. Tell them the benefits. Ask them for feedback. And help them understand what they should do if they notice a failure message. Repeat the context multiple times if you have to. The worst thing that can happen to such an effort is that nobody pays attention except the QA team!<\/p>\n<h5>c) Prepare arguments for drawbacks of the test<\/h5>\n<p>Folks are going to point out that this test barely does anything. That the test is not efficient. Also, the Slack messages are not user-friendly enough, etc. Keep arguments prepared. In most cases, tell them this is still an early version that still delivers more value than not having the test itself. And that over time, you will be addressing these concerns.<\/p>\n<h5>d) Have a discussion around version control<\/h5>\n<p>I do not yet have a good answer to where your tests have to be housed. For example, your Great Expectations tests could be part of whatever repositories house the data collection code. It could also be a separate repo. This decision will really depend on how your application code has been organized. If you are struggling with this point, just ask a developer. They can advice you.<\/p>\n<hr>\n<h3>Next Steps<\/h3>\n<p>We have our test running and setup notifications regarding for it. Next, we will take a look using Data Docs to view the results. Also, we will try to customize our notifications to add more details about the test. Thanks for reading and keep an eye out for the next one!<\/p>\n<hr>\n<h3>References<\/h3>\n<p>1. <a href=\"https:\/\/docs.greatexpectations.io\/docs\/guides\/validation\/checkpoints\/how_to_create_a_new_checkpoint\">How to create a new Checkpoint in Great Expectations<\/a><br \/>\n2. <a href=\"https:\/\/api.slack.com\/messaging\/webhooks#\">Sending Slack messages using Incoming Webhooks<\/a><br \/>\n3. <a href=\"https:\/\/docs.greatexpectations.io\/docs\/guides\/validation\/validation_actions\/how_to_trigger_slack_notifications_as_a_validation_action\/\">Trigger Slack notifications as an Action<\/a><\/p>\n<hr>\n","protected":false},"excerpt":{"rendered":"<p>In this post, we will help you run one Great Expectations test as part of your CI\/CD pipeline using GitHub Actions. This post is second in our series to help testers implement useful tests with Great Expectations for data validation. If your instinct says that adding a single test to a CI\/CD pipeline should not be the next part, read [&hellip;]<\/p>\n","protected":false},"author":27,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[314,313],"tags":[],"class_list":["post-16461","post","type-post","status-publish","format-standard","hentry","category-data-testing","category-great-expectations"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/16461","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/27"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=16461"}],"version-history":[{"count":42,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/16461\/revisions"}],"predecessor-version":[{"id":16541,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/16461\/revisions\/16541"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=16461"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=16461"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=16461"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}