I have a workflow with an action that creates a version number when building an artefact. This version number is written to file.
How can I give that as an input to another action?
I.e: How can I use this version number as part of a commit message in another action?
Per the fabulous answer here, there's actually an inline way to accomplish this. Not intuitive at all, except that the ::set-output... syntax matches the same expected output format for GitHub Actions.
The below step loads the VERSION file into ${{ steps.getversion.outputs.version }}:
- name: Read VERSION file
id: getversion
run: echo "::set-output name=version::$(cat VERSION)"
I had the same use case as OP, so I'm pasting below my entire code, which does three things:
Pull first three-parts of the 4-part version string from the file VERSION.
Get a sequential build number using the einaregilsson/build-number#v2 action.
Concatenate these two into an always-unique 4-part version string that becomes a new GitHub release.
name: Auto-Tag Release
on:
push:
branches:
- master
jobs:
release_new_tag:
runs-on: ubuntu-latest
steps:
- name: "Checkout source code"
uses: "actions/checkout#v1"
- name: Generate build number
id: buildnumber
uses: einaregilsson/build-number#v2
with:
token: ${{secrets.github_token}}
- name: Read VERSION file
id: getversion
run: echo "::set-output name=version::$(cat VERSION)"
- uses: "marvinpinto/action-automatic-releases#latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: v${{ steps.getversion.outputs.version }}.${{ steps.buildnumber.outputs.build_number }}
prerelease: false
Fully automated release management! :-)
Note: The branch filter at top ensures that we only run this on commits to master.
It is possible to use the filesystem to communicate between actions. But if you have input on 3rd party actions, you need to give this from the outputs of another action
Ie. you need to read this file in your action and present it as output in your action.yml. Then you can use this output as input to another action in your workflow.yaml
The accepted answer is outdated as per this blog post from GitHub.
It is still possible to do this as one step from your workflow though:
- name: Read VERSION file
id: getversion
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
This will set an output named version which you can access just as before using ${{ steps.getversion.outputs.version }}:
- uses: "marvinpinto/action-automatic-releases#latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: v${{ steps.getversion.outputs.version }}.${{ steps.buildnumber.outputs.build_number }}
prerelease: false
Related
We merge everything to develop. Once a week we merge everything from develop to master. This weekly master merge contains 50+ commits from 10+ issues with 10+ pull requests. In our weekly master merge we want a description with all the related issues or related PRs. I tried different actions, tools or ways to do that. Now Im trying to use the devops-infra action-pull-request (which we already use for the weekly master merge). I tried using different actions where the output should be the related PRs and use this output in the body of your action. I tried using different outputs (url or PR number) of this action but nothing seems to work. The body is just always empty when I look into the logs. Is it a bug? Am I doing something wrong? Is it outdated? Here is my action:
name: weekly master merge
on:
workflow_dispatch:
jobs:
createPullRequest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v3
with:
fetch-depth: 0
- name: Release Changelog Builder
uses: buildsville/list-pull-requests#v1
id: list
with:
token: ${{ secrets.ALL }}
Labels: '["app/admin"]'
skip_hour: '24'
- name: Set output variables
id: vars
run: |
pr_title="Releases week #$(date +%W)"
body=${{ steps.list.outputs.pulls }}
echo "pr_title=$pr_title" >> $GITHUB_OUTPUT
echo "body=$body >> $GITHUB_OUTPUT
- name: Create Pull Request
uses: devops-infra/action-pull-request#v0.5.3
id: test
with:
github_token: ${{ secrets.ALL }}
source_branch: test
target_branch: main
title: ${{ steps.vars.outputs.pr_title }}
#body: ${{ steps.list.outputs.pulls }}
body: ${{ steps.vars.outputs.outval }}
#body: ${{ steps.test.outputs.* }}
#body: ${{ steps.test.outputs.url }}
It doesnt matter what I do, the PR from this action always has a body full of commits (default body of this action).
This is a test repository with a PAT with most of the permissions. Im just trying to change the body. The comments are some things I tested before but they didnt work either.
Im pretty new to all of this but for my understanding im doing everything correctly. Once again, I tried a bunch of different things...
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 want to use Github actions to transfer files to a remote server via SFTP (only option for this server) when I push up to Github.
I am using this Action https://github.com/marketplace/actions/ftp-deploy
I have created a file in my repo in .github/workflows/main.yml and I have added:
on: push
name: Publish Website
jobs:
FTP-Deploy-Action:
name: FTP-Deploy-Action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2.1.0
with:
fetch-depth: 2
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action#3.1.1
with:
ftp-server: ${{ secrets.FTP_SERVER }}
ftp-username: ${{ secrets.FTP_USERNAME }}
ftp-password: ${{ secrets.FTP_PASSWORD }}
I have created a Secret for this repo which contains the following:
FTP_SERVER: sftp.server.com, FTP_USERNAME: user, FTP_PASSWORD: password
I can see the action running in Github but it errors out on the FTP-Deploy-Action task.
##[error]Input required and not supplied: ftp-server
This is in secrets and does work with Filezilla.
Would anyone know if I've set this up wrongly?
I was able to get it working on my own repo. I think the issue may be possibly on how your secrets were setup. That error usually shows when required parameters of a github action were not provided so curious if the keys are different or whether they were saved as empty. I would delete FTP_SERVER secret and create it again to be sure.
Workflow Success Run
Workflow Code
- name: FTP-Deploy-Action
uses: SamKirkland/FTP-Deploy-Action#3.1.1
with:
ftp-server: ${{ secrets.FTP_SERVER }}
ftp-username: ${{ secrets.FTP_USERNAME }}
ftp-password: ${{ secrets.FTP_PASSWORD }}
local-dir: toupload
UPDATE: Added example per comment left below,
Example secret creation for reference. Basically create a secret per entry rather than comma separated grouped secret
Source: https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets
For (mainly) pedagogical reasons, I'm trying to run this workflow in GitHub actions:
name: "We 🎔 Perl"
on:
issues:
types: [opened, edited, milestoned]
jobs:
seasonal_greetings:
runs-on: windows-latest
steps:
- name: Maybe greet
id: maybe-greet
env:
HEY: "Hey you!"
GREETING: "Merry Xmas to you too!"
BODY: ${{ github.event.issue.body }}
run: |
$output=(perl -e 'print ($ENV{BODY} =~ /Merry/)?$ENV{GREETING}:$ENV{HEY};')
Write-Output "::set-output name=GREET::$output"
produce_comment:
name: Respond to issue
runs-on: ubuntu-latest
steps:
- name: Dump job context
env:
JOB_CONTEXT: ${{ jobs.maybe-greet.steps.id }}
run: echo "$JOB_CONTEXT"
I need two different jobs, since they use different context (operating systems), but I need to get the output of a step in the first job to the second job. I am trying with several combinations of the jobs context as found here but there does not seem to be any way to do that. Apparently, jobs is just the name of a YAML variable that does not really have a context, and the context job contains just the success or failure. Any idea?
Check the "GitHub Actions: New workflow features" from April 2020, which could help in your case (to reference step outputs from previous jobs)
Job outputs
You can specify a set of outputs that you want to pass to subsequent jobs and then access those values from your needs context.
See documentation:
jobs.<jobs_id>.outputs
A map of outputs for a job.
Job outputs are available to all downstream jobs that depend on this job.
For more information on defining job dependencies, see jobs.<job_id>.needs.
Job outputs are strings, and job outputs containing expressions are evaluated on the runner at the end of each job. Outputs containing secrets are redacted on the runner and not sent to GitHub Actions.
To use job outputs in a dependent job, you can use the needs context.
For more information, see "Context and expression syntax for GitHub Actions."
To use job outputs in a dependent job, you can use the needs context.
Example
jobs:
job1:
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
output1: ${{ steps.step1.outputs.test }}
output2: ${{ steps.step2.outputs.test }}
steps:
- id: step1
run: echo "test=hello" >> $GITHUB_OUTPUT
- id: step2
run: echo "test=world" >> $GITHUB_OUTPUT
job2:
runs-on: ubuntu-latest
needs: job1
steps:
- run: echo ${{needs.job1.outputs.output1}} ${{needs.job1.outputs.output2}}
Note the use of $GITHUB_OUTPUT, instead of the older ::set-output now (Oct. 2022) deprecated.
To avoid untrusted logged data to use set-state and set-output workflow commands without the intention of the workflow author we have introduced a new set of environment files to manage state and output.
Jesse Adelman adds in the comments:
This seems to not work well for anything beyond a static string.
How, for example, would I take a multiline text output of step (say, I'm running a pytest or similar) and use that output in another job?
either write the multi-line text to a file (jschmitter's comment)
or base64-encode the output and then decode it in the next job (Nate Karasch's comment)
Update: It's now possible to set job outputs that can be used to transfer string values to downstream jobs. See this answer.
What follows is the original answer. These techniques might still be useful for some use cases.
Write the data to file and use actions/upload-artifact and actions/download-artifact. A bit awkward, but it works.
Create a repository dispatch event and send the data to a second workflow. I prefer this method personally, but the downside is that it needs a repo scoped PAT.
Here is an example of how the second way could work. It uses repository-dispatch action.
name: "We 🎔 Perl"
on:
issues:
types: [opened, edited, milestoned]
jobs:
seasonal_greetings:
runs-on: windows-latest
steps:
- name: Maybe greet
id: maybe-greet
env:
HEY: "Hey you!"
GREETING: "Merry Xmas to you too!"
BODY: ${{ github.event.issue.body }}
run: |
$output=(perl -e 'print ($ENV{BODY} =~ /Merry/)?$ENV{GREETING}:$ENV{HEY};')
Write-Output "::set-output name=GREET::$output"
- name: Repository Dispatch
uses: peter-evans/repository-dispatch#v1
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: my-event
client-payload: '{"greet": "${{ steps.maybe-greet.outputs.GREET }}"}'
This triggers a repository dispatch workflow in the same repository.
name: Repository Dispatch
on:
repository_dispatch:
types: [my-event]
jobs:
myEvent:
runs-on: ubuntu-latest
steps:
- run: echo ${{ github.event.client_payload.greet }}
In my case I wanted to pass an entire build/artifact, not just a string:
name: Build something on Ubuntu then use it on MacOS
on:
workflow_dispatch:
# Allows for manual build trigger
jobs:
buildUbuntuProject:
name: Builds the project on Ubuntu (Put your stuff here)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- uses: some/compile-action#v99
- uses: actions/upload-artifact#v2
# Upload the artifact so the MacOS runner do something with it
with:
name: CompiledProject
path: pathToCompiledProject
doSomethingOnMacOS:
name: Runs the program on MacOS or something
runs-on: macos-latest
needs: buildUbuntuProject # Needed so the job waits for the Ubuntu job to finish
steps:
- uses: actions/download-artifact#master
with:
name: CompiledProject
path: somewhereToPutItOnMacOSRunner
- run: ls somewhereToPutItOnMacOSRunner # See the artifact on the MacOS runner
It is possible to capture the entire output (and return code) of a command within a run step, which I've written up here to hopefully save someone else the headache. Fair warning, it requires a lot of shell trickery and a multiline run to ensure everything happens within a single shell instance.
In my case, I needed to invoke a script and capture the entirety of its stdout for use in a later step, as well as preserve its outcome for error checking:
# capture stdout from script
SCRIPT_OUTPUT=$(./do-something.sh)
# capture exit code as well
SCRIPT_RC=$?
# FYI, this would get stdout AND stderr
SCRIPT_ALL_OUTPUT=$(./do-something.sh 2>&1)
Since Github's job outputs only seem to be able to capture a single line of text, I also had to escape any newlines for the output:
echo "::set-output name=stdout::${SCRIPT_OUTPUT//$'\n'/\\n}"
Additionally, I needed to ultimately return the script's exit code to correctly indicate whether it failed. The whole shebang ends up looking like this:
- name: A run step with stdout as a captured output
id: myscript
run: |
# run in subshell, capturiing stdout to var
SCRIPT_OUTPUT=$(./do-something.sh)
# capture exit code too
SCRIPT_RC=$?
# print a single line output for github
echo "::set-output name=stdout::${SCRIPT_OUTPUT//$'\n'/\\n}"
# exit with the script status
exit $SCRIPT_RC
continue-on-error: true
- name: Add above outcome and output as an issue comment
uses: actions/github-script#v5
env:
STEP_OUTPUT: ${{ steps.myscript.outputs.stdout }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// indicates whather script succeeded or not
let comment = `Script finished with \`${{ steps.myscript.outcome }}\`\n`;
// adds stdout, unescaping newlines again to make it readable
comment += `<details><summary>Show Output</summary>
\`\`\`
${process.env.STEP_OUTPUT.replace(/\\n/g, '\n')}
\`\`\`
</details>`;
// add the whole damn thing as an issue comment
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
})
Edit: there is also an action to accomplish this with much less bootstrapping, which I only just found.
2022 October update: GitHub is deprecating set-output and recommends to use GITHUB_OUTPUT instead. The syntax for defining the outputs and referencing them in other steps, jobs.
An example from the docs:
- name: Set color
id: random-color-generator
run: echo "SELECTED_COLOR=green" >> $GITHUB_OUTPUT
- name: Get color
run: echo "The selected color is ${{ steps.random-color-generator.outputs.SELECTED_COLOR }}"
I'm trying to set up a github action that will automatically request reviewers based on the names of the files that are in the change. For example, if the diff contains a *.sql file, I'd like to request a review from a specific person, and likewise for other file extensions.
This action on the marketplace is what I'm starting with: https://github.com/marketplace/actions/auto-assign-action. I thought the best way to do this would be to use a conditional, something like:
name: 'DB Review'
on: pull_request
jobs:
add-reviews:
runs-on: ubuntu-latest
steps:
- uses: kentaro-m/auto-assign-action#v1.0.1
if: "{{ contains(github.files, '.sql') }}"
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
Unfortunately, it doesn't seem like this magical diff list exists: https://help.github.com/en/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#github-context, so I was hoping for some other suggestions.
One option could be to use the pull_requests.paths filter and create a new workflow for each of the file types when a pull request is opened you want to handle, along with the people who can handle them.
For example:
on:
pull_request:
types: [opened]
paths:
- '**.sql'
jobs:
add-sql-reviews:
runs-on: ubuntu-latest
steps:
- uses: kentaro-m/auto-assign-action#v1.0.1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: ".github/auto_assign_sql.yml"
Now you create this workflow for each file pattern group you want to support and configure who the reviewers are in each of the tasks.
The pull_requests.paths filter is one option, but I think you'll end up with a workflow for each file pattern if you do it that way? Assuming you are going to create more of these...
You could write a custom step in the job which uses the pull request files API, and then you might have a job for each pattern? And an auto-assign config for each job too?
If you're just looking to assign reviewers based on paths, you might consider using GitHub's CODEOWNERS feature instead of a custom workflow. Or if you're looking for more control than that but don't want to write it yourself, PullApprove lets you create assignment rules and groups using almost any data in the GitHub API.
- name: List files in the repository
run: |
ls ${{ github.workspace }}
`