Skip to content

Commit 87be5a1

Browse files
authored
Initial commit
0 parents  commit 87be5a1

18 files changed

Lines changed: 1447 additions & 0 deletions

.devcontainer/devcontainer.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"image": "mcr.microsoft.com/devcontainers/universal:2",
3+
"features": {
4+
"ghcr.io/devcontainers/features/node:1": {}
5+
}
6+
}

.github/steps/1-step.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
## Step 1: Setting up the project
2+
3+
Imagine you’ve got a repetitive task you’d love to automate. You've searched through the [**GitHub Marketplace**](https://github.com/marketplace?type=actions) for existing actions that might help, you come up empty-handed…
4+
5+
Maybe that’s because your task is a bit _too_ unique 😆
6+
7+
**GENERATING DAD JOKES**! 🎭
8+
9+
<img width="600" alt="dadjoke-mona" src="https://github.com/user-attachments/assets/46b6b931-8d1f-4a01-88f4-4568704039a0" />
10+
11+
Since no pre-built action exists for your quirky automation needs, it's time to roll up your sleeves and create your own!
12+
13+
### ⌨️ Activity: Set up your development environment
14+
15+
Let's use **GitHub Codespaces** to set up a cloud-based development environment and work in it for the remainder of the exercise!
16+
17+
1. Right-click the below button to open the **Create Codespace** page in a new tab. Use the default configuration.
18+
19+
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/{{full_repo_name}}?quickstart=1)
20+
21+
1. Confirm the **Repository** field is your copy of the exercise, not the original, then click the green **Create Codespace** button.
22+
23+
- ✅ Your copy: `/{{full_repo_name}}`
24+
- ❌ Original: `/skills/write-javascript-actions`
25+
26+
1. Wait a moment for Visual Studio Code to load in your browser.
27+
28+
1. Verify that **Node.js** is available by opening a terminal and running:
29+
30+
```sh
31+
node --version
32+
npm --version
33+
```
34+
35+
<details>
36+
<summary>Having trouble? 🤷</summary><br/>
37+
38+
- Make sure you selected your personal copy of the repository, not the original template.
39+
- If the Codespace fails to start, try refreshing the page and creating a new one.
40+
- Node.js and npm should be pre-installed in the development environment.
41+
42+
</details>
43+
44+
### ⌨️ Activity: Initialize Project
45+
46+
Now that your Codespace is ready, let's initialize a new Node.js project and install the dependencies needed for your Dad Jokes action.
47+
48+
1. Within your GitHub Codespace terminal window initialize a new project:
49+
50+
```sh
51+
npm init -y
52+
```
53+
54+
1. Install the required dependencies:
55+
56+
```sh
57+
npm install request request-promise @actions/core @vercel/ncc
58+
```
59+
60+
> 🪧 **Note:** You will learn each library purpose in the next steps
61+
62+
1. Review `package.json` to confirm dependencies are listed in the `dependencies` section.
63+
64+
1. Open the `.gitignore` file and add an entry to exclude the `node_modules` directory from being tracked by Git:
65+
66+
```text
67+
node_modules/
68+
```
69+
70+
We don't want to commit `node_modules` because it contains thousands of files that would bloat the repository.
71+
72+
> 🪧 **Note:** Instead, later in the exercise you will bundle your action into a single JavaScript file with all dependencies included.
73+
74+
1. Commit and push your changes:
75+
76+
```sh
77+
git status
78+
git add .
79+
git commit -m "Initialize project"
80+
git push
81+
```
82+
83+
1. With the changes pushed to GitHub, Mona will check your work and share the next steps.
84+
85+
<details>
86+
<summary>Having trouble? 🤷</summary><br/>
87+
88+
- Ensure you are at the repository root before running `npm init -y`.
89+
- Do not commit `node_modules/` to the repository; ensure it's listed in `.gitignore`.
90+
91+
</details>

.github/steps/2-step.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
## Step 2: Create Source Files & Run Locally
2+
3+
Nice! Now that we have the project initialized and dependencies installed, it's time to create the source files for your Dad Jokes GitHub Action.
4+
5+
### 📖 Theory: The GitHub Actions Toolkit
6+
7+
The `@actions/core` library is the main library from the [GitHub Actions Toolkit](https://github.com/actions/toolkit), a collection of packages for building JavaScript GitHub Actions. It provides essential methods to interact with the GitHub Actions runtime environment, accept action inputs, and produce outputs for other workflow steps.
8+
9+
> [!TIP]
10+
> The [GitHub Actions Toolkit](https://github.com/actions/toolkit) includes other useful libraries like `@actions/github` for interacting with the GitHub API and `@actions/artifact` for uploading and downloading artifacts.
11+
>
12+
> Visit the [actions/toolkit](https://github.com/actions/toolkit) repository for more.
13+
14+
15+
### ⌨️ Activity: Implement the Dad Jokes Action
16+
17+
Let's create the source files and implement the logic for your action.
18+
19+
1. Create `src/` directory to hold your JavaScript files:
20+
21+
1. Create `src/joke.js` file to hold the logic for fetching a joke from the `icanhazdadjoke.com` API:
22+
23+
```js
24+
const request = require("request-promise");
25+
26+
const options = {
27+
method: "GET",
28+
uri: "https://icanhazdadjoke.com/",
29+
headers: {
30+
Accept: "application/json",
31+
"User-Agent": "Writing JavaScript action GitHub Skills exercise.",
32+
},
33+
json: true,
34+
};
35+
36+
async function getJoke() {
37+
const res = await request(options);
38+
return res.joke;
39+
}
40+
41+
module.exports = getJoke;
42+
```
43+
44+
The `getJoke` function makes an HTTP GET request to the `icanhazdadjoke.com` API and returns a random dad joke.
45+
46+
We export the `getJoke` function so it can be used in other files.
47+
48+
1. Create `src/main.js` that will be the main entry point for your action:
49+
50+
```js
51+
const getJoke = require("./joke");
52+
const core = require("@actions/core");
53+
54+
async function run() {
55+
const joke = await getJoke();
56+
console.log(joke);
57+
core.setOutput("joke", joke);
58+
}
59+
60+
run();
61+
```
62+
63+
We call the `getJoke` function and follow up with `core.setOutput()` to set the `joke` output of your GitHub Action.
64+
65+
1. Run the action locally to verify it works:
66+
67+
```sh
68+
node src/main.js
69+
```
70+
71+
1. Commit and push:
72+
73+
```sh
74+
git add src/
75+
git commit -m "Add Dad Joke action source files"
76+
git push
77+
```
78+
79+
1. With the changes pushed to GitHub, Mona will check your work and share the next steps.

.github/steps/3-step.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
## Step 3: Bundle the Action
2+
3+
Good job! :tada:
4+
5+
Now that you've created the source files for your Dad Jokes GitHub Action and tested it locally, it's time to bundle the action so it can be used in GitHub workflows.
6+
7+
### 📖 Theory: Bundling Your Action
8+
9+
When someone uses your action in their workflow, GitHub downloads and executes it as a complete package of code. This means you must include any package dependencies required to run the JavaScript code, such as the `@actions/core` and `request-promise` packages your action uses.
10+
11+
Rather than committing your `node_modules` directory (which causes problems with repository size and performance), you can use bundling tools like `@vercel/ncc` to combine your code and dependencies into a single `dist/index.js` file for distribution.
12+
13+
### ⌨️ Activity: Build Setup & Bundle
14+
15+
1. Add a new `build` script to `package.json` (inside the existing `scripts` object):
16+
17+
```json
18+
"scripts": {
19+
// Existing scripts...
20+
"build": "ncc build src/main.js -o dist"
21+
}
22+
```
23+
24+
1. Run the build command. This should create a `dist/` directory with a bundled `index.js` file:
25+
26+
```sh
27+
npm run build
28+
```
29+
30+
1. (optional) Run the bundled action to verify it works:
31+
32+
```sh
33+
node dist/index.js
34+
```
35+
36+
1. Commit and push the changes to the `main` branch:
37+
38+
```sh
39+
git add .
40+
git commit -m "Add ncc build script and bundled dist/index.js"
41+
git push
42+
```
43+
44+
1. With the changes pushed to GitHub, Mona will check your work and share the next steps.

.github/steps/4-step.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
## Step 4: Add Action Metadata
2+
3+
Great work! :tada: You've successfully bundled your Dad Jokes GitHub Action into a single file.
4+
5+
Now it's time to create the **action metadata file** - this special file tells GitHub exactly how to use your action when someone includes it in their workflow!
6+
7+
### 📖 Theory: Action Metadata
8+
9+
Every GitHub Action requires a metadata file that defines how the action should be executed and what parameters it accepts.
10+
11+
#### Metadata File Requirements
12+
13+
The metadata file has specific requirements:
14+
15+
- **Filename**: Must be `action.yml`
16+
- **Required for**: All actions types - JavaScript, [Docker container](https://docs.github.com/en/actions/tutorials/use-containerized-services/create-a-docker-container-action), and [composite action](https://docs.github.com/en/actions/tutorials/create-actions/create-a-composite-action)
17+
- **Format**: Written in YAML syntax
18+
19+
#### Core Metadata Parameters
20+
21+
| Parameter | Description | Required |
22+
| ----------------- | -------------------------------------------------------------- | :------: |
23+
| **`name`** | The name of your action. ||
24+
| **`description`** | A short description of what your action does. ||
25+
| **`author`** | The name of the action's author. ||
26+
| **`inputs`** | Data that the action expects to receive. ||
27+
| **`outputs`** | Data that downstream steps in the workflow can use ||
28+
| **`runs`** | Tells GitHub how to execute your action. ||
29+
| **`branding`** | Color and icon for your action in GitHub Marketplace. ||
30+
31+
#### JavaScript Action `runs` Configuration
32+
33+
For JavaScript actions, the `runs` section needs:
34+
35+
- **`using`**: Which Node.js version to use
36+
- **`main`**: The main JavaScript file to run
37+
38+
> [!TIP]
39+
> For complete details on all available metadata parameters, optional fields, and advanced configurations, see the official [GitHub Actions metadata syntax documentation](https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax).
40+
41+
---
42+
43+
### ⌨️ Activity: Create Metadata File
44+
45+
1. Create `action.yml` at the repository root (same level as `package.json`).
46+
47+
```yaml
48+
name: "Joke Action"
49+
description: "Fetches a random joke and exposes it as an output"
50+
51+
outputs:
52+
joke:
53+
description: "The fetched joke text"
54+
55+
runs:
56+
using: node24
57+
main: dist/index.js
58+
```
59+
60+
1. Commit and push the action metadata file to the `main` branch:
61+
62+
```sh
63+
git add action.yml
64+
git commit -m "Add action metadata file"
65+
git push
66+
```
67+
68+
1. With the changes pushed to GitHub, Mona will check your work and share the next steps.

.github/steps/5-step.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
## Step 5: Create Workflow & Consume Output
2+
3+
Well done! :clap: You've created the Dad Jokes GitHub Action and defined its metadata.
4+
5+
Your action should be ready to use in any GitHub repository now!
6+
7+
### ⌨️ Activity: Author Workflow
8+
9+
Let's see your Dad Jokes action in action by creating a GitHub Actions workflow that uses it!
10+
11+
1. Create a new GitHub Actions workflow file with the following name
12+
13+
```txt
14+
.github/workflows/joke-action.yml
15+
```
16+
17+
1. Add the following contents to the workflow file:
18+
19+
```yaml
20+
name: Joke Action
21+
run-name: {% raw %}Dad Joke for issue ${{ github.event.issue.number }} by ${{ github.event.comment.user.login }}{% endraw %}
22+
23+
on:
24+
issue_comment:
25+
types: [created]
26+
27+
permissions:
28+
issues: write
29+
contents: read
30+
31+
jobs:
32+
joke:
33+
if: startsWith(github.event.comment.body, '/joke')
34+
runs-on: ubuntu-latest
35+
steps:
36+
- uses: actions/checkout@v5
37+
- name: Get Joke
38+
id: get-joke
39+
uses: ./
40+
- name: Create comment
41+
uses: peter-evans/create-or-update-comment@v5
42+
with:
43+
issue-number: {% raw %}${{ github.event.issue.number }}{% endraw %}
44+
body: {% raw %}${{ steps.get-joke.outputs.joke }}{% endraw %}
45+
```
46+
47+
This workflow triggers for all new issue comments in the repository.
48+
49+
Because of the `if` conditional, the `joke` job only runs if the comment starts with `/joke`.
50+
51+
1. Commit and push the workflow file to the `main` branch:
52+
53+
```sh
54+
git add .github/workflows/joke-action.yml
55+
git commit -m "Add workflow to test joke action"
56+
git push
57+
```
58+
59+
60+
1. With the workflow pushed to GitHub, Mona will check your work and share the next steps.

.github/steps/6-step.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
## Step 6: Trigger & Validate
2+
3+
Awesome! :rocket: You've created the Dad Jokes GitHub Action, defined its metadata, and authored a workflow to use it.
4+
5+
The only thing left to do is test it out!
6+
7+
### ⌨️ Activity: Try out your action
8+
9+
1. Create a comment in this issue (or create a new issue) with the text `/joke`
10+
11+
1. Monitor the **Actions** tab for the `Joke Action` workflow to complete:
12+
13+
<img width="400" alt="SCR-20251113-kntg" src="https://github.com/user-attachments/assets/992da295-0123-4688-a068-d289967f2455" />
14+
15+
16+
1. Return to the issue and you should see a new comment posted by `github-actions[bot]` containing a random dad joke!
17+
18+
1. Mona will post the exercise review once your new Dad Joke workflow completes **successfully**!
19+
20+
<details>
21+
<summary>Having trouble? 🤷</summary><br/>
22+
23+
If the workflow doesn't trigger or fails:
24+
- Make sure your comment starts exactly with `/joke`
25+
- Check the Actions tab for error messages
26+
- Verify that your `dist/index.js` file exists and was committed
27+
- If you did any updates to your source code, ensure you re-bundled with `npm run build` and pushed the changes
28+
- Ensure your `action.yml` file is correctly formatted
29+
30+
</details>

0 commit comments

Comments
 (0)