Github actions echo command not creating file - github-actions

I'm in the process of moving a working CircleCI workflow over to Github Actions.
I'm running:
runs-on: ubuntu-latest
container:
image: google/cloud-sdk:latest
I run the following command:
echo ${{ secrets.GCLOUD_API_KEYFILE }} > ./gcloud-api-key.json
Before running this command, gcloud-api-key.json has not yet been created. This command works in CircleCI but in Github Actions I get the error:
/__w/_temp/asd987as89d7cf.sh: 2: /__w/_temp/asd987as89d7cf.sh: type:: not found
Does anyone know what this error means?

The reason was because my secret key was more then 1 line long. Once I made it one line it worked.

In order to use secrets which contain more than just one line (like secret jsons) one has to save the base64 encoded secret in Github which makes it one line.
On linux the encoding is done via:
cat mysecret.json | base64
Then in the action you need to decode it using
echo ${{ secrets.YOUR_SECRET }} | base64 -d > secret.json

Related

How to safely write json output to a file in a github workflow?

I have a github workflow that obtains information about all Github Releases in my repo and then processes the JSON response using jq. The issue is the shell code I have doesn't handle single-quotes in the JSON data (which it does have sometimes). How can I pipe out steps.release.outputs.data safely to a file without the quotations and other characters being interpreted by the shell?
- name: Get Release Info
uses: octokit/request-action#v2.x
id: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
route: GET /repos/{org_repo}/releases/tags/{tag}
- name: Get Information from Release
run: |
echo '${{ steps.release.outputs.data }}' > release.json
jq -r '.assets[].browser_download_url' release.json > assets.txt
jq -r '.body' release.json > changelog.txt
The part that fails above is the line with echo in the second step. Because the steps.release.outputs.data content has single-quotes in it, that breaks it.
Note that, I only write the JSON data to a file (release.json in the example above) in an attempt to bypass shell processing special characters in the data. If there's a better way to do this without writing to a file I'd prefer that. The part that makes this challenging is that the response JSON gets placed into the final shell script as a literal string instead of as a bash variable.
You can use an environment variable:
- name: Get Information from Release
env:
DATA: ${{ steps.release.outputs.data }}
run: |
jq -r '.assets[].browser_download_url' <<<"$DATA" > assets.txt
jq -r '.body' <<<"$DATA" > changelog.txt

Is it possible to specify image used in steps according to the matrix strategy?

I'm going to setup a workflow on GitHub which uses some docker images to check my package on different platform. I'd like to use the matrix strategy. Then I wrote a workflow like this:
name: Main Workflow
on: [push]
jobs:
test_linux:
runs-on: ubuntu-latest
strategy:
matrix:
image: [ubuntu, fedora]
steps:
- name: Checkout
uses: actions/checkout#v3
- name: Test
uses: docker://${{ matrix.image }}:latest
with:
entrypoint: /bin/bash
args: ./test.sh
This is just a demo workflow. The real one is much more complicated.
However, after I pushed it, GitHub gave me the following error message:
Invalid workflow file: .github/workflows/main.yml#L16
The workflow is not valid. .github/workflows/main.yml (Line: 13, Col: 15): Unrecognized named-value: 'matrix'. Located at position 1 within expression: matrix.image
Actually, I got this error instantly when I pushed codes.
Why? Is the matrix context inaccessible when parsing workflow file? Are there some ways to resolve it?
I tried to export the full docker name to environment in the previous step before "Test", but context env is also inaccessible just like the context matrix. I got nearly the same error. The only different is:
Unrecognized named-value: 'env'...
Now I have to call docker run manually in run scripts like
steps:
- name: Test
run: docker run --rm -v $(pwd):/code --workdir=/code ${{ matrix.image }}:latest /bin/bash -c "/code/test.sh"
It did work but I still prefer to use the uses entry.

yq - inserting JSON as a raw string

I am writing a GitHub Action that does some CD and it uses yq to insert environment variables into a yaml file for deployment.
I'm trying to read a JSON from a GH secret that will eventually be read from env and loaded into python, where said string will be evaluated as a dictionary.
Running this in a terminal, for example:
yq -i '.value="{\"web\": \"test\"}"' test.yaml
Gives me:
value: '{"web": "test"}'
But in a Github Action, where I am doing this:
env:
JSON="{\"web\": \"test\"}"
...
- name: test
run : |
yq -i '
.value=strenv(JSON)
' deployment.yaml
Gives me:
Error: Bad expression, please check expression syntax
Doing other variations of that string, e.g. '{\"web\": \"test\"}', '\"{\"web\": \"test\"}\"' etc also gives me the same error.
I've tried searching on the yq repository and consulted the documentation but can't seem to find what I am looking for.
To summarise, my problem is that I want to read a JSON string as a string when it is evaluated by yq.
One of yq users has recently contributed to yq's github action docs regarding using env variables in github actions - it may help here:
- name: Get an entry with a variable that might contain dots or spaces
id: get_username
uses: mikefarah/yq#master
with:
cmd: yq '.all.children.["${{ matrix.ip_address }}"].username' ops/inventories/production.yml
- name: Reuse a variable obtained in another step
run: echo ${{ steps.get_username.outputs.result }}
See https://mikefarah.gitbook.io/yq/usage/github-action for more info.
Disclaimer: I wrote yq

Rename a file based on release

I'm trying to rename a file when a new release is tagged, but it is failing.
- name: rename file
run: mv ./Code/.pio/build/attiny841/firmware.hex ./Code/.pio/build/attiny841/megadesk-${{ $GITHUB_REF_NAME }}.hex
However when it runs I get an error
Invalid workflow file: .github/workflows/version_pio_build.yml#L44
The workflow is not valid. .github/workflows/version_pio_build.yml (Line: 44, Col: 12): Unexpected symbol: '$GITHUB_REF_NAME'. Located at position 1 within expression: $GITHUB_REF_NAME
If I change this to
- name: rename file
run: mv ./Code/.pio/build/attiny841/firmware.hex ./Code/.pio/build/attiny841/megadesk-${{ env.GITHUB_REF_NAME }}.hex
Then the resulting execution is
mv ./Code/.pio/build/attiny841/firmware.hex ./Code/.pio/build/attiny841/megadesk-.hex
Note this is triggered on a tag push.
- name: env list
run: env
This has a list of variables including
...
RUNNER_TOOL_CACHE=/opt/hostedtoolcache
ImageVersion=20220220.1
DOTNET_NOLOGO=1
GITHUB_REF_NAME=v25
GRAALVM_11_ROOT=/usr/local/graalvm/graalvm-ce-java11-22.0.0.2
GITHUB_JOB=build
AZURE_EXTENSION_DIR=/opt/az/azcliextensions
...
Your problem here is that you used the wrong syntax.
Neither ${{ $GITHUB_REF_NAME }} nor ${{ env.GITHUB_REF_NAME }} will work, but just $GITHUB_REF_NAME will.
Therefore, your command line should be:
run: mv ./Code/.pio/build/attiny841/firmware.hex ./Code/.pio/build/attiny841/megadesk-$GITHUB_REF_NAME.hex
If you want to take a look, here is a demo:
Workflow file: https://github.com/GuillaumeFalourd/poc-github-actions/blob/main/.github/workflows/49-rename-on-release.yml
Workflow run: https://github.com/GuillaumeFalourd/poc-github-actions/runs/5359686796?check_suite_focus=true

GitHub Action Get Commit Message

So I am building an action that does a build for a project that will go to Netlify. In the action I can pass a deploy message. In that deploy message, I want to pass in the commit message of the commit that triggered the build. I was looking at documentation but could not find if this is possible. Thanks
You can get this in the github context for the action, as described here.
The event key will give you the webhook content, as defined here.
So, for your action, you can use something like:
${{ github.event.head_commit.message }}
You can get the concrete commit message with the following command:
github.event.head_commit.message
Or it is possible to get the commit messages with the git log command if you use bash:
git log -1 --pretty=format:"%s"
Update: With regard to the documentation, the payload and thus also the call of the commit message can get with the commits array if there is only one commit. The message can be fetched with the following line in the GitHub action:
github.event.commits[0].message
There is a small difference between the two:
${{ github.event.commits[0].message }}
When the github push event contains several commits, commit[0] contains the oldest commit. I have seen this after a merge.
${{ github.event.head_commit.message }}
On the other hand, the head_commit contains the youngest commit.
The commit-message is available on the following keys:
${{ github.event.commits[0].message }}
${{ github.event.head_commit.message }}
There is quite a lot of other information available on events.
For ex; the following workflow will give you all that information:
# .github/workflows/logger.yaml
name: Event Loggger
on: push
jobs:
log-github-event-goodies:
name: "LOG Everything on GitHub Event"
runs-on: ubuntu-latest
steps:
- name: Logging
run: |
echo "${{toJSON(github.event)}}"
If you trying to access from a different workflow, ex:
on:
workflow_run:
workflows: Spec App
branches: master
types: completed // Only runs after spec is completed...
You have to use:
${{ github.event.workflow_run.head_commit.message }}
In case someone landed here for a quick solution. The ${{ github.event.head_commit.message }} is still working fine. FYI.
Here is a solution how to get message of a last commit in Pull Request for pull_request event:
---
name: 'How to get commit message'
on:
pull_request:
types:
- edited
- opened
- synchronize
jobs:
get_message:
name: 'Get commit message'
runs-on: ubuntu-latest
permissions:
# this permission should be set to be able use secrets.GITHUB_TOKEN
id-token: write
# not sure if this permission is necessary, just didn't try to remove it when testing
contents: read
# this permission should be set to be able get commits data by curl request
pull-requests: read
steps:
- name: Get commits
env:
# github URL to list commits
COMMITS_URL: ${{ github.event.pull_request.commits_url }}
run: |
if [ "${COMMITS_URL}x" != "x" ]; then
# get commits list and pick up last one by jq
# caution: only 100 commits will be taken by curl
# if your PR has more than 100 commits
# you have to set page query parameter
# and request last page commits
# API URL details: https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28#list-commits-on-a-pull-request
LAST_MSG=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "${COMMITS_URL}?per_page=100" | jq -r .[-1].commit.message)
# set environment variable
echo "LAST_MSG=${LAST_MSG}" >> "${GITHUB_ENV}"
else
echo 'LAST_MSG=' >> "${GITHUB_ENV}"
fi
When Get commits step will be completed, commit message may be get from LAST_MSG environment variable