diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..0464eb0 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,6 @@ +{ + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + "ghcr.io/devcontainers/features/node:1": {} + } +} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 8ac6b8c..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "monthly" diff --git a/.github/steps/-step.txt b/.github/steps/-step.txt deleted file mode 100644 index 573541a..0000000 --- a/.github/steps/-step.txt +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/.github/steps/0-welcome.md b/.github/steps/0-welcome.md deleted file mode 100644 index 9ff13a5..0000000 --- a/.github/steps/0-welcome.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/.github/steps/1-initialize-javascript-project.md b/.github/steps/1-initialize-javascript-project.md deleted file mode 100644 index 0394b22..0000000 --- a/.github/steps/1-initialize-javascript-project.md +++ /dev/null @@ -1,85 +0,0 @@ - - -## Step 1: Initialize a new JavaScript project - -_Welcome to the course :tada:_ - -### Configuring a workflow - -Actions are enabled on your repository by default, but we still have to tell our repository to use them. We do this by creating a workflow file in our repository. - -A **workflow** file can be thought of as the recipe for automating a task. They house the start to finish instructions, in the form of `jobs` and `steps`, for what should happen based on specific triggers. - -Your repository can contain multiple **workflow** files that carry out a wide variety of tasks. It is important to consider this when deciding on a name for your **workflow**. The name you choose should reflect the tasks being performed. - -_In our case, we will use this one **workflow** file for many things, which leads us to break this convention for teaching purposes._ - -Read more about [workflows](https://docs.github.com/en/actions/writing-workflows/about-workflows) - -## On to your development environment - -Our JavaScript actions are going to leverage the [GitHub ToolKit](https://github.com/actions/toolkit) for developing GitHub Actions. - -This is an external library that we will install using `npm` which means that you will need [Node.js](https://nodejs.org/) installed. - -We find writing actions to be easier from a local environment vs trying to do everything right here in the repository. Doing these steps locally allows you to use the editor of your choice so that you have all the extensions and snippets you are used to when writing code. - -If you do not have a preferred environment then we suggest following along exactly as you see on the screen, which means you'll need to install [Visual Studio Code](https://code.visualstudio.com/). - -## Don't forget to set up your workstation - -Most of your work going forward will take place away from your Skills repository, so before continuing with the course ensure you have the following installed on your **local machine**. - -1. [ ] [Node.js](https://nodejs.org) -2. [ ] [Visual Studio Code](https://code.visualstudio.com/) or your editor of choice -3. [ ] [Git](https://git-scm.com/) - -### :keyboard: Activity 1: Initialize a new JavaScript project - -Once you have the necessary tools installed locally, follow these steps to begin creating your first action. - -1. Open the **Terminal** (Mac and Linux) or **Command Prompt** (Windows) on your local machine -2. Clone your Skills repo to your local machine: - ```shell - git clone .git - ``` -3. Navigate to the folder you just cloned: - ```shell - cd - ``` -4. We are using branch called `main`. - ```shell - git switch main - ``` -5. Create a new folder for our actions files: - ```shell - mkdir -p .github/actions/joke-action - ``` -6. Navigate to the `joke-action` folder you just created: - ```shell - cd .github/actions/joke-action - ``` -7. Initialize a new project: - ```shell - npm init -y - ``` -8. Install the **request**, **request-promise** and **@actions/core** dependencies using `npm` from the [GitHub ToolKit](https://github.com/actions/toolkit): - ```shell - npm install --save request request-promise @actions/core - ``` -9. Commit those newly added files,we will remove the need to upload **node_modules** in a later step: - ```shell - git add . - git commit -m 'add project dependencies' - ``` -10. Push your changes to your repository: - ```shell - git push - ``` -11. Wait about 20 seconds then refresh this page (the one you're following instructions from). [GitHub Actions](https://docs.github.com/en/actions) will automatically update to the next step. diff --git a/.github/steps/1-step.md b/.github/steps/1-step.md new file mode 100644 index 0000000..d1b67bf --- /dev/null +++ b/.github/steps/1-step.md @@ -0,0 +1,91 @@ +## Step 1: Setting up the project + +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… + +Maybe that’s because your task is a bit _too_ unique 😆 + +**GENERATING DAD JOKES**! 🎭 + +dadjoke-mona + +Since no pre-built action exists for your quirky automation needs, it's time to roll up your sleeves and create your own! + +### ⌨️ Activity: Set up your development environment + +Let's use **GitHub Codespaces** to set up a cloud-based development environment and work in it for the remainder of the exercise! + +1. Right-click the below button to open the **Create Codespace** page in a new tab. Use the default configuration. + + [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/{{full_repo_name}}?quickstart=1) + +1. Confirm the **Repository** field is your copy of the exercise, not the original, then click the green **Create Codespace** button. + + - ✅ Your copy: `/{{full_repo_name}}` + - ❌ Original: `/skills-dev/write-javascript-actions` + +1. Wait a moment for Visual Studio Code to load in your browser. + +1. Verify that **Node.js** is available by opening a terminal and running: + + ```sh + node --version + npm --version + ``` + +
+ Having trouble? 🤷
+ + - Make sure you selected your personal copy of the repository, not the original template. + - If the Codespace fails to start, try refreshing the page and creating a new one. + - Node.js and npm should be pre-installed in the development environment. + +
+ +### ⌨️ Activity: Initialize Project + +Now that your Codespace is ready, let's initialize a new Node.js project and install the dependencies needed for your Dad Jokes action. + +1. Within your GitHub Codespace terminal window initialize a new project: + + ```sh + npm init -y + ``` + +1. Install the required dependencies: + + ```sh + npm install request request-promise @actions/core @vercel/ncc + ``` + + > 🪧 **Note:** You will learn each library purpose in the next steps + +1. Review `package.json` to confirm dependencies are listed in the `dependencies` section. + +1. Open the `.gitignore` file and add an entry to exclude the `node_modules` directory from being tracked by Git: + + ```text + node_modules/ + ``` + + We don't want to commit `node_modules` because it contains thousands of files that would bloat the repository. + + > 🪧 **Note:** Instead, later in the exercise you will bundle your action into a single JavaScript file with all dependencies included. + +1. Commit and push your changes: + + ```sh + git status + git add . + git commit -m "Initialize project" + git push + ``` + +1. With the changes pushed to GitHub, Mona will check your work and share the next steps. + +
+Having trouble? 🤷
+ +- Ensure you are at the repository root before running `npm init -y`. +- Do not commit `node_modules/` to the repository; ensure it's listed in `.gitignore`. + +
diff --git a/.github/steps/2-configure-your-action.md b/.github/steps/2-configure-your-action.md deleted file mode 100644 index 9c4fd27..0000000 --- a/.github/steps/2-configure-your-action.md +++ /dev/null @@ -1,42 +0,0 @@ - - -## Step 2: Configure Your Action - -_Let's keep going! :bike:_ - -### Excellent! - -Now that we have the custom action pre-requisites, let us create **joke-action** action. - -### :keyboard: Activity 1: Configure Your Action - -All of the following steps take place inside of the `.github/actions/joke-action` directory. - -We will start with using the parameters that are **required** and later implement some optional parameters as our action evolves. - -1. Create a new file in: `.github/actions/joke-action/action.yml` -2. Add the following contents to the `.github/actions/joke-action/action.yml` file: - - ```yaml - name: "my joke action" - - description: "use an external API to retrieve and display a joke" - - runs: - using: "node16" - main: "main.js" - ``` - -3. Save the `action.yml` file -4. Commit the changes and push them to the `main` branch: - ```shell - git add action.yml - git commit -m 'create action.yml' - git pull - git push - ``` -5. Wait about 20 seconds then refresh this page (the one you're following instructions from). [GitHub Actions](https://docs.github.com/en/actions) will automatically update to the next step. diff --git a/.github/steps/2-step.md b/.github/steps/2-step.md new file mode 100644 index 0000000..03038db --- /dev/null +++ b/.github/steps/2-step.md @@ -0,0 +1,79 @@ +## Step 2: Create Source Files & Run Locally + +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. + +### 📖 Theory: The GitHub Actions Toolkit + +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. + +> [!TIP] +> 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. +> +> Visit the [actions/toolkit](https://github.com/actions/toolkit) repository for more. + + +### ⌨️ Activity: Implement the Dad Jokes Action + +Let's create the source files and implement the logic for your action. + +1. Create `src/` directory to hold your JavaScript files: + +1. Create `src/joke.js` file to hold the logic for fetching a joke from the `icanhazdadjoke.com` API: + + ```js + const request = require("request-promise"); + + const options = { + method: "GET", + uri: "https://icanhazdadjoke.com/", + headers: { + Accept: "application/json", + "User-Agent": "Writing JavaScript action GitHub Skills exercise.", + }, + json: true, + }; + + async function getJoke() { + const res = await request(options); + return res.joke; + } + + module.exports = getJoke; + ``` + + The `getJoke` function makes an HTTP GET request to the `icanhazdadjoke.com` API and returns a random dad joke. + + We export the `getJoke` function so it can be used in other files. + +1. Create `src/main.js` that will be the main entry point for your action: + + ```js + const getJoke = require("./joke"); + const core = require("@actions/core"); + + async function run() { + const joke = await getJoke(); + console.log(joke); + core.setOutput("joke", joke); + } + + run(); + ``` + + We call the `getJoke` function and follow up with `core.setOutput()` to set the `joke` output of your GitHub Action. + +1. Run the action locally to verify it works: + + ```sh + node src/main.js + ``` + +1. Commit and push: + + ```sh + git add src/ + git commit -m "Add Dad Joke action source files" + git push + ``` + +1. With the changes pushed to GitHub, Mona will check your work and share the next steps. diff --git a/.github/steps/3-create-metadata-file.md b/.github/steps/3-create-metadata-file.md deleted file mode 100644 index ce26a39..0000000 --- a/.github/steps/3-create-metadata-file.md +++ /dev/null @@ -1,64 +0,0 @@ - - -## Step 3: Create the metadata file - -_Nice work configuring your action :smile:_ - -## Action metadata - -Every GitHub Action that we write needs to be accompanied by a metadata file. This file has a few rules to it, as are indicated below: - -- Filename **must** be `action.yml`. -- Required for both Docker container and JavaScript actions. -- Written in YAML syntax. - -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. | :x: | -| Outputs | Specifies the data that subsequent actions can use later in the workflow after the action that defines these outputs has run. | :x: | -| 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. | :x: | - ---- - -Read more about [Action metadata](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions) - -### :keyboard: Activity 1: Create the metadata file - -All of the following steps take place inside of the `.github/actions/joke-action` directory. - -Our action does not require much metadata for it to run correctly. We will not be accepting any inputs, we will however be setting a single output this time. - -1. Update the action metadata file `.github/actions/joke-action/action.yml` with the following content: - - ```yaml - name: "my joke action" - - description: "use an external API to retrieve and display a joke" - - outputs: - joke-output: - description: The resulting joke from the icanhazdadjokes API - - runs: - using: "node16" - main: "main.js" - ``` - -2. Save the `action.yml` file -3. Commit the changes and push them to GitHub: - ```shell - git add action.yml - git pull - git commit -m 'add metadata for the joke action' - git push - ``` -4. Wait about 20 seconds then refresh this page (the one you're following instructions from). [GitHub Actions](https://docs.github.com/en/actions) will automatically update to the next step. diff --git a/.github/steps/3-step.md b/.github/steps/3-step.md new file mode 100644 index 0000000..f7f360b --- /dev/null +++ b/.github/steps/3-step.md @@ -0,0 +1,44 @@ +## Step 3: Bundle the Action + +Good job! :tada: + +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. + +### 📖 Theory: Bundling Your Action + +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. + +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. + +### ⌨️ Activity: Build Setup & Bundle + +1. Add a new `build` script to `package.json` (inside the existing `scripts` object): + + ```json + "scripts": { + // Existing scripts... + "build": "ncc build src/main.js -o dist" + } + ``` + +1. Run the build command. This should create a `dist/` directory with a bundled `index.js` file: + + ```sh + npm run build + ``` + +1. (optional) Run the bundled action to verify it works: + + ```sh + node dist/index.js + ``` + +1. Commit and push the changes to the `main` branch: + + ```sh + git add . + git commit -m "Add ncc build script and bundled dist/index.js" + git push + ``` + +1. With the changes pushed to GitHub, Mona will check your work and share the next steps. \ No newline at end of file diff --git a/.github/steps/4-create-javascript-files-for-action.md b/.github/steps/4-create-javascript-files-for-action.md deleted file mode 100644 index 2039bd3..0000000 --- a/.github/steps/4-create-javascript-files-for-action.md +++ /dev/null @@ -1,163 +0,0 @@ - - -## Step 4: Create the JavaScript files for your action - -_Good job adding the metadata file! :dancer:_ - -## Files - -As you probably know, in JavaScript and other programming languages it is common to break your code into modules so that it is easier to read and maintain going forward. Since JavaScript actions are just programs written in JavaScript that run based on a specific trigger we are able to make our action code modular as well. - -To do so we will create two files. One of them will contain the logic to reach out to an external API and retrieve a joke for us, the other will call that module and print the joke to the actions console for us. We will be extending this functionality in our third and final action. - -### Fetching a joke - -**Joke API** - -The first file will be `joke.js` and it will fetch our joke for us. We will be using the [icanhazdadjoke API](https://icanhazdadjoke.com/api) for our action. This API does not require any authentication, but it does however that we set a few parameters in the [HTTP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers). We need to point out what those are when we get to the code, however it is outside of the scope of this course to cover HTTP in any depth. - -When we make our request to this API we will get back a JSON Object in the response. That Object looks like this: - -``` -{ - id: '0LuXvkq4Muc', - joke: "I knew I shouldn't steal a mixer from work, but it was a whisk I was willing to take.", - status: 200 -} -``` - -It contains 3 key/value pairs of data that we can use in our own program or service. In our case, we are only interested in the `joke` field. - -**Joke Module** - -We will create a file named `joke.js` and it will reside in the `.github/actions/joke-action` directory. - -The joke module will look like this: - -```javascript -const request = require("request-promise"); - -const options = { - method: "GET", - uri: "https://icanhazdadjoke.com/", - headers: { - Accept: "application/json", - "User-Agent": "Writing JavaScript action GitHub Skills course.", - }, - json: true, -}; - -async function getJoke() { - const res = await request(options); - return res.joke; -} - -module.exports = getJoke; -``` - -Need an advanced description of the joke.js source code? - -We first bring in the `request-promise` library that we installed earlier using `npm`. - -Next we define a set of `options` that the `request-promise` library will use when it makes the request. - -Read more about [request-promise](https://github.com/request/request-promise/) - -Inside of the `options` block we add a key named `headers`. This defines the HTTP headers that the **icanhazdadjoke** API expects in each request that comes it's way. - -**icanhazdadjoke** cares the most about the keys, **Accept** and **User-Agent**, so we need to make sure we fill them in. - -Next we define an **asynchronous JavaScript function** to make the request for us, storing the JSON Object that is returned in a variable named `res`. - -Lastly, we `return` the `res.joke` which is only the value associated with the `joke` key of the JSON Object. This value will be random every time our action runs because of how we are interacting with the **icanhazdadjoke** API. - -This file finishes up by exporting the newly created function so that we can use it in our `main.js` file. - -### Creating the main entry point for your action - -**Main Module** - -We will also create a file named `main.js` that resides inside of the `.github/actions/joke-action` directory. - -That file will look like this: - -```javascript -const getJoke = require("./joke"); -const core = require("@actions/core"); - -async function run() { - const joke = await getJoke(); - console.log(joke); - core.setOutput("joke-output", joke); -} - -run(); -``` - -Need an advanced description of the main.js source code? - -Like we did in the `joke.js` file, we are first going to bring in our dependencies. Only this time, our dependencies include something we wrote! To do that we simply use `require()` to point to the location of the file we wish to bring in. - -We also bring in `@actions/core` so that we can set the output of our action. - -Next we write another **asynchronous JavaScript function** that stores the return value of `getJoke()` in a variable called **joke**. - -Then we log the joke to the console. - -Finally we finish the function with by setting the contents of the joke as the value of the `joke-output` output parameter. We will use this output later in the course. -_Don't forget to call the `run()` function._ - -### :keyboard: Activity 1: Creating the JavaScript files for your new action. - -1. Create and add the following contents to the `.github/actions/joke-action/joke.js` file: - - ```javascript - const request = require("request-promise"); - - const options = { - method: "GET", - uri: "https://icanhazdadjoke.com/", - headers: { - Accept: "application/json", - "User-Agent": "Writing JavaScript action GitHub Skills course.", - }, - json: true, - }; - - async function getJoke() { - const res = await request(options); - return res.joke; - } - - module.exports = getJoke; - ``` - -2. Save the `joke.js` file. -3. Create and add the following contents to the `.github/actions/joke-action/main.js` file: - - ```javascript - const getJoke = require("./joke"); - const core = require("@actions/core"); - - async function run() { - const joke = await getJoke(); - console.log(joke); - core.setOutput("joke-output", joke); - } - - run(); - ``` - -4. Save the `main.js` file. -5. Commit the changes to this branch and push them to GitHub: - ```shell - git add joke.js main.js - git commit -m 'creating joke.js and main.js' - git pull - git push - ``` -6. Wait about 20 seconds then refresh this page (the one you're following instructions from). [GitHub Actions](https://docs.github.com/en/actions) will automatically update to the next step. diff --git a/.github/steps/4-step.md b/.github/steps/4-step.md new file mode 100644 index 0000000..3f454d4 --- /dev/null +++ b/.github/steps/4-step.md @@ -0,0 +1,68 @@ +## Step 4: Add Action Metadata + +Great work! :tada: You've successfully bundled your Dad Jokes GitHub Action into a single file. + +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! + +### 📖 Theory: Action Metadata + +Every GitHub Action requires a metadata file that defines how the action should be executed and what parameters it accepts. + +#### Metadata File Requirements + +The metadata file has specific requirements: + +- **Filename**: Must be `action.yml` +- **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) +- **Format**: Written in YAML syntax + +#### Core Metadata Parameters + +| Parameter | Description | Required | +| ----------------- | -------------------------------------------------------------- | :------: | +| **`name`** | The name of your action. | ✅ | +| **`description`** | A short description of what your action does. | ✅ | +| **`author`** | The name of the action's author. | ○ | +| **`inputs`** | Data that the action expects to receive. | ○ | +| **`outputs`** | Data that downstream steps in the workflow can use | ○ | +| **`runs`** | Tells GitHub how to execute your action. | ✅ | +| **`branding`** | Color and icon for your action in GitHub Marketplace. | ○ | + +#### JavaScript Action `runs` Configuration + +For JavaScript actions, the `runs` section needs: + +- **`using`**: Which Node.js version to use +- **`main`**: The main JavaScript file to run + +> [!TIP] +> 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). + +--- + +### ⌨️ Activity: Create Metadata File + +1. Create `action.yml` at the repository root (same level as `package.json`). + + ```yaml + name: "Joke Action" + description: "Fetches a random joke and exposes it as an output" + + outputs: + joke: + description: "The fetched joke text" + + runs: + using: node24 + main: dist/index.js + ``` + +1. Commit and push the action metadata file to the `main` branch: + + ```sh + git add action.yml + git commit -m "Add action metadata file" + git push + ``` + +1. With the changes pushed to GitHub, Mona will check your work and share the next steps. \ No newline at end of file diff --git a/.github/steps/5-add-action-to-workflow-file.md b/.github/steps/5-add-action-to-workflow-file.md deleted file mode 100644 index f556695..0000000 --- a/.github/steps/5-add-action-to-workflow-file.md +++ /dev/null @@ -1,42 +0,0 @@ - - -## Step 5: Add your action to the workflow file - -_Great job! :tada:_ - -All of the following steps will add the action to the workflow file that’s already in the repo [`my-workflow.yml` file](/.github/workflows/my-workflow.yml) - -### :keyboard: Activity 1: Edit the custom action at the bottom of the workflow file. - -```yaml -- name: ha-ha - uses: ./.github/actions/joke-action -``` - -Here is what the full file should look like (we’re using issues instead of the pull request event and removing the reference to the hello world action.) - -```yaml -name: JS Actions - -on: - issues: - types: [labeled] - -jobs: - action: - if: ${{ !github.event.repository.is_template }} - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: ha-ha - uses: ./.github/actions/joke-action -``` - -You can make these changes in your repository by opening [`my-workflow.yml`](/.github/workflows/my-workflow.yml) in another browser tab and [editing the file directly](https://docs.github.com/en/repositories/working-with-files/managing-files/editing-files). Make sure to select the `Commit directly to the main branch` option. - -Wait about 20 seconds then refresh this page (the one you're following instructions from). [GitHub Actions](https://docs.github.com/en/actions) will automatically update to the next step. diff --git a/.github/steps/5-step.md b/.github/steps/5-step.md new file mode 100644 index 0000000..a0e7775 --- /dev/null +++ b/.github/steps/5-step.md @@ -0,0 +1,60 @@ +## Step 5: Create Workflow & Consume Output + +Well done! :clap: You've created the Dad Jokes GitHub Action and defined its metadata. + +Your action should be ready to use in any GitHub repository now! + +### ⌨️ Activity: Author Workflow + +Let's see your Dad Jokes action in action by creating a GitHub Actions workflow that uses it! + +1. Create a new GitHub Actions workflow file with the following name + + ```txt + .github/workflows/joke-action.yml + ``` + +1. Add the following contents to the workflow file: + + ```yaml + name: Joke Action + run-name: {% raw %}Dad Joke for issue ${{ github.event.issue.number }} by ${{ github.event.comment.user.login }}{% endraw %} + + on: + issue_comment: + types: [created] + + permissions: + issues: write + contents: read + + jobs: + joke: + if: startsWith(github.event.comment.body, '/joke') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Get Joke + id: get-joke + uses: ./ + - name: Create comment + uses: peter-evans/create-or-update-comment@v5 + with: + issue-number: {% raw %}${{ github.event.issue.number }}{% endraw %} + body: {% raw %}${{ steps.get-joke.outputs.joke }}{% endraw %} + ``` + + This workflow triggers for all new issue comments in the repository. + + Because of the `if` conditional, the `joke` job only runs if the comment starts with `/joke`. + +1. Commit and push the workflow file to the `main` branch: + + ```sh + git add .github/workflows/joke-action.yml + git commit -m "Add workflow to test joke action" + git push + ``` + + +1. With the workflow pushed to GitHub, Mona will check your work and share the next steps. \ No newline at end of file diff --git a/.github/steps/6-step.md b/.github/steps/6-step.md new file mode 100644 index 0000000..9e67037 --- /dev/null +++ b/.github/steps/6-step.md @@ -0,0 +1,30 @@ +## Step 6: Trigger & Validate + +Awesome! :rocket: You've created the Dad Jokes GitHub Action, defined its metadata, and authored a workflow to use it. + +The only thing left to do is test it out! + +### ⌨️ Activity: Try out your action + +1. Create a comment in this issue (or create a new issue) with the text `/joke` + +1. Monitor the **Actions** tab for the `Joke Action` workflow to complete: + + SCR-20251113-kntg + + +1. Return to the issue and you should see a new comment posted by `github-actions[bot]` containing a random dad joke! + +1. Mona will post the exercise review once your new Dad Joke workflow completes **successfully**! + +
+ Having trouble? 🤷
+ + If the workflow doesn't trigger or fails: + - Make sure your comment starts exactly with `/joke` + - Check the Actions tab for error messages + - Verify that your `dist/index.js` file exists and was committed + - If you did any updates to your source code, ensure you re-bundled with `npm run build` and pushed the changes + - Ensure your `action.yml` file is correctly formatted + +
diff --git a/.github/steps/6-trigger-action.md b/.github/steps/6-trigger-action.md deleted file mode 100644 index c5898b9..0000000 --- a/.github/steps/6-trigger-action.md +++ /dev/null @@ -1,19 +0,0 @@ - - -## Step 6: Trigger the joke action - -_Great job! :heart:_ - -Everything is all set up and now we are ready to start laughing. You will find you have some joke related labels available to you in this repository. You don't have to use them, any label will trigger our workflow, but the easiest way to follow along would be to use suggested labels. - -### Trigger a joke - -1. Open issue #1 in the "Issues tab" -2. Apply the `first-joke` label to the issue -3. Wait a few seconds and then apply the `second-joke` label to the issue -4. Check the `JS Actions` workflow results on the "Actions tab" -5. Wait about 20 seconds then refresh this page (the one you're following instructions from). [GitHub Actions](https://docs.github.com/en/actions) will automatically update to the next step. diff --git a/.github/steps/X-finish.md b/.github/steps/X-finish.md deleted file mode 100644 index 58521c1..0000000 --- a/.github/steps/X-finish.md +++ /dev/null @@ -1,34 +0,0 @@ - - -## Finish - -celebrate - -### Congratulations, you've completed this course! - -In this course, you've learned a lot about developing custom actions using JavaScript and Actions Toolkit. - -## Publishing your actions - -Publishing your actions is a great way to help others in your team and across the GitHub community. Although actions do not need to be published to be consumed, by adding them to the marketplace you make them easier to find. - -Some notable actions you will find on the marketplace are: - -- [Actions for Discord](https://github.com/marketplace/actions/actions-for-discord) -- [GitHub Action for Slack](https://github.com/marketplace/actions/github-action-for-slack) -- [Jekyll action](https://github.com/marketplace/actions/jekyll-action) -- [Run Jest](https://github.com/marketplace/actions/run-jest) - -And that just scratches the surface of the 1600+ and counting actions you will find on the marketplace - -Follow [this guide](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/publishing-actions-in-github-marketplace#publishing-an-action) to learn how to publish your actions to the GitHub Marketplace - -### What's next? - -- [Take another GitHub Skills course](https://github.com/skills). -- We'd love to hear what you thought of this course in our [discussion board](https://github.com/orgs/skills/discussions/categories/write-javascript-actions). -- [Read the GitHub Getting Started docs](https://docs.github.com/en/get-started). -- To find projects to contribute to, check out [GitHub Explore](https://github.com/explore). diff --git a/.github/steps/x-review.md b/.github/steps/x-review.md new file mode 100644 index 0000000..427aa01 --- /dev/null +++ b/.github/steps/x-review.md @@ -0,0 +1,23 @@ +## Review + +_Congratulations, you've completed this exercise and learned how to write JavaScript GitHub Actions!_ + +celebrate + +Here's a recap of your accomplishments: + +- **Initialized a Node.js project** with proper dependencies and excluded `node_modules` with a `.gitignore` configuration +- **Created JavaScript source files** implementing a Dad Jokes action and leveraged the `@actions/core` library to handle action outputs +- **Bundled your action** into a single distributable `dist/index.js` file +- **Created action metadata** (`action.yml`) defining name, description, outputs, and execution parameters +- **Authored a GitHub Actions workflow** that uses your custom action +- **Tested your action** by triggering it with issue comments and validating the output + +### What's next? + +- Check out the other [GitHub Skills exercises](https://learn.github.com/skills). +- Try using your Dad Jokes action in your other repositories to add some humor to your workflows! + +- **Create your next action** using GitHub's template repositories with best practices like tests and linting already built-in: + - [actions/javascript-action](https://github.com/actions/javascript-action) template repository + - [actions/typescript-action](https://github.com/actions/typescript-action) template repository \ No newline at end of file diff --git a/.github/workflows/0-start-exercise.yml b/.github/workflows/0-start-exercise.yml new file mode 100644 index 0000000..9344d46 --- /dev/null +++ b/.github/workflows/0-start-exercise.yml @@ -0,0 +1,66 @@ +name: Step 0 # Start Exercise + +on: + workflow_dispatch: + push: + branches: + - main + +permissions: + contents: write + actions: write + issues: write + +env: + STEP_1_FILE: ".github/steps/1-step.md" + +jobs: + start_exercise: + if: | + !github.event.repository.is_template + name: Start Exercise + uses: skills/exercise-toolkit/.github/workflows/start-exercise.yml@v0.7.3 + with: + exercise-title: "Write JavaScript Actions" + intro-message: "Learn to create and use custom JavaScript actions in your GitHub workflows" + + post_next_step_content: + name: Post next step content + runs-on: ubuntu-latest + needs: [start_exercise] + env: + ISSUE_NUMBER: ${{ needs.start_exercise.outputs.issue-number }} + ISSUE_REPOSITORY: ${{ github.repository }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Create comment - add step content + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: ${{ env.STEP_1_FILE }} + vars: | + full_repo_name: ${{ github.repository }} + + - name: Create comment - watching for progress + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md + + - name: Enable next step workflow + run: | + gh workflow enable "Step 1" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/0-welcome.yml b/.github/workflows/0-welcome.yml deleted file mode 100644 index 81d1011..0000000 --- a/.github/workflows/0-welcome.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Step 0, Welcome - -# This step triggers after the learner creates a new repository from the template. -# This workflow updates from step 0 to step 1. - -# When creating a repository from a template, there is variability in the -# order and timing of events that fire and when workflow triggers are registered. -# Given that, these triggers are purposely broad to ensure this workflow is always triggered. -# The conditions within the on_start job are to ensure it is only fully executed once. -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows -on: - push: - branches: - - main - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - issues: write - -jobs: - # Get the current step to only run the main job when the learner is on the same step. - get_current_step: - name: Check current step number - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: get_step - run: | - echo "current_step=$(cat ./.github/steps/-step.txt)" >> $GITHUB_OUTPUT - outputs: - current_step: ${{ steps.get_step.outputs.current_step }} - - on_start: - name: On start - needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 0. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions - if: >- - ${{ !github.event.repository.is_template - && needs.get_current_step.outputs.current_step == 0 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. - runs-on: ubuntu-latest - - steps: - # We'll need to check out the repository so that we can edit the README. - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Let's get all the branches. - - # This is required to establish labels. - # after being created from the template repository. - - name: Prepare labels - run: | - echo "Make sure we are on step 0" - if [ "$(cat .github/steps/-step.txt)" != 0 ] - then - echo "Current step is not 0" - exit 0 - fi - echo "Create label 1" - gh label create "first joke" -d "first joke for lab" -f - echo "Create label 2" - gh label create "second joke" -d "second joke for lab" -f - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # This is required to create issues. - # after being created from the template repository. - - name: Prepare issues - run: | - echo "Make sure we are on step 0" - if [ "$(cat .github/steps/-step.txt)" != 0 ] - then - echo "Current step is not 0" - exit 0 - fi - echo "Create issue #1 from file" - gh issue create --title "Create Custom Action" --body "Implement custom action using JavaScript" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # Update README from step 0 to step 1. - - name: Update to step 1 - uses: skills/action-update-step@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - from_step: 0 - to_step: 1 diff --git a/.github/workflows/1-initialize-javascript-project.yml b/.github/workflows/1-initialize-javascript-project.yml deleted file mode 100644 index b10da80..0000000 --- a/.github/workflows/1-initialize-javascript-project.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Step 1, Initialize JavaScript Project - -# This step listens for the learner pushing a commit to `main`. -# This workflow updates from step 1 to step 2. - -# This will run every time we push a commit to `main`. -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows - -on: - workflow_dispatch: - push: - branches: - - main - -permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. - contents: write - -jobs: - # Get the current step to only run the main job when the learner is on the same step. - get_current_step: - name: Check current step number - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: get_step - run: | - echo "current_step=$(cat ./.github/steps/-step.txt)" >> $GITHUB_OUTPUT - outputs: - current_step: ${{ steps.get_step.outputs.current_step }} - - on_commit_contains_required_dependendencies: - name: Check if main branch has the required action dependencies - needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 1. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions - if: >- - ${{ !github.event.repository.is_template - && needs.get_current_step.outputs.current_step == 1 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Let's get all the branches. - - - name: Dump GitHub comment context - id: github_comment_step - env: - COMMENT_CONTEXT: ${{ toJson(github.event) }} - run: echo "$COMMENT_CONTEXT" - - # Check if NPM package.json exists in the expected location. - - name: Check file existence - id: check_files - uses: andstor/file-existence-action@v3 - with: - files: ".github/actions/joke-action/package.json" - - # Update README from step 1 to step 2. - - name: Update to step 2 - if: steps.check_files.outputs.files_exists == 'true' - uses: skills/action-update-step@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - from_step: 1 - to_step: 2 diff --git a/.github/workflows/1-step.yml b/.github/workflows/1-step.yml new file mode 100644 index 0000000..f87d53f --- /dev/null +++ b/.github/workflows/1-step.yml @@ -0,0 +1,204 @@ +name: Step 1 + +on: + push: + branches: + - main + paths: + - "package.json" + - ".gitignore" + +permissions: + contents: read + actions: write + issues: write + +env: + STEP_2_FILE: ".github/steps/2-step.md" + +jobs: + find_exercise: + if: github.run_number != 1 + name: Find Exercise Issue + uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 + + check_step_work: + name: Check step work + runs-on: ubuntu-latest + needs: [find_exercise] + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Find last comment + id: find-last-comment + uses: peter-evans/find-comment@v3 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + direction: last + + - name: Update comment - checking work + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + file: exercise-toolkit/markdown-templates/step-feedback/checking-work.md + edit-mode: replace + + # START: Check practical exercise + + - name: Check if package.json file exists + id: check-package-json + continue-on-error: true + uses: skills/exercise-toolkit/actions/file-exists@v0.7.0 + with: + file: package.json + + - name: Check for @actions/core dependency + id: check-core-dep + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: package.json + keyphrase: "@actions/core" + + - name: Check for request dependency + id: check-request-dep + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: package.json + keyphrase: "request" + + - name: Check for request-promise dependency + id: check-request-promise-dep + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: package.json + keyphrase: "request-promise" + + - name: Check for @vercel/ncc dependency + id: check-ncc-dep + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: package.json + keyphrase: "@vercel/ncc" + + - name: Check .gitignore excludes node_modules + id: check-gitignore + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: .gitignore + keyphrase: "node_modules/" + + - name: Check node_modules is not committed + id: check-node-modules-not-committed + continue-on-error: true + run: | + if [ -d "node_modules" ] || find . -name "node_modules" -type d | grep -q .; then + found_dirs=$(find . -name "node_modules" -type d) + echo "❌ Found node_modules directory in repository" + echo "$found_dirs" + echo "STEP_MESSAGE=Found node_modules committed to repository. Remove it from the repository." >> $GITHUB_OUTPUT + exit 1 + else + echo "✅ No node_modules directory found in repository" + echo "STEP_MESSAGE=node_modules properly excluded from repository" >> $GITHUB_OUTPUT + fi + + - name: Update comment - step results + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + edit-mode: replace + file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md + vars: | + step_number: 1 + results_table: + - description: "package.json file exists" + passed: ${{ steps.check-package-json.outcome == 'success' }} + - description: "@actions/core dependency present" + passed: ${{ steps.check-core-dep.outcome == 'success' }} + - description: "request dependency present" + passed: ${{ steps.check-request-dep.outcome == 'success' }} + - description: "request-promise dependency present" + passed: ${{ steps.check-request-promise-dep.outcome == 'success' }} + - description: "@vercel/ncc dependency present" + passed: ${{ steps.check-ncc-dep.outcome == 'success' }} + - description: ".gitignore excludes node_modules/" + passed: ${{ steps.check-gitignore.outcome == 'success' }} + - description: "${{ steps.check-node-modules-not-committed.outputs.STEP_MESSAGE }}" + passed: ${{ steps.check-node-modules-not-committed.outcome == 'success' }} + + # END: Check practical exercise + + - name: Fail job if not all checks passed + if: contains(steps.*.outcome, 'failure') + run: exit 1 + + post_next_step_content: + name: Post next step content + needs: [find_exercise, check_step_work] + runs-on: ubuntu-latest + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Create comment - step finished + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md + vars: | + next_step_number: 2 + + - name: Create comment - add step content + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: ${{ env.STEP_2_FILE }} + + - name: Create comment - watching for progress + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md + + - name: Disable current workflow and enable next one + run: | + gh workflow disable "${{github.workflow}}" + gh workflow enable "Step 2" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/2-configure-your-action.yml b/.github/workflows/2-configure-your-action.yml deleted file mode 100644 index 64e192b..0000000 --- a/.github/workflows/2-configure-your-action.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Step 2, Configure Your Action - -# This step listens for the learner pushing a commit to `main`. -# This workflow updates from step 2 to step 3. - -# This will run every time we push a commit to `main`. -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows -on: - workflow_dispatch: - push: - branches: - - main - -permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. - contents: write - -jobs: - # Get the current step to only run the main job when the learner is on the same step. - get_current_step: - name: Check current step number - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: get_step - run: | - echo "current_step=$(cat ./.github/steps/-step.txt)" >> $GITHUB_OUTPUT - outputs: - current_step: ${{ steps.get_step.outputs.current_step }} - - on_check_action_file_added: - name: Check if the action.yml file was added - needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 2. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions - if: >- - ${{ !github.event.repository.is_template - && needs.get_current_step.outputs.current_step == 2 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. - runs-on: ubuntu-latest - - steps: - # We'll need to check out the repository so that we can edit the README. - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Let's get all the branches. - - - name: Dump GitHub comment context - id: github_comment_step - env: - COMMENT_CONTEXT: ${{ toJson(github.event) }} - run: echo "$COMMENT_CONTEXT" - - # Check if NPM package.json exists in the expected location. - - name: Check file existence - id: check_files - uses: andstor/file-existence-action@v3 - with: - files: ".github/actions/joke-action/action.yml" - - # Update README from step 2 to step 3. - - name: Update to step 3 - if: steps.check_files.outputs.files_exists == 'true' - uses: skills/action-update-step@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - from_step: 2 - to_step: 3 diff --git a/.github/workflows/2-step.yml b/.github/workflows/2-step.yml new file mode 100644 index 0000000..07b3f93 --- /dev/null +++ b/.github/workflows/2-step.yml @@ -0,0 +1,146 @@ +name: Step 2 + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - "src/main.js" + - "src/joke.js" + +permissions: + contents: read + actions: write + issues: write + +env: + STEP_3_FILE: ".github/steps/3-step.md" + +jobs: + find_exercise: + name: Find Exercise Issue + uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 + + check_step_work: + name: Check step work + runs-on: ubuntu-latest + needs: [find_exercise] + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Find last comment + id: find-last-comment + uses: peter-evans/find-comment@v3 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + direction: last + + - name: Update comment - checking work + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + file: exercise-toolkit/markdown-templates/step-feedback/checking-work.md + edit-mode: replace + + # START: Check practical exercise + + - name: Check if src/main.js exists + id: check-main-js + continue-on-error: true + uses: skills/exercise-toolkit/actions/file-exists@v0.7.0 + with: + file: src/main.js + + - name: Check if src/joke.js exists + id: check-joke-js + continue-on-error: true + uses: skills/exercise-toolkit/actions/file-exists@v0.7.0 + with: + file: src/joke.js + + - name: Update comment - step results + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + edit-mode: replace + file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md + vars: | + step_number: 2 + results_table: + - description: "Checked for src/main.js file" + passed: ${{ steps.check-main-js.outcome == 'success' }} + - description: "Checked for src/joke.js file" + passed: ${{ steps.check-joke-js.outcome == 'success' }} + + # END: Check practical exercise + + - name: Fail job if not all checks passed + if: contains(steps.*.outcome, 'failure') + run: exit 1 + + post_next_step_content: + name: Post next step content + needs: [find_exercise, check_step_work] + runs-on: ubuntu-latest + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Create comment - step finished + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md + vars: | + next_step_number: 3 + + - name: Create comment - add step content + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: ${{ env.STEP_3_FILE }} + + - name: Create comment - watching for progress + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md + + - name: Disable current workflow and enable next one + run: | + gh workflow disable "${{github.workflow}}" + gh workflow enable "Step 3" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/3-create-metadata-file.yml b/.github/workflows/3-create-metadata-file.yml deleted file mode 100644 index 538efae..0000000 --- a/.github/workflows/3-create-metadata-file.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Step 3, Create Metadata File - -# This step listens for the learner pushing a commit to `main`. -# This workflow updates from step 3 to step 4. - -# This will run every time we push a commit to `main`. -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows -on: - workflow_dispatch: - push: - branches: [main] - -permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. - contents: write - -env: - EXPECTED_METADATA: outputs - -jobs: - # Get the current step to only run the main job when the learner is on the same step. - get_current_step: - name: Check current step number - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: get_step - run: | - echo "current_step=$(cat ./.github/steps/-step.txt)" >> $GITHUB_OUTPUT - outputs: - current_step: ${{ steps.get_step.outputs.current_step }} - - on_action_file_contains_expected_metadata: - name: Check if the action.yml file contains the expected metadata - needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 3. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions - if: >- - ${{ !github.event.repository.is_template - && needs.get_current_step.outputs.current_step == 3 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. - runs-on: ubuntu-latest - - steps: - # We'll need to check out the repository so that we can edit the README. - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Let's get all the branches. - - - name: Dump GitHub comment context - id: github_comment_step - env: - COMMENT_CONTEXT: ${{ toJson(github.event) }} - run: echo "$COMMENT_CONTEXT" - - # Check if action.yml file contains metadata. - - name: Read action file contents - id: read_action_yml_file - uses: andstor/file-reader-action@v1 - with: - path: ".github/actions/joke-action/action.yml" - - # Update README to from step 3 to step 4. - - name: Update to step 4 - if: (contains(steps.read_action_yml_file.outputs.contents, ${{ env.EXPECTED_METADATA }}) - uses: skills/action-update-step@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - from_step: 3 - to_step: 4 diff --git a/.github/workflows/3-step.yml b/.github/workflows/3-step.yml new file mode 100644 index 0000000..a6e954d --- /dev/null +++ b/.github/workflows/3-step.yml @@ -0,0 +1,147 @@ +name: Step 3 + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - "package.json" + - "dist/index.js" + +permissions: + contents: read + actions: write + issues: write + +env: + STEP_4_FILE: ".github/steps/4-step.md" + +jobs: + find_exercise: + name: Find Exercise Issue + uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 + + check_step_work: + name: Check step work + runs-on: ubuntu-latest + needs: [find_exercise] + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Find last comment + id: find-last-comment + uses: peter-evans/find-comment@v3 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + direction: last + + - name: Update comment - checking work + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + file: exercise-toolkit/markdown-templates/step-feedback/checking-work.md + edit-mode: replace + + # START: Check practical exercise + + - name: Check for build script in package.json + id: check-build-script + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: package.json + keyphrase: "ncc build src/main.js -o dist" + + - name: Check if dist/index.js exists + id: check-dist-index + continue-on-error: true + uses: skills/exercise-toolkit/actions/file-exists@v0.7.0 + with: + file: dist/index.js + + - name: Update comment - step results + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + edit-mode: replace + file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md + vars: | + step_number: 3 + results_table: + - description: "Build script present in package.json" + passed: ${{ steps.check-build-script.outcome == 'success' }} + - description: "dist/index.js generated" + passed: ${{ steps.check-dist-index.outcome == 'success' }} + + # END: Check practical exercise + + - name: Fail job if not all checks passed + if: contains(steps.*.outcome, 'failure') + run: exit 1 + + post_next_step_content: + name: Post next step content + needs: [find_exercise, check_step_work] + runs-on: ubuntu-latest + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Create comment - step finished + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md + vars: | + next_step_number: 4 + + - name: Create comment - add step content + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: ${{ env.STEP_4_FILE }} + + - name: Create comment - watching for progress + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md + + - name: Disable current workflow and enable next one + run: | + gh workflow disable "${{github.workflow}}" + gh workflow enable "Step 4" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/4-create-javascript-files-for-action.yml b/.github/workflows/4-create-javascript-files-for-action.yml deleted file mode 100644 index 25c2880..0000000 --- a/.github/workflows/4-create-javascript-files-for-action.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: Step 4, Create JavaScript Files For Action - -# This step listens for the learner pushing a commit to `main`. -# This workflow updates from step 4 to step 5. - -# This will run every time we push a commit to `main` -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows -on: - workflow_dispatch: - push: - branches: [main] - -permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. - contents: write - -jobs: - # Get the current step to only run the main job when the learner is on the same step. - get_current_step: - name: Check current step number - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: get_step - run: | - echo "current_step=$(cat ./.github/steps/-step.txt)" >> $GITHUB_OUTPUT - outputs: - current_step: ${{ steps.get_step.outputs.current_step }} - - on_javascript_files_added: - name: Check if JavaScript files were added - needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 4. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions - if: >- - ${{ !github.event.repository.is_template - && needs.get_current_step.outputs.current_step == 4 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. - runs-on: ubuntu-latest - - steps: - # We'll need to check out the repository so that we can edit the README. - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Let's get all the branches. - - - name: Dump GitHub comment context - id: github_comment_step - env: - COMMENT_CONTEXT: ${{ toJson(github.event) }} - run: echo "$COMMENT_CONTEXT" - - # Check if action JavaScript exists in the expected location. - - name: Check file existence - id: check_files - uses: andstor/file-existence-action@v3 - with: - files: ".github/actions/joke-action/joke.js, .github/actions/joke-action/main.js" - - # Update README from step 4 to step 5. - - name: Update to step 5 - if: steps.check_files.outputs.files_exists == 'true' - uses: skills/action-update-step@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - from_step: 4 - to_step: 5 diff --git a/.github/workflows/4-step.yml b/.github/workflows/4-step.yml new file mode 100644 index 0000000..1376933 --- /dev/null +++ b/.github/workflows/4-step.yml @@ -0,0 +1,156 @@ +name: Step 4 + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - "action.yml" + +permissions: + contents: read + actions: write + issues: write + +env: + STEP_5_FILE: ".github/steps/5-step.md" + +jobs: + find_exercise: + name: Find Exercise Issue + uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 + + check_step_work: + name: Check step work + runs-on: ubuntu-latest + needs: [find_exercise] + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Find last comment + id: find-last-comment + uses: peter-evans/find-comment@v3 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + direction: last + + - name: Update comment - checking work + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + file: exercise-toolkit/markdown-templates/step-feedback/checking-work.md + edit-mode: replace + + # START: Check practical exercise + + - name: Check if action.yml exists + id: check-action-yml + continue-on-error: true + uses: skills/exercise-toolkit/actions/file-exists@v0.7.0 + with: + file: action.yml + + - name: Check action.yml references dist/index.js + id: check-action-main + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: action.yml + keyphrase: "dist/index.js" + + - name: Check action.yml declares joke output + id: check-action-output + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: action.yml + keyphrase: "joke:" + + - name: Update comment - step results + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + edit-mode: replace + file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md + vars: | + step_number: 4 + results_table: + - description: "action.yml exists" + passed: ${{ steps.check-action-yml.outcome == 'success' }} + - description: "action.yml references dist/index.js" + passed: ${{ steps.check-action-main.outcome == 'success' }} + - description: "action.yml declares joke output" + passed: ${{ steps.check-action-output.outcome == 'success' }} + + # END: Check practical exercise + + - name: Fail job if not all checks passed + if: contains(steps.*.outcome, 'failure') + run: exit 1 + + post_next_step_content: + name: Post next step content + needs: [find_exercise, check_step_work] + runs-on: ubuntu-latest + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Create comment - step finished + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md + vars: | + next_step_number: 5 + + - name: Create comment - add step content + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: ${{ env.STEP_5_FILE }} + + - name: Create comment - watching for progress + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md + + - name: Disable current workflow and enable next one + run: | + gh workflow disable "${{github.workflow}}" + gh workflow enable "Step 5" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/5-add-action-to-workflow-file.yml b/.github/workflows/5-add-action-to-workflow-file.yml deleted file mode 100644 index 3728511..0000000 --- a/.github/workflows/5-add-action-to-workflow-file.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Step 5, Add Action To Workflow File - -# This step listens for the learner pushing a commit to `main` -# This workflow updates from step 5 to step 6. - -# This will run every time we push a commit to `main`. -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows -on: - workflow_dispatch: - push: - branches: [main] - -permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. - contents: write - -env: - EXPECTED_METADATA: ha-ha - -jobs: - # Get the current step to only run the main job when the learner is on the same step. - get_current_step: - name: Check current step number - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: get_step - run: | - echo "current_step=$(cat ./.github/steps/-step.txt)" >> $GITHUB_OUTPUT - outputs: - current_step: ${{ steps.get_step.outputs.current_step }} - - on_workflow_added_with_custom_action: - name: Check if workflow is referencing the custom action - needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 5. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions - if: >- - ${{ !github.event.repository.is_template - && needs.get_current_step.outputs.current_step == 5 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. - runs-on: ubuntu-latest - - steps: - # We'll need to check out the repository so that we can edit the README. - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Let's get all the branches. - - - name: Dump GitHub comment context - id: github_comment_step - env: - COMMENT_CONTEXT: ${{ toJson(github.event) }} - run: echo "$COMMENT_CONTEXT" - - # Check if action.yml file contains metadata. - - name: Read action file contents - id: read_action_yml_file - uses: andstor/file-reader-action@v1 - with: - path: ".github/workflows/my-workflow.yml" - - # Update README from step 5 to step 6. - - name: Update to step 6 - if: (contains(steps.read_action_yml_file.outputs.contents, ${{ env.EXPECTED_METADATA }}) - uses: skills/action-update-step@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - from_step: 5 - to_step: 6 diff --git a/.github/workflows/5-step.yml b/.github/workflows/5-step.yml new file mode 100644 index 0000000..90622f9 --- /dev/null +++ b/.github/workflows/5-step.yml @@ -0,0 +1,156 @@ +name: Step 5 + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - ".github/workflows/joke-action.yml" + +permissions: + contents: read + actions: write + issues: write + +env: + STEP_6_FILE: ".github/steps/6-step.md" + +jobs: + find_exercise: + name: Find Exercise Issue + uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 + + check_step_work: + name: Check step work + runs-on: ubuntu-latest + needs: [find_exercise] + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Find last comment + id: find-last-comment + uses: peter-evans/find-comment@v3 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + direction: last + + - name: Update comment - checking work + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + file: exercise-toolkit/markdown-templates/step-feedback/checking-work.md + edit-mode: replace + + # START: Check practical exercise + + - name: Check if joke-action workflow exists + id: check-joke-workflow + continue-on-error: true + uses: skills/exercise-toolkit/actions/file-exists@v0.7.0 + with: + file: .github/workflows/joke-action.yml + + - name: Check workflow has issue_comment trigger + id: check-issue-comment-trigger + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: .github/workflows/joke-action.yml + keyphrase: issue_comment + + - name: Check workflow has "Joke Action" name + id: check-joke-action-name + continue-on-error: true + uses: skills/action-keyphrase-checker@v1 + with: + text-file: .github/workflows/joke-action.yml + keyphrase: "Joke Action" + + - name: Update comment - step results + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + comment-id: ${{ steps.find-last-comment.outputs.comment-id }} + edit-mode: replace + file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md + vars: | + step_number: 5 + results_table: + - description: "joke-action workflow file exists" + passed: ${{ steps.check-joke-workflow.outcome == 'success' }} + - description: "issue_comment trigger present" + passed: ${{ steps.check-issue-comment-trigger.outcome == 'success' }} + - description: "workflow name should be 'Joke Action'" + passed: ${{ steps.check-joke-action-name.outcome == 'success' }} + + # END: Check practical exercise + + - name: Fail job if not all checks passed + if: contains(steps.*.outcome, 'failure') + run: exit 1 + + post_next_step_content: + name: Post next step content + needs: [find_exercise, check_step_work] + runs-on: ubuntu-latest + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Create comment - step finished + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md + vars: | + next_step_number: 6 + + - name: Create comment - add step content + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: ${{ env.STEP_6_FILE }} + + - name: Create comment - watching for progress + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md + + - name: Disable current workflow and enable next one + run: | + gh workflow disable "${{github.workflow}}" + gh workflow enable "Step 6" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/6-step.yml b/.github/workflows/6-step.yml new file mode 100644 index 0000000..aa87f26 --- /dev/null +++ b/.github/workflows/6-step.yml @@ -0,0 +1,69 @@ +name: Step 6 + +on: + workflow_dispatch: + workflow_run: + workflows: + - Joke Action + types: + - completed + +permissions: + contents: write + actions: write + issues: write + +env: + REVIEW_FILE: ".github/steps/x-review.md" + +jobs: + find_exercise: + if: github.event.workflow_run.conclusion == 'success' + name: Find Exercise Issue + uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.7.0 + + post_review_content: + name: Post review content + needs: [find_exercise] + runs-on: ubuntu-latest + env: + ISSUE_REPOSITORY: ${{ github.repository }} + ISSUE_NUMBER: ${{ needs.find_exercise.outputs.issue-number }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Get response templates + uses: actions/checkout@v5 + with: + repository: skills/exercise-toolkit + path: exercise-toolkit + ref: v0.7.0 + + - name: Create comment - step finished - final review next + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: exercise-toolkit/markdown-templates/step-feedback/lesson-review.md + + - name: Create comment - add review content + uses: GrantBirki/comment@v2.1.1 + with: + repository: ${{ env.ISSUE_REPOSITORY }} + issue-number: ${{ env.ISSUE_NUMBER }} + file: ${{ env.REVIEW_FILE }} + + - name: Disable current workflow + run: gh workflow disable "${{github.workflow}}" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + finish_exercise: + name: Finish Exercise + needs: [find_exercise] + uses: skills/exercise-toolkit/.github/workflows/finish-exercise.yml@v0.7.0 + with: + issue-url: ${{ needs.find_exercise.outputs.issue-url }} + exercise-title: "Write JavaScript Actions" diff --git a/.github/workflows/6-trigger-action.yml b/.github/workflows/6-trigger-action.yml deleted file mode 100644 index 55ee27a..0000000 --- a/.github/workflows/6-trigger-action.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Step 6, Trigger Your Action - -# This step listens for the learner applying a label to an issue. -# This workflow updates from step 6 to step X. - -# This will run every time we apply a label to an issue. -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows -on: - workflow_dispatch: - issues: - types: [labeled] - -permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. - contents: write - -env: - EXPECTED_METADATA: "second joke" - -jobs: - # Get the current step to only run the main job when the learner is on the same step. - get_current_step: - name: Check current step number - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: get_step - run: | - echo "current_step=$(cat ./.github/steps/-step.txt)" >> $GITHUB_OUTPUT - outputs: - current_step: ${{ steps.get_step.outputs.current_step }} - - on_my_workflow_run: - name: Check if my_workflow has run - needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 6. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions - if: >- - ${{ !github.event.repository.is_template - && needs.get_current_step.outputs.current_step == 6 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. - runs-on: ubuntu-latest - - steps: - # We'll need to check out the repository so that we can edit the README. - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Let's get all the branches. - - - name: Dump GitHub comment context - id: github_comment_step - env: - COMMENT_CONTEXT: ${{ toJson(github.event) }} - run: echo "$COMMENT_CONTEXT" - - # Update README from step 6 to step X. - - name: Update to step X - if: contains(github.event, ${{ env.EXPECTED_METADATA }}) - uses: skills/action-update-step@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - from_step: 6 - to_step: X diff --git a/.github/workflows/my-workflow.yml b/.github/workflows/my-workflow.yml deleted file mode 100644 index afe29e8..0000000 --- a/.github/workflows/my-workflow.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: JS Actions - -on: - issues: - types: [labeled] - -jobs: - action: - if: ${{ !github.event.repository.is_template }} - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 773bfd6..f966d66 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ .Trashes ehthumbs.db Thumbs.db + +# Add Node modules below # +################ \ No newline at end of file diff --git a/README.md b/README.md index 1f915f2..73f7aca 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,50 @@ -
- - - # Write JavaScript Actions _Write your own GitHub JavaScript Action and automate customized tasks unique to your workflow._ -
- - - ## Welcome -Write your own GitHub JavaScript Action and automate customized tasks unique to your workflow. - - **Who is this for**: Developers, GitHub users, users new to Git, students, managers, and for teams. -- **What you'll learn**: How to consume actions within a workflow file, create custom JavaScript based actions and publish your newly created action to the marketplace. -- **Prerequisites**: Before you start, you should be familiar with GitHub, GitHub Actions, and Continuous Integration with GitHub Actions. -- **How long**: This course takes about 1 to 2 hours to be completed. +- **What you'll learn**: How to create custom JavaScript-based GitHub Actions, bundle them for distribution, and use them in workflows. +- **What you'll build**: A Javascript based GitHub Action that fetches random dad jokes and exposes them as an output. +- **Prerequisites**: -In this course, you will: + - You should be familiar with GitHub and GitHub Actions. We recommend taking the [Hello GitHub Actions](https://github.com/skills-dev/hello-github-actions) exercise first. + +- **How long**: This exercise takes less than 1 hour to complete. + +In this exercise, you will: 1. Initialize a JavaScript project -2. Configure an action -3. Create a metadata file -4. Create JavaScript files -5. Add actions to workflow file -6. Trigger action - -### How to start this course - - - -[![start-course](https://user-images.githubusercontent.com/1221423/235727646-4a590299-ffe5-480d-8cd5-8194ea184546.svg)](https://github.com/new?template_owner=skills&template_name=write-javascript-actions&owner=%40me&name=skills-write-javascript-actions&description=My+clone+repository&visibility=public) - -1. Right-click **Start course** and open the link in a new tab. -2. In the new tab, most of the prompts will automatically fill in for you. - - For owner, choose your personal account or an organization to host the repository. - - We recommend creating a public repository, as private repositories will [use Actions minutes](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions). - - Scroll down and click the **Create repository** button at the bottom of the form. -3. After your new repository is created, wait about 20 seconds, then refresh the page. Follow the step-by-step instructions in the new repository's README. - - +© 2025 GitHub • [Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md) • [MIT License](https://gh.io/mit)