How to version build artifacts using GitHub Actions? - github

My use case is I want to have a unique version number for artifacts per each build/run. With current tools like CircleCI, Travis, etc. there is a build number available which is basically a counter that always goes up. So, I can create version strings like 0.1.0-27. This counter is increased each time even for the same commit.
How can I do something similar with GitHub Actions? Github actions only offer GITHUB_SHA and GITHUB_REF.

GitHub Actions now has a unique number and ID for a run/build in the github context.
github.run_id : A unique number for each workflow run within a repository. This number does not change if you re-run the workflow run.
github.run_number : A unique number for each run of a particular workflow in a repository. This number begins at 1 for the workflow's first run, and increments with each new run. This number does not change if you re-run the workflow run.
github.run_attempt : A unique number for each attempt of a particular workflow run in a repository. This number begins at 1 for the workflow run's first attempt, and increments with each re-run.
ref: https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context
You can reference them in workflows like this:
- name: Output Run ID
run: echo ${{ github.run_id }}
- name: Output Run Number
run: echo ${{ github.run_number }}
- name: Output Run Attempt
run: echo ${{ github.run_attempt }}

I had the same problem and have just created an action to generate sequential build numbers. Use it like
- uses: einaregilsson/build-number#v1
with:
token: ${{secrets.github_token}}
In steps after that you'll have a BUILD_NUMBER environment variable. See more info about using the same build number for different jobs and more at https://github.com/einaregilsson/build-number/
UPDATE: There is now a $GITHUB_RUN_NUMBER variable built into GitHub Actions, so this approach is not needed anymore.

If you want a constant integer increment (1,2,3,4,5), I haven't found anything in the docs that you could use as such increment which is aware of how many times that particular action ran. There's two solutions I can think of:
Maintaining state on the repo: for example with a count.build file that uses the workflow ID and you increment it on build. This is my least favourite solution of the two because it adds other complexities, like it will itself trigger a push event. You could store this file somewhere else like S3 or in a Gist.
Using the Date: if you're not worried about sequence on the integer increment you could just use the current data and time, for example 0.1.0-201903031310 for Today at 13:10.
Regardless if you have Actions Beta Access, I would definitely feed this back to GitHub.
Hope it helps.

You can use GitVersion to generate incrementing versions from tags in Git. The PR at https://github.com/GitTools/GitVersion/pull/1787 has some details, but basically you can define this job:
- uses: actions/checkout#v1
- name: Get Git Version
uses: docker://gittools/gitversion:5.0.2-beta1-34-linux-debian-9-netcoreapp2.1
with:
args: /github/workspace /nofetch /exec /bin/sh /execargs "-c \"echo $GitVersion_MajorMinorPatch > /github/workspace/version.txt\""

Related

Update/Edit of workflow file in GitHub action

I have configured a manual workflow and it runs OK, but once I update/edit it and commit it to the same branch, the changes do not affect it. I mean the action still runs but uses the old version of the workflow file. is there any step I need to do?
Steps I followed for editing the workflow file:
https://docs.github.com/en/actions/learn-github-actions/finding-and-customizing-actions#browsing-marketplace-actions-in-the-workflow-editor
Here is workflow file details, just in case
The original:
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "development" branch
release:
types: [created]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout#v3
# Runs a single command using the runners shell
- name: Run a one-line script
run: echo Hello, world Nikzad!, 3
Note: Let's say I just replace the last line with the bellow line, but my output still says Hello, world Nikzad!, 3 where it should say Hello, world Nikzad!, 4.
run: echo Hello, world Nikzad!, 4
I found my problem. actually, when we are creating a new release, we are providing a tag name for that release, and when we create that tag name and push it to the repo, the version of the workflow at that point is what matters, so when I want to edit or update my workflow, I do the followings:
Edit the workflow (Make any change you want, eg change the title or add echo)
Commit and push workflow changes
Create a new tag and push
From the GitHub panel, create a new release based on the new tag
Now I see the action is running based on the new workflow
Note: Maybe it is more about learning of the process, but I did not find it straight forward anywhere, I hope it helps someone.

Create dynamic secret names in Github Actions

My goal is actually pretty easy but I am not sure if it is possible in the Github Actions or not. So I have an action file that is used for deployment of different Azure subscription/tenants. So I have different AZURE_CREDENTIALS for every one of them.
For example AZURE_CREDENTIALS_NUM1 is one of them. I am giving the name of NUM1 as a customer name to the script in a config file but I do not want to change everywhere in the script that use the same secret. I try this approach but it didn't work:
- uses: azure/login#v1
with:
creds: ${{ "${{needs.Parameters.outputs.azureCredentials}}" }}
Inside the needs.Parameters.outputs.azureCredentials part, I created name for AZURE_CREDENTIALS_NUM1 but this syntax is not accepted by Github Actions.
You need to add mask as below:
- name: Add mask
run: |
echo "::add-mask::${{needs.Parameters.outputs.azureCredentials}}"
- uses: azure/login#v1
with:
creds: ${{needs.Parameters.outputs.azureCredentials}}
Then it will be masked in logs. For more details please check here
when this step is running echo "::add-mask::${{needs.Parameters.outputs.azureCredentials}}"
this value will be printed in the logs "${{needs.Parameters.outputs.azureCredentials}}"
if ${{needs.Parameters.outputs.azureCredentials}}="password" in the logs it will show as below echo "::add-mask::password" indirectly we can see the creds in the logs!!

Stop GitHub Jobs in Progress if Another Failed (stop on fail)

TL; DR: Running jobs a,b in parallel. If a fails, stop the execution of b, while it's still running.
My company uses GitHub Actions to deploy our code.
The first step in our deployment is building dockers and pushing them to DockerHub.
We wrote a test for our code, which we want to run in parallel with building the dockers.
Both of these are separate jobs, and we have a few more jobs depending on the success of the first two.
Right now, if the test job fails, the other job continues to run, but obviously, the next one won't run, because the test job failed.
What I would like to do is cancel the docker building job while it's running, if the test failed.
Is that possible? After searching the web, StackOverflow and the GitHub Actions page, I haven't found a way to do that.
Thanks!
You can specify the needs option and refer to the job name. See: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idneeds
An example could be something like:
jobs:
build:
...
deploy:
needs: build
...
You can use the Cancel this build action.
The basic idea is to add it as a final step in each of your jobs that you want to cause a short-circuit in case of failure:
jobs
job_a:
steps:
- run: |
echo 'I am failing'
exit 1
- name: Cancelling parallel jobs
if: failure()
uses: andymckay/cancel-action#0.2
job_b:
steps:
- run: echo 'long task'
This will basically cancel job_b or any other in the same workflow whenever job_a fails.
Since you are working on an enterprise project, I would prefer to avoid using unverified actions from public repositories no matter how many stars they have. I think you can add a step to the end of each job a, b. This step will only run if previous steps failed. If it is failed then it will send a cancel-workflow api call.
- if: failure()
name: Check Job Status
uses: actions/github-script#v6
env:
RUN_ID: ${{ github.run_id }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
script: |
const runId = process.env.RUN_ID
const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/");
const resp = await github.rest.actions.cancelWorkflowRun({
owner,
repo,
runId
})
Note: You may need to add another custom github_pat since this api-call may require higher permissions than default actions. I also suggest you to take a look at this post , I found it quite useful.

Create dependencies between jobs in GitHub Actions

I'm new to GitHub Actions, playing with various options to work out good approaches to CI/CD pipelines.
Initially I had all my CI steps under one job, doing the following:
checkout code from repo
lint
scan source for vulnerabilities
build
test
create image
scan image for vulnerabilities
push to AWS ECR
Some of those steps don't need to be done in sequence though; e.g. we could run linting and source code vulnerability scanning in parallel with the build; saving time (if we assume that those steps are going to pass).
i.e. essentially I'd like my pipeline to do something like this:
job1 = {
- checkout code from repo #required per job, since each job runs on a different runner
- lint
}
job2 = {
- checkout code from repo
- scan source for vulnerabilities
}
job3 = {
- checkout code from repo
- build
- test
- create image
- scan image for vulnerabilities
- await job1 & job2
- push to AWS ECR
}
I have a couple of questions:
Is it possible to setup some await jobN rule within a job; i.e. to view the status of one job from another?
(only relevant if the answer to 1 is Yes): Is there any way to have the failure of one job immediately impact other jobs in the same workflow? i.e. If my linting job detects issues then I can immediately call this a fail, so would want the failure in job1 to immediately stop jobs 2 and 3 from consuming additional time, since they're no longer adding value.
Ideally, some of your jobs should be encapsulated in their own workflows, for example:
Workflow for testing the source by whatever means.
Workflow for (building and-) deploying.
and then, have these workflows depend on each other, or be triggered using different triggers.
Unfortunately, at least for the time being, workflow dependency is not an existing feature (reference).
Edit: Dependencies between workflows is now also possible, as discussed in this StackOverflow question.
Although I feel that including all of your mentioned jobs in a single workflow would create a long and hard to maintain file, I believe you can still achieve your goal by using some of the conditionals provided by the GitHub actions syntax.
Possible options:
jobs.<job_id>.if
jobs.<job_id>.needs
Using the latter, a sample syntax may look like this:
jobs:
job1:
job2:
needs: job1
job3:
needs: [job1, job2]
And here is a workflow ready to be used for testing of the above approach. In this example, job 2 will run only after job 1 completes, and job 3 will not run, since it depends on a job that failed.
name: Experiment
on: [push]
jobs:
job1:
name: Job 1
runs-on: ubuntu-latest
steps:
- name: Sleep and Run
run: |
echo "Sleeping for 10"
sleep 10
job2:
name: Job 2
needs: job1
runs-on: ubuntu-latest
steps:
- name: Dependant is Running
run: |
echo "Completed job 2, but triggering failure"
exit 1
job3:
name: Job 3
needs: job2
runs-on: ubuntu-latest
steps:
- name: Will never run
run: |
echo "If you can read this, the experiment failed"
Relevant docs:
Workflow syntax for GitHub Actions
Context and expression syntax for GitHub Actions

GitHub custom checks

I'd like to integrate custom checks into some repos, but I can't figure out the best way to do this.
We have pretty large team of developers and we've introduced some naming conventions to maintain consistency in our repo. For example, every commit description should contain X, and every branch name should contain Y or Z, or have a match to some regular expression.
How do I enforce some custom checks on pull request, that branch that is being checked complies to these specified rules? Simply put, when pushed commits don't have Jira reference in their description - merge action is blocked. We also want to see these checks in the PR, like those CI checks which can pass or fail.
I've read about github apps, actions, api, marketplace and etc. Couldn't find something simple and straightforward.
What app or approach should I utilize for such a task?
The easiest way to do this is with a GitHub Action, which will allow you to execute whatever code you want to implement CI or linting checks.
You can create a shell script in your repository (for example, script/lint) that takes two arguments, the base branch and the branch being tested. Lint and check whatever you want, printing useful error messages and exiting zero if the commits are acceptable and nonzero if they're unacceptable.
Then create a workflow in .github/workflow/lint.yml with something like this (changing the script name if need be):
name: lint
on: pull_request
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#master
- run: script/lint "$GITHUB_SHA" "$GITHUB_REF"
This will appear in the checks interface like other CI checks under the name “Lint.” You can customize the name field to change the name.
An example lint script that checks for JIRA tags in commit messages might look like this:
#!/bin/sh
RET=0
for i in $(git rev-list "$1".."$2")
do
printf "Checking $i for JIRA reference..."
if git log -1 --format="%B" $i | grep -qsE "[A-Z]+-[0-9]+"
then
echo "looks ok."
else
echo "failed."
RET=1
fi
done
exit $RET