GitHub Actions - How to trim a string in a condition? - github-actions

How can I trim a string in a condition in GitHub actions workflow?
In the following example, the comment can contains accidentally spaces and new lines. I want to trim the spaces in github.event.comment.body:
steps:
- name: "Check CLA signed"
if: github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA'

NOTE: Skip to the end for a better answer.
I believe GitHub Actions expressions are very limited to checking basic things in a workflow, rather than offering programming capabilities.
If you need to go the route of checking different ways of writing a message, your best option is to run a check against the string in a step:
steps:
...
- name: Check if person has accepted and signed CLA
shell: python
run: |
import sys
def check_user_accepted_and_signed(text):
"""Some complex natural language processing will go here"""
comment = '''${{ github.event.comment.body }}'''
if not check_user_accepted_and_signed(comment):
sys.exit(1) # This will abort the job
- name: Not accepted or signed
if: ${{ failure() }}
run: optionally do something if the check fails
- name: Move on if the check passed
run: ...
In the code above, you could also replace the inline Python snippet with a script call from your code base, for a cleaner code:
steps:
- uses: actions/checkout#v3
- name: Check if person has accepted and signed CLA
run: ./scripts/check-accepted-signed-cla.sh '${{ toJSON(github.event.comment.body) }}'
# Single quotes and JSON string prevents bad whitespace interpretation
Simpler is usually better
IMHO though, you'd be better off -- and safer! -- doing simple things. Here's an idea:
Set up your GitHub repository with a default pull request body containing a checkbox, for example:
Write your description.
---
- [ ] I have read the CLA and hereby sign it.
In your workflow, check for that checkbox and fail if it's not checked. Shopify/task-list-checker can be of great help here!

You can find all functions that github actions support here
I think you can use contains function for cover your case

Related

Parsing a comment made by "github-actions" bot into JSON

On every pull request that has a specific label our github-actions bot makes an automatic comment that includes a template which needs to be edited by the PR approver, before it can be merged.
The template the bot comments is as follows:
**Hello, #${{ github.actor }}!**
**This component is critical!**
**Edit and input the following BEFORE approving the PR!**
___
* Description: XXXXXXXXXX
* Justification: XXXXXXXXXX
The last change was authored by:
#${{ github.event.pull_request.user.login }}
The Description and Justification fields are replaced with actual values manually by the PR approver (it is not possible to know these in advance). Their values need to be saved as: change_description and justification to be stored in a .json file like so:
{"change_date": "<Date when PR Merged>", "change_id": "<Pull Request Link>", "change_description": "<from PR Comment>", "component": "<from terragrunt.hcl file>", "justification": "<from PR Comment>", "team": "<from terragrunt.hcl file>"}
I've gotten as far as saving the comment body as an environment variable in a new Github action, where I want to parse the comment and save it into a .json file:
env:
BODY: ${{ github.event.comment.body }}
All of the logic so far as been simple enough, but now I cannot find a way to pull the values of the Description and Justification from the comment body after they are edited manually. Is this not possible via Github Actions?
Yes it's possible in GitHub Actions.
You have to use regular expressions and bash to parse desired values.
Here is example of regexp to get one of your variables:
\*\*Hello, (.*)\*\*
https://regex101.com/r/Wfww5Y/1
End then in bash you can do:
[[ $body =~ $regex ]]
$ echo ${BASH_REMATCH[1]}

Triggering action by PR comment - action dosn't return status

I have strange issue with github action, let me describe step by step:
Assumption:
Creating PullReqest -> manually verification by some specific text in PR comment like "ok" -> PR can be merged.
I decided to use gihub action + setting in branch protection like:
Require status checks to pass before merging
Where is problem:
After creation PR, github action is triggered by right comment, but status is not returned to PR.
Looks like:
Some checks haven’t completed yet
1 expected check
deploy Expected — Waiting for status to be reported
I used example from:
https://github.community/t/trigger-a-github-workflow-if-it-matches-a-particular-comment-in-the-pull-request/116402/2
I also tried to use Github API by POST status, like described here:
Github says "Waiting for status to be reported" for a valid existing job
Do you have some experience or idea why the status is not updated?
If I use other trigger like:
on: pull_request: types: [opened]
works good.
Here's an example:
name: PR commented
on: issue_comment
jobs:
pr:
if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, 'ok') }}
runs-on: ubuntu-latest
steps:
- name: Print
run: |
echo "It's OK!"

What is the difference between 'name' and 'id' in Github Actions

In the github action for Google app engine deploy there is a reference to the id in a github action:
- id: Deploy
uses: google-github-actions/deploy-appengine#main
with:
credentials: ${{ secrets.GCP_SA_KEY }}
But the Github Actions examples don't refer to id, rather it refers to the name as the id:
Each job must have an id to associate with the job. The key job_id is a string and its value is a map of the job's configuration data. You must replace <job_id> with a string that is unique to the jobs object. The <job_id> must start with a letter or _ and contain only alphanumeric characters, -, or _.
jobs:
my_first_job:
name: My first job
my_second_job:
name: My second job
What's the difference?
I believe you are confusing between a step definition, and a job definition.
This is a step:
steps:
- id: deploy
uses: google-github-actions/deploy-appengine#main
with:
credentials: ${{ secrets.gcp_credentials }}
as can be seen in the Usage section of the deploy-appengine repository.
The GitHub Actions workflow syntax documentation is the definitive guide - if you see something written elsewhere that is not mentioned in this guide, it is either a mistake or a misunderstanding.
As for the difference between ID and Name (both in jobs and steps):
ID is used as a reference, from other jobs or steps (for example, in jobs.<job_id>.needs).
Name is used for display purposes on GitHub.
Finally, for completeness, here are the ID/name related entries in the GitHub workflow syntax:
name: Test # <- Workflow name
jobs:
test: # <- Job ID
name: Run test suite # <- Optional Job Name
steps:
- id: checkout # <- Optional step ID
name: Checkout code # <- Optional step name

Ansible - Access tags at run time

How can I access the tags and skip-tags passed via command line to an ansible playbook at run time?
I am trying to achieve a with_items loop that can skip or include items based on tag/skip-tag using a when clause. This previous SO question touches on the same topic but takes a different approach.
I would evaluate the existence of a tag per iteration.
For example:
- name: Build docker images
docker_image:
name: "{{item.name}}"
path: "{{build_folder}}/dockerfiles/{{item.name}}"
dockerfile: "{{item.name}}.Dockerfile"
state: build
tag: "{{private_docker_registry}}/{{item.name}}"
when: "{{ansible_host_vars['tags'][image1]}}" is defined
with_items:
- image1
- image2
- image3
Since 2.5, ansible added some magic variables to access at runtime. Some of them is ansible_run_tags. It seems to be what you needed.
Ref: Ansible 2.5 change logs
Tags are not available at runtime. Tags define what tasks will be executed. You can use this to translate tags to facts:
- set_fact:
image1: True
tags: image1
- set_fact:
image2: True
tags: image2
- set_fact:
image3: True
tags: image3
Now you have facts corresponding to your tags and can use them in your condition:
...
when: hostvars[inventory_hostname][item] == True
with_items:
- image1
- image2
- image3
But for me this feels wrong. This is not the purpose of tags. Tags should not define what software is installed on a host. This should be defined in your group/host vars. Tags then should simply limit the play to a subset of tasks, for example to update packages, to restart services, etc.
Beside tags you could archive the same with extra-vars. This also gives you more control. If you call your playbook without any tags provided, all tasks will be executed.

Complex stdout check in Ansible

I run a job on a remote server with Ansible. The stdout generates some output where sometimes errors show up. The error text is in the form of
#ERROR FMM0129E The following error was returned by the vSphere(TM) API: 'Cannot complete login due to an incorrect user name or password.'.
The thing is that some of these errors can safely be ignored and only these that are not in my false positive list should raise a fail.
My question is, can this be done in a pure Ansible way?
The only thing that comes to mind is the simple failed_when check which, in this case, falls short. I am thinking that these "complex" output checking should be done out of Ansible, invoking a python / shell / etc. script to help.
If you are remotely executing a shell command anyway then there's no reason why you couldn't wrap that in a shell script that returns a non 0 status code for the things you care about and then simply execute that via the script module.
example.sh
#!/bin/bash
randomInt=$[ 1 + $[ RANDOM % 10 ]]
echo $randomInt
if [ $randomInt == 1 ]; then
exit 1
else
exit 0
fi
And then use it like this in your playbook:
- name: run example.sh
script: example.sh
Ansible will automatically see any non 0 return codes as the task failing.
Instead of failed_when you could use ignore_errors: true which would get you into the position of passing the failing task and forwarding the stdout to another task. But I would not recommend this, since in my opinion a task should never ever report a failed state by intend. But if you feel this is an option for you, there even would be a way to reset the error counter so the Ansible stats at the end are correct.
- some: task
register: some_result
ignore_errors: true
- name: Reset errors after intentional fail
meta: clear_host_errors
when: some_result | failed
- another: task
check: "{{ some_result.stdout }}
when: some_result | failed
The last task then would check your stdout in a custom script or whatever you have and should report a failed state itself (return code != 0).
As far as I know the clear_host_errors feature is yet undocumented and the commit is about a month old, so I guess it will only be available in Ansible 2.0.1.
Another idea would be to wrap your task inside the script which checks the output or pipe it to that script. That obviously will only work if you run a shell command and not with any other ansible modules.
Other than those two options I don't think there is anything else available.