Closed jayhaddad closed 4 years ago
Great job @jayhaddad, you now have action metadata for your first action. The next piece we will add will be the logic of our action. In this case, our logic will be written in Go.
If you are not familiar with Go programming that's perfectly okay, you are here to learn about writing actions! All the necessary code for each language will be provided for you!
The first iteration of our action will follow the traditional path of logging "Hello World" πto the console. We will expand on this as we move forward, for now it's a good test to make sure all of our files are set up correctly π
main.go
containing the Hello World source codeCreate and add the following contents to the .github/actions/hello-world/main.go
file:
You can use this link to easily create this file in the proper location.
package main
import "fmt"
func main() {
fmt.Println("Hello Docker Actions")
}
Commit the changes to this branch
Click the green Commit new file
button
π Learn Go programming
I'll respond when you push changes to this pull request.
Awesome π
This action now has two of the three key files it needs to run:
Dockerfile
Lastly we will create the Dockerfile
. Like with Go programming, it is perfectly okay if you are not a Docker guru, we will provide the needed code snippets for your Dockerfile
.
Dockerfile
containing the Docker instructionsCreate and add the following contents to the .github/actions/hello-world/Dockerfile
file:
You can use this link to easily create this file in the proper location.
FROM golang:latest
WORKDIR /go/src/hello
COPY . .
RUN go get -d -v ./...
RUN go install -v ./...
CMD ["hello"]
Commit the changes to this branch
Click the green Commit new file
button
I'll respond when you push changes to this pull request.
Your very first Docker action has been written and executed within a workflow! You may be wondering how I know that and the truth is that GitHub Actions provide real-time logging of the events happening within the runner! Since our action prints to the console we can just expand that step in our workflow and look at the standard output that is on our screen.
You can do this in your own Actions tab or you can settle for examining the screenshot below to see our Hello World statement in place of where our previous errors existed.
Whoa, that's a lot of output for a simple hello world! Don't let this alarm you, the output you see is from the Docker build
operation that packages up your files into a Docker image.
π Learn about Docker build
A "Hello World" message is great, but let's personalize it a little bit. We will do this by adding an input parameter to the action.yml
, workflow.yml
and main.go
files.
Although this example may seem a little lightweight input parameters have a very flexible use case. Consider a scenario where you need to access secret API key with your action, or when you need to specify the path to a given file. Inputs allows for these problems to be easily solved.
To add inputs we need to add the inputs:
parameter to the action.yml
file. The inputs:
parameter has a few parameters of its own.
Parameter | Description | Required |
---|---|---|
description: |
String describing the purpose of the input | True |
required: |
Boolean value indicating if the input parameter is required or not. (Default value is True) | False |
default: |
String representing a default value for the input parameter | False |
Let's take a look at how this fits into an action.yml
file.
action.yml
name: "my hello action"
description: "say hello with actions"
inputs:
firstGreeting:
description: "who would you like to greet in the console"
required: true
default: "Hubot"
secondGreeting:
description: "another person to greet"
required: true
default: "Mona the Octocat"
thirdGreeting:
description: "a third greeting"
required: false
The placement of your inputs:
is not strictly enforced, however it has become commonplace to ensure the runs:
statement is defined after your inputs:
and outputs:
in your action.yml
file.
Well, in the my-workflow.yml
file we could specify values for inputs we just created:
Or we could leave them out and rely on their default values.
The example below demonstrates a mix of both:
my-workflow.yml
name: "Docker Actions"
on: [push]
jobs:
action:
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v1
- name: "hello-action"
uses: ./.github/actions/hello-world
with:
firstGreeting: "Learning Lab User"
Now that there are inputs in the action's metadata the user can interface with them by supplying values. In this case Learning Lab User was passed as the value for the firstGreeting
input which overrides the default value, specified in the action.yml
, of Hubot
main.go
package main
import (
"fmt"
"os"
)
func main() {
// Access Inputs as environment vars
firstGreeting := os.Getenv("INPUT_FIRSTGREETING")
secondGreeting := os.Getenv("INPUT_SECONDGREETING")
thirdGreeting := os.Getenv("INPUT_THIRDGREETING")
// Use those inputs in the actions logic
fmt.Println("Hello " + firstGreeting)
fmt.Println("Hello " + secondGreeting)
// Someimes inputs are not "required" and we can build around that
if thirdGreeting != "" {
fmt.Println("Hello " + thirdGreeting)
}
}
In our actions source code we can access the inputs as if they are environment variables. GitHub Actions takes every inputs:
value and converts it by adding INPUT_
and making the value uppercase.
For example:
firstGreeting
= INPUT_FIRSTGREETING
secondGreeting
= INPUT_SECONDGREETING
someInput
= INPUT_SOMEINPUT
How you access environment variables will vary by language
πRead more about the input parameter
Now that we know what input parameters are, let's edit the metadata for our hello-world action.
action.yml
to accept input parameters for Hello Worldπ‘All of the following steps take place inside of the .github/actions/hello-world
directory.
Add the following contents to the .github/actions/hello-world/action.yml
file:
You can use this link to easily edit this file.
name: "my hello action"
description: "say hello with GitHub Actions"
inputs:
firstGreeting:
description: "who would you like to greet in the console"
required: true
default: "Hubot"
secondGreeting:
description: "another person to greet"
required: true
default: "Mona the Octocat"
thirdGreeting:
description: "a third greeting"
required: false
runs:
using: "docker"
image: "Dockerfile"
Commit the changes to this branch
I'll respond when you push changes to this pull request.
Great job π next let's update our source code to consume the inputs that are now defined.
π‘All of the following steps take place inside of the .github/actions/hello-world
directory.
Add the following contents to the .github/actions/hello-world/main.go
file:
You can use this link to easily edit this file.
package main
import (
"fmt"
"os"
)
func main() {
// Access Inputs as environment vars
firstGreeting := os.Getenv("INPUT_FIRSTGREETING")
secondGreeting := os.Getenv("INPUT_SECONDGREETING")
thirdGreeting := os.Getenv("INPUT_THIRDGREETING")
// Use those inputs in the actions logic
fmt.Println("Hello " + firstGreeting)
fmt.Println("Hello " + secondGreeting)
// Someimes inputs are not "required" and we can build around that
if thirdGreeting != "" {
fmt.Println("Hello " + thirdGreeting)
}
}
Commit the changes to this branch
I'll respond when you push changes to this pull request.
The last piece to this actions puzzle is to edit the workflow file so that we can set custom values for these inputs.
my-workflow.yml
π‘All of the following steps take place inside of the .github/workflows
directory.
Add the following contents to the .github/workflows/my-workflow.yml
file:
You can use this link to easily edit this file.
name: "Docker Actions"
on: [push]
jobs:
action:
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v1
- name: "hello-action"
uses: ./.github/actions/hello-world
with:
firstGreeting: "Learning Lab User"
Commit the changes to this branch
I'll respond when you push changes to this pull request.
Great Job π making those changes @jayhaddad. I will take just a moment to walk you through what happened.
If you look at the screenshot below you will see a very similar output to what your results should show. If you'd like you can open your own Actions tab to follow along.
Your action now says hello to Learning Lab User which was the specified value for the firstGreeting
input parameter which was added to the my-workflow.yml
file.
What's interesting though, is that we also see Mona the Octocat and if you recall that is the value of the secondGreeting
parameter in the action.yml
file.
Why do we see the value of the secondGreeting
π€
If you remember, we made the secondGreeting
input parameter required. This means that even if it is not specified in my-workflow.yml
it will be executed by the main.js
code using whatever value was set as default. It cannot be ignored like our thirdGreeting
was.
Circling back to the fistGreeting
you may have noticed that you were able to overwrite the default value of Hubot
by being explicit in the my-workflow.yml
file.
Had you been explicit with thirdGreeting
in the my-workflow.yml
file then the if
statement in the main.go
file would have executed and you would have three inputs.
Take a few minutes to play with the current code you have. I don't suggest editing the main.go
, Dockerfile
, or action.yml
files, rather I think there is a lot to gain by changing the my-workflow.yml
file to include or exclude certain input parameters.
my-workflow.yml
file. What happens when your action executes?my-workflow.yml
file. What happens when your action executes?third-greeting
input parameter in the my-workflow.yml
file. what happens when your action executes?When you are finished experimenting and examining the results merge this pull request into the master branch.
Our next lesson will show you how to add external libraries to an action as well as interact with external APIs.
When I notice that you have merged this branch I will open a new issue in your repository to continue guiding you.
Congratulations jayhaddad you have officially written your first GitHub Docker action!!!
That's super exciting news, but this lesson has just started, so let's head over to the new issue I've opened to continue writing GitHub Actions.
Create pull request