Closed github-learning-lab[bot] closed 3 years ago
Every GitHub Action that we write needs to be accompanied by a metadata file. This file has a few rules to it, lets outline those now:
action.yml
This file defines the following information about your action:
Parameter | Description | Required |
---|---|---|
Name | The name of your action. Helps visually identify the actions in a job. | :white_check_mark: |
Description | A summary of what your action does. | :white_check_mark: |
Inputs | Input parameters allow you to specify data that the action expects to use during runtime. These parameters become environment variables in the runner. | ❌ |
Outputs | Specifies the data that subsequent actions can use later in the workflow after the action that defines these outputs has run. | ❌ |
Runs | The command to run when the action executes. | :white_check_mark: |
Branding | You can use a color and Feather icon to create a badge to personalize and distinguish your action in GitHub Marketplace. | ❌ |
📖Read more about Action metadata
Now that we know what action metadata is, let's create the metadata for our current hello-world action.
💡All of the following steps take place inside of the .github/actions/hello-world
directory.
We will start with using the parameters that are required and later implement some optional parameters as our action evolves.
.github/actions/hello-world/action.yml
Add the following contents to the .github/actions/hello-world/action.yml
file:
name: "my hello action"
description: "say hello with GitHub Actions"
runs:
using: "node12"
main: "main.js"
action.yml
fileCommit the changes and push them to the hello-world
branch:
git add action.yml
git commit -m 'create action.yml'
git push
I'll respond here once I notice that you've pushed your changes.
As you have learned runs:
defines the command necessary to execute your action.
In our current case runs:
takes 2 arguments
using:
main:
These are specific to JavaScript actions. It is our way of telling the runner to run the main.js
file using node12
This is no different than running a local JavaScript file using Node like you see below:
Which means that the value of main:
would be different if your file was not named main.js
.
In this scenario our metadata block would look like this:
runs:
using: "node12"
main: "bread.js"
This execution is visible from within your workflow. To save time I have included a screenshot of what your workflow currently looks like. As always, you can follow along in the [Actions tab]().
Look 👀, now we have a new error! We are totally making progress here! What we can reason from this output is that our action.yml
file was found and read. Since we defined the main:
parameter to point to a file named main.js
the workflow looked for that file in the root of the hello-world
directory, but since it couldn't find it the workflow fails.
Let's fix this next!
You may have noticed that your workflow has been running every time a change has been made. This is expected since it's trigger is a push
event.
Hopefully you have also noticed that it fails when it reaches the hello-action
step.
As we can see from the screenshot, as well as the Actions tab, the failure occurs because the runner cannot find the action.
Lets fix that by creating the action it is looking for!
💡All of the following steps take place inside of the .github/actions/hello-world
directory.
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 😄
Create and add the following contents to the .github/actions/hello-world/main.js
file:
console.log("Hello World");
Save the main.js
file
Commit the changes and push them to the hello-world
branch:
git add main.js
git commit -m 'create main.js'
git push
I'll respond here once the workflow has completed running. Remember, you need to push your changes to trigger it!
Your very first JavaScript 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.
Earlier I asked you to install the @actions/core
package using npm
. We did this so that we can expand our action to make it more flexible.
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
and main.js
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 | False (Default value is True) |
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:
first-greeting:
description: "who would you like to greet in the console"
required: true
default: "Hubot"
second-greeting:
description: "another person to greet"
required: true
default: "Mona the Octocat"
third-greeting:
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: "JS Actions"
on: [push]
jobs:
action:
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v1
- name: "hello-action"
uses: ./.github/actions/hello-world
with:
first-greeting: "Learning Lab User"
Now that there are inputs in the action's metadata we can use the @actions/core
package to handle them within our main.js
file.
main.js
const core = require("@actions/core");
const firstGreeting = core.getInput("first-greeting");
const secondGreeting = core.getInput("second-greeting");
const thirdGreeting = core.getInput("third-greeting");
console.log(`Hello ${firstGreeting}`);
console.log(`Hello ${secondGreeting}`);
if (thirdGreeting) {
console.log(`Hello ${thirdGreeting}`);
}
By using core.getInput()
we can specify the string of any input parameter we have placed inside of the action.yml
file.
The @actions/core
package brings a few more methods along with it to help us interact with the GitHub Actions platform. If writing actions is something you plan to continue doing it's work reading the documentation about this package.
📖Read more about the input parameter
That was a lot of information that you just learned. @cpswan it is time for you to put it in practice.
Using your code editor change these files to reflect the code in the examples shown above:
.github/actions/hello-world/main.js
.github/actions/hello-world/action.yml
.github/workflows/my-workflow.yml
Save the changes to each file
Commit the changes to this branch and push them to GitHub:
git add main.js action.yml workflow.yml
git commit -m 'allow input in all action files'
git push
I'll respond here when GitHub Actions reports it's finished.
Great Job 👍 making those changes @cpswan. 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 first-greeting
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 second-greeting
parameter in the action.yml
file.
Why do we see the value of the second-greeting
🤔
If you remember, we made the second-greeting
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 third-greeting
was.
Circling back to the fist-greeting
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 third-greeting
in the my-workflow.yml
file then the if
statement in the main.js
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.js
file, 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 main 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 cpswan you have officially written your first GitHub JavaScript action!!!
That's super exciting news, but this lesson has just start, so let's head over to the new issue I've opened to continue writing GitHub Actions.
Anatomy of an action
Earlier you learned how the different pieces of the GitHub Actions feature work together. Now you will learn about the components that make up an individual action.
Remember, and action is the unit of work that a workflow file executes when it reaches that task. They are called by referencing them as the value to the
uses:
key in a workflow step.What makes up an action?
JavaScript actions are consist of two key components:
action.yml
Let's take a look at how those components fit in with the workflow file.
Although the workflow file is used to allow us to set the
inputs
andoutputs
using thewith:
keyword it is not a required component of an individual action.The failing workflow
Before we jump into the details of action metadata, it might be helpful to examine our workflow to understand the order that things happen. I have attached a screenshot below of the most recent workflow run, you can also follow along by clicking on the Actions tab for your repository.
Notice that our third workflow step, the one that is looking for our action is failing. We expect this, but the magic ✨is in the error message!
That step is looking for a file named
action.yml
.Because
action.yml
is non-existent in thehello-world
directory we see this error. So let's start by talking about, and creating, the missingaction.yml
file.