Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Getting Started with Github Action Workflows
Rob
Rob

Posted on

     

Getting Started with Github Action Workflows

This article gives a brief introduction to the concepts and syntax of github actions. While theofficial documentation of github actions is comprehensive, the aim of this article is to help avoid those early learning mistakes.

link to original article

Context 👨🏼‍🏫

Github actions is a platform to automate developer workflows. It was built to reduce the organisational burden attached to large open-source community driven repositories. This burden would manifest in the form of hundreds, if not thousands, of contributors, branches, pull requests, merges as well as testing, labelling, creating release documentation and many other tasks or events.

The purpose of an action is to listen to these events and trigger a workflow in response. For example, if a contributor raises an issue, you may want to sort it, label it, and assign it automatically. A workflow is a.yml or.yaml file with a set of instructions you define.

While CI/CD is often used to convey its utility, it is just one of many possible workflows you can create to serve your needs. The examples in this article are simple workflows created merely to introduce some of the basic concepts.

  1. Executing Shell Commands
  2. Accessing Environment Variables
  3. Calling Composite Actions
  4. Setting & Passing Variables
  5. Making Web Service Calls

1.Executing Shell Commands 🐚

The first example below is a very basic workflow executing different commands in their native shells. The point of this example is to illustrate the role of therun-on andshell instructions. A workflow refers to all the instructions within the file, which is comprised of one or morejobs, which in turn is comprised of one or moresteps.

Eachjob listed within a workflow is executed concurrently on a different github server, but you can choose to host them yourself. The significance of this means you need to specify which operating system you want yourjob to run on by using therun-on keyword. This can include various versions of windows, macOS, ubuntu or even being self-hosted.

If for example all your steps within a job run powershell commands or scripts, you could specifyrun-on: windows-latest and call it job done as powershell would be understood by the runners of that operating system. But let's say you needed to run a one off Zshell script in the same job, here theshell keyword can allow you to override the shell of the specified OS by specifying the correct shell language.

Below is an example of 'Hello World' being printed to the console inpowershell,bash,zshell and evenpython , which are all being run on awindows github server. Github also acceptspowershell,pwsh (powershell core) andcmd when overriding for Windows commands. See the code example for more useful information in the comments and follow all links to source file.

Workflow

name:1 - Run Hello Worlds scripts# <- Workflow name.on:# <- The trigger definition block.push:# <- An event to trigger the action, of type push.branches:[# <- Target Branches. Accepts an array.main,another-branch]jobs:# <- The execution of work block.Job-Identifier:# <- Job ID. Contains related action steps.name:Executing Hello World Script# <- Job Name.runs-on:windows-latest# <- Tells the server which OS to run on. Can also be windows, macOS, or even self-hosted.steps:# <- Step definitions.-uses:actions/checkout@v2# <- Use keyword selects an action. Actions/ path in github is where common actions are predefined.-name:Printing Powershell# <- Optional step name, but advised.run:./Powershell/HelloWorld.ps1# <- Run keyword executes a command. In this case a powershell script.-name:Printing Bashshell:bash# <- Overrides the default shell language of your specified server.run:./Bash/HelloWorld.sh-name:Printing ZShellshell:shrun:./Zshell/HelloWorld.zsh-name:Printing Pythonshell:pythonrun:exec(open('./Python/HelloWorld.py').read())
Enter fullscreen modeExit fullscreen mode

Console Output

Run ./Powershell/HelloWorld.ps1Hello World from Powershell!Run ./Bash/HelloWorld.shHello World from Bash!Run ./Zshell/HelloWorld.zshhello world from Zshell!Runexec(open('./Python/HelloWorld.py').read())Hello World from Python!
Enter fullscreen modeExit fullscreen mode

2.Accessing Environment Variables 🌱

The following example illustrates how you can readenvironment variables. There are two kinds of variables, those provided by github which use protected names and can be found in thedocumentation, and custom variables you can set yourself throughout your workflow.

Another significant feature of theworkflow,job andstep relationship is how custom variables are scoped. Declared variables within the workflow using the keywordenv follow an access hierarchy and can only be accessed within the element they were defined. Those variables declared at the highestworkflow level can be accessed by alljobs andsteps. Variables declared within ajob can only be used by steps within that job and if declared inside astep they can only be used by that step.

2.1 Custom & Protected Environment Variables

In the below workflow example you can see that 3 custom variables are declared at different levels:BEST_PINT,BEST_WHISKEY andBEST_COCKTAIL. In thePrint Variables to Script step ascript is executed to print these variables to the console along with a sample of various set github environment variables.

Workflow

name:2 - Access Github Environment Variableson:push:branches:[main,another-branch]pull_request:# <- Pull request trigger. Used in Example 2.2.branches:[main# <- If any pull request is made to branch 'main'.]env:BEST_PINT:Guinness# <- Custom environment variable declared at workflow level.jobs:#Example 2.1Access-Environment-Variables:name:Print Github Environment Variablesruns-on:windows-latestenv:BEST_WHISKEY:Midleton# <- Scoped to this job and subsequent steps.steps:-uses:actions/checkout@v2-name:Print Variables to Scriptrun:./Powershell/GithubEnvVariables.ps1env:BEST_COCKTAIL:Whiskey Sour# <- Scoped to this step only.-name:Inspect Environment Variablesrun:env# <- Prints to output the available variables to this step.
Enter fullscreen modeExit fullscreen mode

Console Output

The owner and repository name.GITHUB_REPOSITORY:'Mulpeter91/Github-Actionman'The commit SHA that triggered the workflow.GITHUB_SHA:'321d557ec2d724d2c6aaf056b14859ea8468051e'The jobidyou assigned to the current job.GITHUB_JOB:'Job-Identifier-Sample'A unique numberforeach workflow run within a repository. This number does not changeifyou re-run the workflow run.GITHUB_RUN_ID:'1836698654'An unique numberforeachtimethe same workflow is run again. Starts at 1 and increments by 1.GITHUB_RUN_NUMBER:'18'The name of the runner executing the job.RUNNER_NAME:'GitHub Actions 4'I love a pint of Guinness with a glass of Midleton and end the night on a Whiskey Sour.
Enter fullscreen modeExit fullscreen mode

A useful command to inspect available environment variables within a step isrun: env. Notice that the below output does not containBEST_COCKTAIL because it was defined and scoped to the previous step.

...APPDATA=C:\Users\runneradmin\AppData\RoamingAZURE_EXTENSION_DIR=C:\Program Files\Common Files\AzureCliExtensionDirectoryBEST_PINT=GuinnessBEST_WHISKEY=MidletonCABAL_DIR=C:\cabalChocolateyInstall=C:\ProgramData\chocolatey...
Enter fullscreen modeExit fullscreen mode

You must remember to use the correct syntax for referencing variables in your target shell. For example, Windows runners would required the format$env:NAME while the Linux runners using bash shell would use$NAME.

2.2 Specific Event Variables

Most github environment variables will always populate, such asGITHUB_ACTOR but some will only be populated during a specific event trigger. In the aboveworkflow example you can see a trigger has been added forpull_request. This has been added to show you some of the variables that will only populate during that event, such asGITHUB_BASE_REF andGITHUB_HEAD_REF.

Workflow

#Example 2.2Pull-Request-Variables:name:Obtain variables useful to a pull requestruns-on:windows-latestenv:var:nothingsteps:-uses:actions/checkout@v2-name:Print Variables for Pull Request# <- Add a pipe key on the run command to make a multiple.run:|Write-Host "Actor: $Env:GITHUB_ACTOR"Write-Host "Target Branch: $Env:GITHUB_BASE_REF"Write-Host "Source Branch: $Env:GITHUB_HEAD_REF"
Enter fullscreen modeExit fullscreen mode

Console Output

Actor: Mulpeter91Target Branch: mainSource Branch: pull-request-ex
Enter fullscreen modeExit fullscreen mode

2.3 Accessing Event Metadata

Another variable worth noting and is heavily effected by the action event type isGITHUB_EVENT_PATH. This variable contains the directory within your runner to a temporarily storedevent.json file. This file contains substantial metadata regarding the specific event triggered within the workflow and can be fed into a json object for easy access to specific data nodes.

Every event type has it's own structured version of the file. So what exists in apull_request:event.json will not exactly match the nodes in apush:event.json.

Workflow

#Example 2.3-name:Print Json from Action Event Filerun:./PowershellEventFile.ps1
Enter fullscreen modeExit fullscreen mode

File

"Event metadata file path:$Env:GITHUB_EVENT_PATH`n""File Contents:"$EVENT_FILE = Get-Content -Path$Env:GITHUB_EVENT_PATHWrite-Host$EVENT_FILE$EVENT_JSON =$EVENT_FILE | ConvertFrom-Json"`nSample selectors"Write-Host"OBJECT.head_commit.author.username:"$EVENT_JSON.head_commit.author.usernameWrite-Host"OBJECT.head_commit.url:"$EVENT_JSON.head_commit.url
Enter fullscreen modeExit fullscreen mode

Console Output

Event metadata file path: D:\a\_temp\_github_workflow\event.jsonFile Contents:(see above consolelink)Sample selectorsOBJECT.head_commit.author.username: Mulpeter91OBJECT.head_commit.url: https://github.com/Mulpeter91/Github-Actionman/commit/443da01e18050bd8912d3fac24a86f0c340a2ea8
Enter fullscreen modeExit fullscreen mode

3.Calling Composite Actions ⚙️

Composite actions are a specific type of workflow file which are designed to abstract out and reuse a set of instructions for one or more requesting workflows. They are typically stored in their own repositories, such asGithub's own shared actions orGoogle's integration actions, but they can also be stored and executed in the same repository.

A step utilises theuses keyword when executing acomposite action. In the below example you will notice two steps each using a composite action. The first is using github's sharedactions/checkout@v2 and the other is using our localcomposite action.

Composite actions depend on targeted releases to know which version of the code to execute. In the case ofcheckout@v2 this is referencing releasev2 in thecheckout repository. You need to checkout your code in order to build it, test it or in our case execute composite actions.

Workflow

name:3 - Running a local Composite Actionon:push:branches:[main,another-branch]jobs:Run-Composite-Action:name:Print message from another actionruns-on:windows-lateststeps:-uses:actions/checkout@v2# <- Required to checkout your code in order to access composite actions from with the repo-name:Use hello world composite actionuses:./.github/actions/hello-world# <- Use keyword for calling other actions
Enter fullscreen modeExit fullscreen mode

Thecomposite action file requires aname anddescription field with an optionalauthor field. The run also needs to addusing: 'composite' before executing its steps.

Composite Action

name:Print Hello Worlddescription:Prints a Hello World message.author:Robert Mulpeter @Mulpeter91runs:using:"composite"# <- Required declaration of a composite action.steps:-run:Write-Host "Hello World from Composite Action!"shell:pwsh
Enter fullscreen modeExit fullscreen mode

Console Output

Run ./.github/actions/hello-worldRun Write-Host"Hello World from Composite Action!"Hello World from Composite Action!
Enter fullscreen modeExit fullscreen mode

Another important point regardingcomposite actions is that they must be defined inside a file called eitheraction.yml oraction.yaml. It is recommended that if you have multiple composite actions in the same repo that you house them in their own directories within the.github directory. While these directories can contain other files such as docker files, they must containoneaction file. See workingrepo for an example.

4.Setting and Passing Variables 🤾

The belowstep examples are all run on the sameworkflow file and combine parts of the previous code with the added fun of setting variables from outside theyml file and passing variables around the workflow.

4.1 Passing Parameters to Composite Action

In the below example we are using acomposite action much like example 3 but withinput parameters. Thestep passing these named parameters to the action with thewith keyword and<variable> name, in this case 'message'.

Job 1 / Example 1

jobs:Create-Variables:name:Creating and passing variablesruns-on:windows-lateststeps:#Example 4.1-uses:actions/checkout@v2-name:Use print message composite actionuses:./.github/actions/print-messagewith:# <- With keyword to signify parametersmessage:"CobraKaineverdies"# <- Named parameter in the called action.
Enter fullscreen modeExit fullscreen mode

The composite action lists its parameters with theinputs keyword. Parameters can berequired: true orfalse, include adescription and adefault value if no value is passed. In our case, amessage value is sent but aversion value is not.

Composite Action

name:Print Parametersdescription:Prints a message passed from the workflow.author:Robert Mulpeter @Mulpeter91inputs:# <- keyword for defining action parameters.message:required:truedescription:"Themessagetobeprinted"version:required:falsedescription:"Theversion."default:"🤟🏻"runs:using:"composite"steps:-run:Write-Host ${{ inputs.message }} ${{ inputs.version }}shell:pwsh
Enter fullscreen modeExit fullscreen mode

Console Output

Run ./.github/actions/print-messageRun Write-Host Cobra Kai never dies 🤟🏻Cobra Kai never dies 🤟🏻
Enter fullscreen modeExit fullscreen mode

4.2 Set Variables from Environment File

The following example combines a parameterised composite action with reading the contents of an.env file into the environment variables for access by the workflow.

Job 1 / Example 2

#Example 4.2-name:Set variables from environment fileuses:./.github/actions/read-env-filewith:filePath:./.github/variables/variables.env
Enter fullscreen modeExit fullscreen mode

Using>> $Env:GITHUB_ENV instructs github to read the variable into the environment variable dictionary.

Composite Action

name:Read Env Variables from filedescription:Reads environment variables from a passed .env file.author:Robert Mulpeter @Mulpeter91inputs:filePath:required:truedescription:"Filepathtovariablefile."default:./.github/variables*runs:using:"composite"steps:-run:|Get-Content ${{ inputs.filePath }} >> $Env:GITHUB_ENV   # <- Adding directly $Env:GITHUB_ENV saves at the workflow levelshell:pwsh
Enter fullscreen modeExit fullscreen mode

It is advised to keep all variable related files within the.github directory.

Input File

DOJO_1=Miyagi-Do Karate
Enter fullscreen modeExit fullscreen mode

Console Output

Run Get-Content ./Powershell/Variables.ps1>>$Env:GITHUB_ENV  Get-Content ./Powershell/Variables.ps1>>$Env:GITHUB_ENVenv:    DOJO_1: Miyagi-Do Karate
Enter fullscreen modeExit fullscreen mode

4.3 Set Variables from Powershell File

The following example achieves the same outcome of example 4.2 but adds environment variables by executing apowershell script directly in the workflow step.

Job 1 / Example 3

#Example 4.3-name:Set variables from powershell filerun:Get-Content ./Powershell/Variables.ps1 >> $Env:GITHUB_ENV
Enter fullscreen modeExit fullscreen mode

Input File

DOJO_2=Eagle Fang KarateDOJO_3=Cobra-Kai Karate
Enter fullscreen modeExit fullscreen mode

Console Output

Run Get-Content ./Powershell/Variables.ps1>>$Env:GITHUB_ENV
Enter fullscreen modeExit fullscreen mode

4.4 Set Variables from Local Step Variable

The below example takes a local environment variable declared in the step and reads it directly into the github environment dictionary. Note from the below console output, that the variable$LOCAL_VARIABLE has been read into the dictionary under variable$WORKFLOW_VARIABLE which is accessible in the subsequentInspect Environment Variables step.

Job 1 / Example 4

#Example 4.4-name:Set local step variable to environment variablerun:|echo "WORKFLOW_VARIABLE=$(echo ${Env:LOCAL_VARIABLE})" >> $Env:GITHUB_ENVenv:LOCAL_VARIABLE:Karate Kid-name:Inspect Environment Variablesrun:env
Enter fullscreen modeExit fullscreen mode

Console Output

echo"WORKFLOW_VARIABLE=$(echo${Env:LOCAL_VARIABLE})">>$Env:GITHUB_ENVenv:  DOJO_1: Miyagi-Do Karate  DOJO_2: Eagle Fang Karate  DOJO_3: Cobra-Kai Karate  LOCAL_VARIABLE: Karate KidRunenvenv:  DOJO_1: Miyagi-Do Karate  DOJO_2: Eagle Fang Karate  DOJO_3: Cobra-Kai Karate  WORKFLOW_VARIABLE: Karate Kid
Enter fullscreen modeExit fullscreen mode

4.5 Pass Variable to Dependant Job

We previously noted thatjobs are run concurrently by default and that variables are scoped to the element they are defined in. The following example illustrates how you can enforce a dependency between jobs to have them run consecutively to each other by using theneeds array and pass a variable from the initial job to thedependent job using theoutputs keyword rather than sending everything to the high level environment dictionary.

The below step is extracted from the first jobcreate-variables and uses theoutputs keyword with an object reference to stepstep_output. This step in turn uses the::set-ouput name=NAME::Value command to set the outputted variable.

Job 1 / Example 5

jobs:create-variables:name:Creating and passing variablesruns-on:windows-latestoutputs:output1:${{ steps.step_output.outputs.TONIGHTS_DINNER }}#Example 4.5-id:step_outputname:Create variable output from steprun:|echo "::set-output name=TONIGHTS_DINNER::Burrito"
Enter fullscreen modeExit fullscreen mode

The next step which is in the subsequentObtain-Variables job then uses theneeds keyword to wait for the referenced job to complete. The step then references the outputted variable and assigns it to the internalDinner variable.

Job 2 / Example 5

Obtain-Variables:needs:[Create-Variables]# <- Jobs run concurrently by default. Over this with the 'needs' keyword to set dependents.name:Reading previous variablesruns-on:windows-lateststeps:#Example 4.5-name:Print output variablerun:|Write-Host "Tonights dinner will be " $Env:Dinnerenv:Dinner:${{ needs.create-variables.outputs.dinner }}
Enter fullscreen modeExit fullscreen mode

Console Output

Run Write-Host"Tonights dinner will be"$Env:DinnerTonights dinner will be Burrito
Enter fullscreen modeExit fullscreen mode

5. Web Requests

The below workflow demonstrates a series of simple web calls to theGithub Apipulls endpoint, which returns information on pull requests. You can feed the response into a json object to access relevant data. The belowInvoke-WebRequest calls will work because this repo is public. If private you will need tocreate an OAuthPersonal Access Token to the header with-Headers @{"Authorization"="Bearer <token>"}. If the repository belongs to an organisation to which you are a member you will need authorize that created token to enable access viaconfigure SSO.

Workflow

name:5 - Process Web Requestson:pull_request:branches:[main]jobs:Obtain-Pull-Request-Data:name:Call Github APIruns-on:windows-latestenv:PR_STATE:closed# <- query parameters to github are case sensitivesteps:-uses:actions/checkout@v2-name:Call the Github /pulls endpointrun:./Powershell/GithubWebRequests.ps1
Enter fullscreen modeExit fullscreen mode

Input File

"This will return a list of all open pull requests:"$URI="https://api.github.com/repos/$Env:GITHUB_REPOSITORY/pulls"Write-Host$URI"`nThis willreturnall pull requests of a specified state:"$URI = "https://api.github.com/repos/$Env:GITHUB_REPOSITORY/pulls?state=$Env:PR_STATE"Write-Host$URI"`nThis will return a specific pull request:"$PR_NUMBER=$Env:GITHUB_REF_NAME-replace"/.*"# <- You can also get the PR number from the pull request event file.$URI="https://api.github.com/repos/$Env:GITHUB_REPOSITORY/pulls/$PR_NUMBER"Write-Host$URI$RESPONSE= Invoke-WebRequest-Uri$URI-Method Get-TimeoutSec 480Write-Host$RESPONSE"`nAccessing variables from the object:"$JSON_OBJECT =$RESPONSE | ConvertFrom-JsonWrite-Host "HTML URL:"$JSON_OBJECT.html_urlWrite-Host "TITLE:"$JSON_OBJECT.titleWrite-Host "BODY:"$JSON_OBJECT.bodyWrite-Host "USER:"$JSON_OBJECT.user.loginWrite-Host "REQUESTED REVIEWERS:"$JSON_OBJECT.requested_reviewersWrite-Host "MERGE_COMMIT_SHA:"$JSON_OBJECT.merge_commit_sha
Enter fullscreen modeExit fullscreen mode

Console Output

This willreturna list of all open pull requests:https://api.github.com/repos/Mulpeter91/Github-Actionman/pullsThis willreturnall pull requests of a specified state:https://api.github.com/repos/Mulpeter91/Github-Actionman/pulls?state=closedThis willreturna specific pull request:https://api.github.com/repos/Mulpeter91/Github-Actionman/pulls/24Accessing variables from the object: HTML URL: https://github.com/Mulpeter91/Github-Actionman/pull/24TITLE: Test TitleBODY: Test BodyUSER: Mulpeter91REQUESTED REVIEWERS: MERGE_COMMIT_SHA: bd98939094bdb3d775966900ec43a126cf5fac80
Enter fullscreen modeExit fullscreen mode

Conclusion

The purpose of this article and these examples was to give you an introduction to basic concepts and syntax in order to continue learning github actions with a clearer vision of the platform. But this is just the tip of the iceberg. Github actions are capable of far more precise workflows with the use of more complex syntax.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Joined

More fromRob

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp