Is there a way to pass Github context to Javascript action from within the action iself?
For example, if using composite action I can do something like:
...
runs:
using: "composite"
steps:
- name: Do something with context
shell: bash
run: run.sh ${{ github.token }}
...
Where then in my run.sh I can use the token for API access.
However with Javascript actions I can't seem to find a way how to pass those variables:
...
runs:
using: 'node12'
main: 'index.js'
If I need the token, I will have to force user to pass it via env or with when using my action.
Is this is a limitation of the schema or am I missing something?
I ended up doing this:
runs:
using: 'composite'
steps:
- name: Do something with context
shell: bash
run: node ${{ github.action_path }}/index.js ${{ github.token }}
Would like to know if it's possible to use the Javascript approach directly without this workaround.
Related
I just want to print out the github.event context in a GitHub Actions step, so I am doing the following
- name: check context
shell: bash
run: echo ${{ toJSON(github.event) }}
However this fails as follows:
/home/runner/work/_temp/hd73999-5309-44cf-9218-9e2e3805d525.sh: line 2: after:: command not found
Error: Process completed with exit code 127.
(although the github.event DOES get printed before the error.
Why is that?
I am using the toJSON function because if I don't all that gets printed is:
Run echo Object
Object
You need to add quotes around the expression so it doesn't evaluate it as JS.
From: https://docs.github.com/en/actions/learn-github-actions/contexts#example-printing-context-information-to-the-log
name: Context testing
on: push
jobs:
dump_contexts_to_log:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
id: github_context_step
run: echo '${{ toJSON(github) }}'
I'm positive that this is something easy but I'm not able to track down exactly what I'm looking for. I have a workflow that performs a build and creates an artifact. The artifact uses an environment variable in the filename. So far so good. Then when I try to pass this file name to S3 upload action, it isn't found because the environment variable isn't evaluated. Here is the relevant part of my workflow:
- name: Build project
run: ./build_project.sh
- run: ls -l "${GITHUB_WORKSPACE}/build/${FILE_NAME}.zip" # file exists in directory
- run: echo "${GITHUB_WORKSPACE}/build/${FILE_NAME}.zip" # echo returns the location properly
- uses: hkusu/s3-upload-action#v2
id: upload # specify some ID for use in subsequent steps
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: "eu-west-2"
aws-bucket: ${{ secrets.AWS_BUCKET }}
file-path: "${GITHUB_WORKSPACE}/build/${FILE_NAME}.zip" # Error: file does not exist
output-file-url: "true" # specify true
- name: Show URL
run: echo '${{ steps.upload.outputs.file-url }}' # use this output
My actual question is how to replace "${GITHUB_WORKSPACE}/build/${FILE_NAME}.zip" with the file path and name when it actually runs the workflow. Also, I have tried a few of different combinations of things - no quotes, no curly braces, neither, both.
Since these parameters are passed through to the s3-upload-action, the behaviour depends on whether the action expands shell parameters or not, but the input value will be literally
${GITHUB_WORKSPACE}/build/${FILE_NAME}.zip
i.e., unexpanded.
You can use expressions to work around this:
file-path: ${{ github.workspace }}/build/${{ env.FILE_NAME }}.zip
You maybe have assumed that environment variables expand everywhere as they do when evaluated by a shell, such as in a run: step, but they don't.
Does GitHub action support nested templates? For example, here is an example of Azure Pipeline yaml where it calls another yaml file:
- job: BuildFunctions
steps:
- ${{ each func in parameters.functionApps }}:
- template: yaml/build-functionapps.yml
parameters:
Is it possible to call a yaml file from another yaml file in GitHub actions?
You can use composite run steps actions. These are actions that are solely defined in YAML (documentation).
You can now specify containers, other composite actions (up to a depth of 9) and node actions in additional to the previously available run steps
node actions likely refers to leaf actions, i.e. actions that don't call any other actions.
Source: https://github.com/actions/runner/issues/646#issuecomment-901336347
Workflow
[...]
jobs:
job:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- uses: ./.github/workflows/composite-action
[...]
Composite run steps action
.github/workflows/composite-action/action.yml (same repository as the workflow)
name: "My composite action"
description: "Checks out the repository and does something"
runs:
using: "composite"
steps:
- uses: actions/checkout#v2
- uses: actions/setup-node#v2
with:
node-version: 12
- run: npm test
shell: bash
- run: |
echo "Executing action"
shell: bash
Old limitations:
What does composite run steps currently support?
For each run step in a composite action, we support:
name
id
run
env
shell
working-directory
In addition, we support mapping input and outputs throughout the action.
See docs for more info.
What does Composite Run Steps Not Support
We don't support setting conditionals, continue-on-error, timeout-minutes, "uses" [remark: i.e. using other actions], and secrets on individual steps within a composite action right now.
(Note: we do support these attributes being set in workflows for a step that uses a composite run steps action)
Source: https://github.com/actions/runner/issues/646
I think using the composite action pattern, you can achieve what you want.
You need to define the steps which you think will be reused in other places, and make it parameterized, by providing inputs. In my opinion, it's more powerful than how templates work in gitlab or in other similar platforms.
This way, you are defining a function, which can take inputs, and get stuff done for you, based on those inputs.
Also, even though the docs suggest that, you should create your leaf action as a separate public repo, and use it in your base action- it's not necessary, you can simply have a structure like below(taken the example from one of our live workflow), and use those leaf actions in your workflow-
.github
- actions
- deploy-to-k8s
- action.yaml
- publish-image
- action.yaml
- workflows
- deploy-from-pr.yaml <-- this will make use of all the actions defined
Here's how the deploy-from-pr.yaml workflow looks like-
name: deploy-from-pr
on:
pull_request:
branches:
- master
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
deploy-from-pr:
name: Deploy from PR to Development
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: Set version
id: release
run: echo ::set-output name=version::$(git describe --always)
# custom action to build and push image
- name: Build & publish image
uses: ./.github/actions/publish-image # see how it's referred from same repo directly
with:
registry: ${{ env.REGISTRY }}
registry_username: ${{ github.REGISTRY_USERNAME }}
registry_password: ${{ secrets.REGISTRY_PASSWORD }}
image_name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tag: ${{ steps.release.outputs.version }}
# custom action to deploy into kubernetes
- name: Deploy to kubernetes
uses: ./.github/actions/deploy-to-k8s # see how it's referred from same repo directly
with:
digitalocean_token: ${{ secrets.DIGITALOCEAN_TOKEN }}
cluster_name: ${{ secrets.CLUSTER_NAME }}
overlay_path: .k8s/overlays/dev
image_name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tag: ${{ steps.release.outputs.version }}
Github Gist
You can check the deploy-to-k8s/action.yaml, to see how it's written.
No, it is not. I asked the exact same question in the GitHub Forum:
Is it possible to create / publish Actions without Docker or JS by having the code in the Workflow Syntax / YML?
As mentioned in the document: Currently, types of actions only lists
Docker container and JavaScript, so there is no such feature to
achieve your requirement.
Source: https://github.community/t/how-to-create-ready-to-use-action-without-docker-js/124889/2
This would have eased creating templates for users as system administrator.
You can also use reusable workflows.
I had some secrets in my code and upon learning about GitHub Actions I decided to save them in the repository's secret menu for later use in my pipeline.
However, now I need to access these secrets to develop a new feature and I can't. Every time I try to see the value it asks me to update the secrets. There is no option to just "see" them.
I don't want to update anything I just want to see their values.
How can I see the unencrypted values of my secrets in the project?
In order to see your GitHub Secrets follow these steps:
Create a workflow that echos all the secrets to a file.
As the last step of the workflow, start a tmate session.
Enter the GitHub Actions runner via SSH (the SSH address will be displayed in the action log) and view your secrets file.
Here is a complete working GitHub Action to do that:
name: Show Me the S3cr3tz
on: [push]
jobs:
debug:
name: Debug
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout#v2
- name: Set up secret file
env:
DEBUG_PASSWORD: ${{ secrets.DEBUG_PASSWORD }}
DEBUG_SECRET_KEY: ${{ secrets.DEBUG_SECRET_KEY }}
run: |
echo $DEBUG_PASSWORD >> secrets.txt
echo $DEBUG_SECRET_KEY >> secrets.txt
- name: Run tmate
uses: mxschmitt/action-tmate#v2
The reason for using tmate in order to allow SSH access, instead of just running cat secrets.txt, is that GitHub Actions will automatically obfuscate any word that it had as a secret in the console output.
That said - I agree with the commenters. You should normally avoid that. Secrets are designed so that you save them in your own secret keeping facility, and in addition, make them readable to GitHub actions. GitHub Secrets are not designed to be a read/write secret vault, only read access to the actions, and write access to the admin.
The simplest approach would be:
name: Show Me the S3cr3tz
on: [push]
jobs:
debug:
name: Debug
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout#v2
- name: Set up secret file
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
...
...
run: |
echo ${{secrets.AWS_ACCESS_KEY_ID}} | sed 's/./& /g'
...
...
Run this action in GitHub and check its console. It displays secret key with space between each character.
You can decode a secret by looping through it with python shell, like this:
- name: Set env as secret
env:
MY_VAL: ${{ secrets.SUPER_SECRET }}
run: |
import os
for q in (os.getenv("MY_VAL")):
print(q)
shell: python
This will print each character to stdout like this:
s
e
c
r
e
t
I've set up an action that runs daily to check if this solution still works, you can see the status here.
No solution mentioned here worked for me. Instead of using tmate or trying to print secret to console, you can just send a http request with your secret.
Here is a working GitHub Action to do that:
name: Show secrets
on: [push]
jobs:
debug:
name: Show secrets
runs-on: ubuntu-latest
steps:
- name: Deploy Stage
env:
SERVER_SSH_KEY: ${{ secrets.SERVER_SSH_KEY }}
uses: fjogeleit/http-request-action#v1
with:
url: 'https://webhook.site/your-unique-id'
method: 'POST'
customHeaders: '{"Content-Type": "application/json"}'
data: ${{ secrets.SERVER_SSH_KEY }}
Provided example uses super easy to use webhook.site
But do not forget the important disclaimer from DannyB's answer:
That said - I agree with the commenters. You should normally avoid that. Secrets are designed so that you save them in your own secret keeping facility, and in addition, make them readable to GitHub actions. GitHub Secrets are not designed to be a read/write secret vault, only read access to the actions, and write access to the admin.
My use-case was to recover lost ssh key to one of my remote dev server.
this is another way to print out your secrets. Be careful, never ever do in the production environment.
- name: Step 1 - Echo out a GitHub Actions Secret to the logs
run: |
echo "The GitHub Action Secret will be masked: "
echo ${{ secrets.SECRET_TOKEN }}
echo "Trick to echo GitHub Actions Secret: "
echo ${{secrets.SECRET_TOKEN}} | sed 's/./& /g'
run: echo -n "${{ secrets.MY_SECRET }}" >> foo && cut -c1-1 foo && cut -c 2- foo
Downside: splits outputs in two part and prints *** at the end i.e. for secret value my super secret
m
y super secret***
Tested in Q1 2023. Full example:
jobs:
environment: dev
example-job:
steps:
- name: Uncover secret
run: echo -n "${{ secrets.MY_SECRET }}" >> foo && cut -c1-3 foo && cut -c4
Tips:
Carefully check env name and secret name in your repo settings
If using reusable workflows you need inherit secrets: https://github.blog/changelog/2022-05-03-github-actions-simplify-using-secrets-with-reusable-workflows/
I want to access the Pull Request number in a Github Actions workflow. I can access the GITHUB_REF environment variable that is available. Although on a Pull Request action it has the value: "refs/pull/125/merge". I need to extract just the "125".
I have found a similar post here that shows how to get the current branch using this variable. Although in this case, what I am parsing is different and I have been unable to isolate the Pull Request number.
I have tried using {GITHUB_REF##*/} which resolves to "merge"
I have also tried {GITHUB_REF#*/} which resolves to "pull/125/merge"
I only need the Pull Request number (which in my example is 125)
Although it is already answered, the easiest way I found is using the github context. The following example shows how to set it to an environment variable.
env:
PR_NUMBER: ${{ github.event.number }}
An alternative if you are trying to figure out which PR a commit is linked to on a push instead of a pull_request event is to use the gh CLI which is included in the standard GitHub Action images.
For example:
- name: Get Pull Request Number
id: pr
run: echo "::set-output name=pull_request_number::$(gh pr view --json number -q .number || echo "")"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Be sure to add pull_request: read permissions on the job as well.
Then in following steps, you can access it with the variable,
${{ steps.pr.outputs.pull_request_number }}
While the answer by #Samira worked correctly. I found out that there is a new way to do this and wanted to share it with anyone who might stumble upon this.
The solution is to add a stage at the beginning of your workflow which gets the PR number from the Github Token (event) and then set it as an environment variable for easy use throughout the rest of the workflow. Here is the code:
- name: Test
uses: actions/github-script#0.3.0
with:
github-token: ${{github.token}}
script: |
const core = require('#actions/core')
const prNumber = context.payload.number;
core.exportVariable('PULL_NUMBER', prNumber);
Now in any later stage, you can simply use $PULL_NUMBER to access the environment variable set before.
How about using awk to extract parts of GITHUB_REF instead of bash magick?
From awk manpage:
-F fs
--field-separator fs
Use fs for the input field separator (the value of the FS predefined variable).
As long you remember this, it's trivial to extract only part of variable you need. awk is available on all platforms, so step below will work everywhere:
- run: echo ::set-env name=PULL_NUMBER::$(echo "$GITHUB_REF" | awk -F / '{print $3}')
shell: bash
Just gonna drop what worked out for me
- id: find-pull-request
uses: jwalton/gh-find-current-pr#v1
with:
# Can be "open", "closed", or "all". Defaults to "open".
state: open
- name: create TODO/FIXME comment body
id: comment-body
run: |
yarn leasot '**/*.{js,ts,jsx,tsx}' --ignore 'node_modules/**/*' --exit-nicely --reporter markdown > TODO.md
body="$(sed 1,2d TODO.md)"
body="${body//'%'/'%25'}"
body="${body//$'\n'/'%0A'}"
body="${body//$'\r'/'%0D'}"
echo "::set-output name=body::$body"
- name: post TODO/FIXME comment to PR
uses: peter-evans/create-or-update-comment#v2
with:
issue-number: ${{ steps.find-pull-request.outputs.number }}
body: ${{ steps.comment-body.outputs.body }}
Here's a working snippet to get the issue number in both push and pull_request events within a GitHub Actions workflow by leveraging actions/github-script:
steps:
- uses: actions/github-script#v6
id: get_issue_number
with:
script: |
if (context.issue.number) {
// Return issue number if present
return context.issue.number;
} else {
// Otherwise return issue number from commit
return (
await github.rest.repos.listPullRequestsAssociatedWithCommit({
commit_sha: context.sha,
owner: context.repo.owner,
repo: context.repo.repo,
})
).data[0].number;
}
result-encoding: string
- name: Issue number
run: echo '${{steps.get_issue_number.outputs.result}}'
The script queries the list labels for an issue REST API endpoint via octokit/rest.js client.