From 0d4b8fd3971ee002a47aa5c6c6e609a68b8d8cb5 Mon Sep 17 00:00:00 2001 From: Joaquin Trillo Date: Mon, 4 Dec 2023 00:43:37 +0100 Subject: [PATCH] Bootcamp update 2023 --- .github/workflows/cd-docker.yml | 38 +++-- .github/workflows/ci.yml | 34 ++-- .github/workflows/reusable-node-build.yml | 18 +-- .github/workflows/test-custom-action.yml | 18 +++ .../src/dals/games/game.dal.test.ts | 2 +- 01-setup-ci/readme.md | 61 ++++---- 02-multiple-target-environments/readme.md | 97 ++++++++++-- 03-running-multiple-jobs/readme.md | 100 ++++++++++-- 04-working-with-build-artifacts/readme.md | 55 +++---- 05-integration-tests/readme.md | 31 ++-- .../readme.md | 59 ++++--- 07-approval-protection/readme.md | 8 +- 08-continous-delivery/readme.md | 140 ++++++++++++++--- .../01-creating-reusable-workflow/readme.md | 8 +- 09-workflow-calls/readme.md | 5 +- 10-custom-action/action-files/README.md | 23 +++ 10-custom-action/action-files/action.yml | 13 ++ 10-custom-action/action-files/index.js | 25 +++ 10-custom-action/readme.md | 148 ++++++++++++++++++ {10-exercises => 99-exercises}/readme.md | 9 +- hangman-api/Dockerfile.workflow | 5 +- hangman-api/src/dals/games/game.dal.test.ts | 2 +- 22 files changed, 679 insertions(+), 220 deletions(-) create mode 100644 .github/workflows/test-custom-action.yml rename {06-containerized-containers => 06-service-containers}/readme.md (73%) create mode 100644 10-custom-action/action-files/README.md create mode 100644 10-custom-action/action-files/action.yml create mode 100644 10-custom-action/action-files/index.js create mode 100644 10-custom-action/readme.md rename {10-exercises => 99-exercises}/readme.md (82%) diff --git a/.github/workflows/cd-docker.yml b/.github/workflows/cd-docker.yml index a1deff0..5aeb494 100644 --- a/.github/workflows/cd-docker.yml +++ b/.github/workflows/cd-docker.yml @@ -12,30 +12,28 @@ jobs: # runs-on: ubuntu-latest # steps: - # - uses: actions/checkout@v3 - # - uses: actions/setup-node@v3 - # with: - # node-version: 16 - # cache: 'npm' - # cache-dependency-path: hangman-api/package-lock.json - # - name: build - # working-directory: ./hangman-api - # run: | - # npm ci - # npm run build --if-present - # - uses: actions/upload-artifact@v3 - # with: - # name: build-code - # path: hangman-api/dist/ - + # - uses: actions/checkout@v4 + # - uses: actions/setup-node@v4 + # with: + # node-version: 16 + # cache: 'npm' + # cache-dependency-path: hangman-api/package-lock.json + # - name: build + # working-directory: ./hangman-api + # run: | + # npm ci + # npm run build --if-present + # - uses: actions/upload-artifact@v3 + # with: + # name: build-code + # path: hangman-api/dist/ delivery: - runs-on: ubuntu-latest needs: build steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/download-artifact@v3 with: name: build-code @@ -49,6 +47,6 @@ jobs: run: | echo $DOCKER_PASSWORD | docker login --username $DOCKER_USER --password-stdin image=$DOCKER_USER/$DOCKER_REPOSITORY:$(date +%s) - docker build . --file Dockerfile.workflow --tag $image + docker build -t $image -f Dockerfile.workflow . docker push $image - \ No newline at end of file + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15081de..7fa36dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,25 +1,25 @@ -name: CI +name: CI on: # push: # branches: [ main ] # paths: [ 'hangman-api/**' ] workflow_dispatch: - + pull_request: - branches: [ main ] - paths: [ 'hangman-api/**' ] + branches: [main] + paths: ["hangman-api/**"] jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: node-version: 16 - cache: 'npm' + cache: "npm" cache-dependency-path: hangman-api/package-lock.json - name: build working-directory: ./hangman-api @@ -31,9 +31,9 @@ jobs: runs-on: ubuntu-latest needs: build - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 16 - name: test @@ -50,8 +50,8 @@ jobs: postgres: image: postgres:14-alpine env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres POSTGRES_DB: hangman_db # Set health checks to wait until postgres has started options: >- @@ -63,12 +63,12 @@ jobs: - 5432:5432 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 16 # - name: Create database relationships - - name: Running integration tests + - name: Running integration tests working-directory: ./hangman-api env: DATABASE_PORT: 5432 @@ -82,5 +82,3 @@ jobs: npm ci npx knex migrate:latest --env development npm run test:integration - - diff --git a/.github/workflows/reusable-node-build.yml b/.github/workflows/reusable-node-build.yml index 48e131f..dab8f32 100644 --- a/.github/workflows/reusable-node-build.yml +++ b/.github/workflows/reusable-node-build.yml @@ -1,9 +1,9 @@ -name: Reusable Node Build +name: Reusable Node Build -on: +on: workflow_call: inputs: - node-version: + node-version: required: true type: number working-directory: @@ -15,18 +15,18 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: node-version: ${{ inputs.node-version }} - cache: 'npm' + cache: "npm" cache-dependency-path: ${{ inputs.working-directory }}/package-lock.json - - name: build + - name: build working-directory: ${{ inputs.working-directory }} run: | npm ci npm run build --if-present - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v3 with: name: build-code path: ${{ inputs.working-directory }}/dist/ diff --git a/.github/workflows/test-custom-action.yml b/.github/workflows/test-custom-action.yml new file mode 100644 index 0000000..62ed925 --- /dev/null +++ b/.github/workflows/test-custom-action.yml @@ -0,0 +1,18 @@ +name: Workflow to test the custom action + +on: + workflow_dispatch: + +jobs: + get_commodity_price: + runs-on: ubuntu-latest + + steps: + - name: Get commodity price step + id: commodity_price + uses: jtrillo/get-commodity-price@v1.0.1 + with: + commodity: silver + # Use the output from `commodity_price` step + - name: Get the output price + run: echo "Price per ounce is ${{ steps.commodity_price.outputs.price }} USD" diff --git a/.start-code/hangman-api/src/dals/games/game.dal.test.ts b/.start-code/hangman-api/src/dals/games/game.dal.test.ts index d821556..f08b05a 100644 --- a/.start-code/hangman-api/src/dals/games/game.dal.test.ts +++ b/.start-code/hangman-api/src/dals/games/game.dal.test.ts @@ -23,7 +23,7 @@ beforeEach(async () => { describe('game.dal', () => { describe('getGames', () => { - test('resturns the games related to a player', async () => { + test('returns the games related to a player', async () => { // Arrange const playersDAL = playerDALFactory(db); const wordsDAL = wordDALFactory(db); diff --git a/01-setup-ci/readme.md b/01-setup-ci/readme.md index 08a0543..5298f41 100644 --- a/01-setup-ci/readme.md +++ b/01-setup-ci/readme.md @@ -7,8 +7,8 @@ In our case we're going to set up CI for a Node.js project. Let's start by creat * Create `.github/workflows/ci.yml` ```bash -mkdir -p .gitub/workflows -touch .gitub/workflows/ci.yml +mkdir -p .github/workflows +touch .github/workflows/ci.yml ``` ```yaml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - - name: inspect + - name: Inspect machine run: | ls -al whoami @@ -38,10 +38,10 @@ jobs: Let's commit this file to a new branch: ```bash -git checkout -b added-basic-workflow -git push -u origin added-basic-workflow +git checkout -b add-basic-workflow +git push -u origin add-basic-workflow git add . -git commit -m "added ci file" +git commit -m "added ci workflow file" git push ``` @@ -49,11 +49,11 @@ Now if we move to GitHub web site, we will find a message to create a new pull r We can see that a new action starts, and by default is going to check if CI process has succeded before allow us to merge this branch into main branch. -> The workflow is triggered by `pull_request` event. +> The workflow is triggered by `pull_request` event. If we open the action job audit from website and have a look into the steps, we can notice a couple of things: -``` +```bash drwxr-xr-x 2 runner docker 4096 Oct 9 18:03 . drwxr-xr-x 3 runner docker 4096 Oct 9 18:03 .. runner @@ -61,11 +61,11 @@ runner v16.17.1 ``` -* Node is already installed -* Our user is runner * There's no contents inside the current directory. +* Our user is runner +* Node is already installed -Let's solve this by getting the code into workflow context. +Now, let's get the code into workflow context. * Update `ci.yml` @@ -83,7 +83,8 @@ jobs: runs-on: ubuntu-latest steps: -+ - uses: actions/checkout@v3 ++ - name: Checkout # This field is optional ++ - uses: actions/checkout@v4 - name: inspect run: | ls -al @@ -93,7 +94,7 @@ jobs: ``` -Recall that on job steps we can use and action or run a command, here we're using an action `actions/checkout@v3`, that no needs further configuration. +Recall that on job steps we can use an action or run a command. Here we're using an action `actions/checkout@v4` that needs no further configuration. ```bash git add . @@ -103,7 +104,7 @@ git push Now if we go back to the last action job, we will find out that our code has been download: -``` +```bash total 44 drwxr-xr-x 11 runner docker 4096 Oct 9 18:17 . drwxr-xr-x 3 runner docker 4096 Oct 9 18:17 .. @@ -121,14 +122,13 @@ runner v16.17.1 ``` -Really nice, out target is that this workflow implements the CI process. - +Really nice, but our target is that this workflow implements the CI process. > **Continous Integration (CI)** - The process of automating the build and testing of changes when a commit is pushed to a branch. -Lets remove the current job and add new one that builds and test our code: +Lets remove the current job and add new one that builds and tests our code: -````diff +```diff name: CI on: @@ -142,7 +142,7 @@ jobs: - runs-on: ubuntu-latest - steps: -- - uses: actions/checkout@v3 +- - uses: actions/checkout@v4 - - name: inspect - run: | - ls -al @@ -150,7 +150,7 @@ jobs: - pwd - node -v -```` +``` ```yaml name: CI @@ -167,11 +167,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build and test working-directory: ./hangman-api run: | - npm ci + npm ci npm run build --if-present ls ./dist npm test @@ -180,12 +180,11 @@ jobs: ```bash git add . -git commit -m "added build test step" +git commit -m "added build and test step" git push ``` -We can check the results in actions. For last, because we're going to add more projects to current solution, seems a good idea that the workflow only starts if the contents of api solution are updated. - +We can check the results in actions (GitHub website). Since we're going to add more projects to the current solution, it seems a good idea that the workflow only starts if the contents of api project are updated. * Update `ci.yml` @@ -205,7 +204,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build and test working-directory: ./hangman-api run: | @@ -218,4 +217,12 @@ jobs: * With `paths` we filter the directories that are able to trigger a new workflow. -> Check the [filter pattern cheat sheet](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet) for a better understanding +> Check the [filter pattern cheat sheet](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet) for a better understanding. + +```bash +git add . +git commit -m "added path filter" +git push +``` + +If we check again 'Actions' tab, we will not see a new trigger. Why? Because the latest changes did not modify `hangman-api` folder. diff --git a/02-multiple-target-environments/readme.md b/02-multiple-target-environments/readme.md index a794d1b..afc2ff3 100644 --- a/02-multiple-target-environments/readme.md +++ b/02-multiple-target-environments/readme.md @@ -1,19 +1,22 @@ -# Multiple Environments +# Multiple Target Environments Some times our code must run on different target versions. GitHub Actions has a feature that is pretty handy for this kind of situations `matrix strategy`. -> A `matrix strategy` lets you use variables in a single job definition to automatically create multiple job runs that are based on the combinations of the variables. For example, you can use a matrix strategy to test your code in multiple versions of a language or on multiple operating systems. +> A `matrix strategy` allows you to use variables in a single job definition to automatically create multiple job runs that are based on the combinations of the variables. For example, you can use a matrix strategy to test your code in multiple versions of a language or on multiple operating systems. -* In our case we want to test the following node versions: - - 14.x - - 15.x - - 16.x +## Using a single-dimension matrix + +In our case we want to test the following node versions: + +- 14.x +- 15.x +- 16.x But if you recall from previous demo, we have already installed a node version on our machine, how can we handle this? If we visit [GitHub Actions Marketplace](https://github.com/marketplace?type=actions), we can search by **node environment** and we will find out [setup-node-js-environment](https://github.com/marketplace/actions/setup-node-js-environment), this is perfect for us. -* Let's start by adding the matrix strategy, update `cy.yml` +- Let's start by adding the matrix strategy, update `ci.yml` ```yml name: CI @@ -35,7 +38,7 @@ jobs: node-version: [14.x, 15.x, 16.x] # diff # steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build and test working-directory: ./hangman-api run: | @@ -43,7 +46,6 @@ jobs: npm run build --if-present ls ./dist npm test - ``` Almost there. Now let's add the new action: @@ -58,10 +60,10 @@ jobs: node-version: [14.x, 15.x, 16.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # diff # - name: Setup Node.js environment - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} # diff # @@ -72,7 +74,6 @@ jobs: npm run build --if-present ls ./dist npm test - ``` Now let's push the new changes and see what is going on with our workflows: @@ -83,9 +84,9 @@ git commit -m "added matrix" git push ``` -Humm... Seems that our workflow is not running, recall that we have introduce a filter per directory, to make it run, we have two options comment out the filter or add a dummy change, let's go for second: +Humm... Seems that our workflow is not running, recall that we have introduced a filter per directory. To make it run, we have two options, comment out the filter or add a dummy change. Let's go for the second one: -* Update `hangman-api/src/config.ts` +- Update `hangman-api/src/config.ts` ```diff import { config } from 'dotenv'; @@ -107,7 +108,6 @@ export default { poolMax: +process.env.DATABASE_POOL_MAX!, }, }; - ``` ```bash @@ -117,3 +117,70 @@ git push ``` Now if we check the workflow we will see three jobs each one refering a different node version. + +## Using a multi-dimension matrix + +In this case we want to execute our job in two different OS, Ubuntu 20.04 and Ubuntu 22.04. We can specify a second variable in our matrix to create a multi-dimensional one. A job will run for each possible combination of the variables. + +```diff +jobs: + build-test: +- runs-on: ubuntu-latest + strategy: + matrix: + node-version: [14.x, 15.x, 16.x] ++ os: [ubuntu-20.04, ubuntu-22.04] ++ runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - name: build and test + working-directory: ./hangman-api + run: | + npm ci + npm run build --if-present + ls ./dist + npm test +``` + +- Do not forget to update any file from `hangman-api` (if not workflow will no be triggered). We can update again `hangman-api/src/config.ts` + +```diff +import { config } from 'dotenv'; + +-// TODO: Use connection string +config({ + path: '.env', +}); + +export default { + database: { + isActive: process.env.DATA_BASE_ACTIVE, + host: process.env.DATABASE_HOST, + user: process.env.DATABASE_USER, + password: process.env.DATABASE_PASSWORD, + port: +process.env.DATABASE_PORT!, + database: process.env.DATABASE_NAME, + poolMin: +process.env.DATABASE_POOL_MIN!, + poolMax: +process.env.DATABASE_POOL_MAX!, + }, +}; +``` + +```bash +git add . +git commit -m "added multi-dimension matrix" +git push +``` + +Now if we check the workflow we will see 6 jobs: + +- OS: `ubuntu-20.04` & node-version: `14.x` +- OS: `ubuntu-20.04` & node-version: `15.x` +- OS: `ubuntu-20.04` & node-version: `16.x` +- OS: `ubuntu-22.04` & node-version: `14.x` +- OS: `ubuntu-22.04` & node-version: `15.x` +- OS: `ubuntu-22.04` & node-version: `16.x` diff --git a/03-running-multiple-jobs/readme.md b/03-running-multiple-jobs/readme.md index d5c19b3..9d3203c 100644 --- a/03-running-multiple-jobs/readme.md +++ b/03-running-multiple-jobs/readme.md @@ -2,13 +2,15 @@ In this demo we will set up multiple jobs in the same workflow. By now we're running a single job that is doing the the build and also is running the unit tests, let's split it into two different jobs. -Let's merge the previous pull request `added-basic-workflow`, and create a new branch. +Let's merge the previous pull request, delete branch `add-basic-workflow`, and create a new branch. -* Visit the project page and merge `added-basic-workflow` and delete it. +* Visit the project page merge PR and delete branch `add-basic-workflow` (there will be a button to it automatically). + +* In your machine, execute the following commands: ```bash git checkout main -git branch -d added-basic-workflow +git branch -d add-basic-workflow ``` * Create a new branch `fix-test` @@ -33,16 +35,18 @@ on: jobs: build-test: - runs-on: ubuntu-latest ++ runs-on: ubuntu-latest - strategy: - matrix: - node-version: [14.x, 15.x, 16.x] +- os: [ubuntu-20.04, ubuntu-22.04] +- runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Setup Node.js environment -- uses: actions/setup-node@v3 +- uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - name: build and test @@ -55,7 +59,7 @@ jobs: ``` -We have removed the matrix to reduce the number of running workflows.Now lets remove the test step and rename the job: +We have removed the matrix to reduce the number of running workflows. Now let's remove the test step and rename the job: ```diff jobs: @@ -64,7 +68,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: build and test + - name: build working-directory: ./hangman-api @@ -94,7 +98,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build working-directory: ./hangman-api run: | @@ -105,7 +109,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: test working-directory: ./hangman-api run: | @@ -114,15 +118,15 @@ jobs: # diff # ``` -Let's push our changes +Let's push our changes. ```bash git add . -git commit -m "added new job" +git commit -m "jobs split" git push ``` -* Let's update `hangman-api/src/services/word-provider.service.spec.ts` and breake the test: +* Let's update `hangman-api/src/services/word-provider.service.spec.ts` and break the test: ```diff ....... @@ -145,8 +149,6 @@ git push Now if we visit, the pull request page, we can check that the test job has failed and we can navigate to the details. And we can check the exact line where the test has failed lets fixed: -* Update `hangman-api/src/services/word-provider.service.spec.ts`: - ```diff ....... // Act @@ -164,6 +166,47 @@ git commit -m "fixed broken test" git push ``` +If we check the actions tab, we will see that the job is again succesful. + +The last thing we want to do before merging the PR is to add a dependency between jobs: `test` will be executed after `build` job. In order to achieve this, we need to make use of option [needs](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds). + +* Update `ci.yml`: + +```diff +name: CI + +on: + push: + branches: [ main ] + paths: [ 'hangman-api/**' ] + pull_request: + branches: [ main ] + paths: [ 'hangman-api/**' ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: build + working-directory: ./hangman-api + run: | + npm ci + npm run build --if-present + + test: + runs-on: ubuntu-latest ++ needs: build # If it depends on more than one, use an array + steps: + - uses: actions/checkout@v4 + - name: test + working-directory: ./hangman-api + run: | + npm ci + npm test +``` + Check the results on GitHub page and for last merge into main, and delete current branch: * Merge `fix-test` and delete on portal @@ -174,3 +217,30 @@ git checkout main git pull git branch -d fix-test ``` + +## Extra: how to execute a job even if its dependent fail + +If you would like a job to run even if a job it is dependent on did not succeed, use the `always()` conditional expression in `jobs..if`. + +* Example: requiring successful dependent jobs + +```yaml +jobs: + job1: + job2: + needs: job1 + job3: + needs: [job1, job2] +``` + +* Example: not requiring successful dependent jobs + +```yaml +jobs: + job1: + job2: + needs: job1 + job3: + if: ${{ always() }} + needs: [job1, job2] +``` diff --git a/04-working-with-build-artifacts/readme.md b/04-working-with-build-artifacts/readme.md index c282333..a63909e 100644 --- a/04-working-with-build-artifacts/readme.md +++ b/04-working-with-build-artifacts/readme.md @@ -2,9 +2,9 @@ In this demo we're going to use build artifacts to reuse data, that is already done by other job on workflow. -If we have a look in our current workflow, we're executing the build and test job, on parallel, this is the default behaviour forjobs. Because of this we're stalling dependencies twice, let's try to reuse these dependencies on test job. +If we have a look in our current workflow, we're executing the build and test job on parallel, which is the default behaviour for jobs. Because of this we're installing dependencies twice.Let's try to reuse these dependencies on test job. -First of all, we're going to do the updates on `main` branch, at last we're on a demo and we can take some licenses ๐Ÿ˜ˆ. +First of all, we're going to do the updates on `main` branch, at last we're on a demo and we can take some licenses ๐Ÿ˜ˆ. * Update `ci.yml` @@ -30,7 +30,7 @@ git push Now if we visit the `Actions` tab and select `CI`, we have and option to run it manually. That's perfect for us, right now, when we get the results that we want, we will back and change it again. -To work with artifacts, we're going to use [Upload Build Artifact](https://github.com/marketplace/actions/upload-a-build-artifact) +To work with artifacts, we're going to use [Upload a Build Artifact](https://github.com/marketplace/actions/upload-a-build-artifact) * Update `ci.yml` @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build working-directory: ./hangman-api run: | @@ -56,18 +56,17 @@ jobs: We're creating an artifact `dependencies`, and we're grabbing the content for this artifact from `node_modules` -Now we need the simmetric operation [Download a Build Artifact](https://github.com/marketplace/actions/download-a-build-artifact) - +Now we need the symmetric operation: [Download a Build Artifact](https://github.com/marketplace/actions/download-a-build-artifact) * Update `ci.yml` -```yml +```diff jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build working-directory: ./hangman-api run: | @@ -80,28 +79,22 @@ jobs: test: runs-on: ubuntu-latest - # diff # needs: build - # diff # steps: - - uses: actions/checkout@v3 - # diff # - - uses: actions/download-artifact@v3.0.0 - with: - name: dependencies - path: hangman-api/node_modules - # diff # + - uses: actions/checkout@v4 ++ - uses: actions/download-artifact@v3 ++ with: ++ name: dependencies ++ path: hangman-api/node_modules - name: test working-directory: ./hangman-api run: | - npm ci +- npm ci npm test ``` -* We have added `needs: build`, since this job depends now on the artifact generated on build job. - -Lets try it +Let's push the changes done. ```bash git add . @@ -109,7 +102,7 @@ git commit -m "added artifacts" git push ``` -And trigger from project site +And trigger the workflow from project site. If we check the workflow, we will notice that is taking a long time to resolve the dependencies upload. This is not the way to manage this, let's try something different. @@ -123,8 +116,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 -+ - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 ++ - uses: actions/setup-node@v4 + with: + node-version: 16 + cache: 'npm' @@ -144,17 +137,25 @@ jobs: needs: build steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/download-artifact@v3.0.0 - with: - name: dependencies - path: hangman-api/node_modules -+ - uses: actions/setup-node@v3 ++ - uses: actions/setup-node@v4 + with: + node-version: 16 - name: test working-directory: ./hangman-api run: | - npm ci ++ npm ci npm test ``` + +Let's push these changes. + +```bash +git add . +git commit -m "added caching for npm" +git push +``` diff --git a/05-integration-tests/readme.md b/05-integration-tests/readme.md index 6e67230..aa834ec 100644 --- a/05-integration-tests/readme.md +++ b/05-integration-tests/readme.md @@ -1,10 +1,10 @@ # Integration Tests -If we have a look into our code we notice that our integartion tests, are not running. +If we have a look into our code, we notice that our integration tests are not running. -A fair question is how can we implement this? Because we have to deal with the database dependency to run this kind of tests. One quick option that could work on our machines and on the GitHub Workflow machine is use `docker-compose`. Yes, `Docker` and `Docker Compose` are already installed, so let's go ahead. +A fair question is how can we implement this. Because we have to deal with the database dependency to run this kind of tests. One quick option that could work on our machines and on the GitHub Workflow machine is to use `docker-compose`. Yes, `Docker` and `Docker Compose` are already installed, so let's go ahead. -First we are going to implement this loacally. `Docker Compose`, deals with services, and services are containers that are going to be located on private `Docker Network`, so our first step will be create a `Docker Image` that contains everything to run these tests. +First we are going to implement this locally. `Docker Compose`, deals with services, and services are containers that are going to be located on private `Docker Network`, so our first step will be create a `Docker Image` that contains everything to run these tests. * Create `hangman-api/Dockerfile.test-integration` @@ -26,12 +26,11 @@ COPY ./tsconfig.json ./tsconfig.json RUN npm ci CMD [ "npm", "run", "test:integration" ] - ``` Now we can go ahead and set up the Docker Compose that will use this. Let's create `test-integration.yml`. -> We're using a meaning full name here, instead the default one. +> We're using a meaningful name here, instead the default one. ```yml version: "3.9" @@ -55,12 +54,12 @@ services: Here we're declaring the database service, because we're feeding `POSTGRES_DB: hangman_db`, the default database that will be created will be `hangman_db` instead of `postgres`, that's ok for us. -Now in order to make that our tests can run, we need the expected schemas, recall we have migrations in this project, lets create another Dockerfile for that specific purpose: +Now in order to make that our tests can run, we need the expected schemas. Recall that we have migrations in this project, so let's create another Dockerfile for that specific purpose: * Create `Dockerfile.migrations` ```Dockerfile -FROM node:16-buster +FROM node:16-bullseye WORKDIR /opt/app @@ -73,7 +72,7 @@ RUN npm init -y RUN npm install knex pg dotenv ``` -For simplicity we're creating the manifest file in line, this is ok, here, because we're on demo time, but be aware that we could easily misalign dependencies. +For simplicity we're creating the manifest file in line (last command in the above Dockerfile). This is ok here, because we're on demo time, but be aware that we could easily misalign dependencies. Ok good, now we can add a new service to initialize our schemas: @@ -130,14 +129,14 @@ docker compose -f test-integration.yml up --force-recreate --exit-code-from buil If we run this, we will find that our service `build-db-relationships` is unable to find the postgres database: -``` +```output build-db-relationships | Using environment: development build-db-relationships | getaddrinfo ENOTFOUND postgres build-db-relationships | Error: getaddrinfo ENOTFOUND postgres build-db-relationships | at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:107:26) ``` -This is happening because the container is ready, but the database server that is hosting no. Let's fix it by addinh [wait for it](https://github.com/vishnubob/wait-for-it). +This is happening because the container is ready, but the database server is not. Let's fix it by adding [wait for it](https://github.com/vishnubob/wait-for-it). * Copy the file on root project. @@ -160,9 +159,9 @@ COPY ./db/migrations ./db/migrations COPY ./knexfile.js ./knexfile.js -+COPY ./wait-for-it.sh ./wait-for-it.sh ++ COPY ./wait-for-it.sh ./wait-for-it.sh -+RUN chmod +x wait-for-it.sh ++ RUN chmod +x wait-for-it.sh RUN npm init -y @@ -196,7 +195,7 @@ Let's give it a try: docker compose -f test-integration.yml up --force-recreate --exit-code-from build-db-relationships ``` -Cool now works, for last. Now the last part of the puzzle: +Cool, now it works, for last. Now the last part of the puzzle: ```bash docker compose -f test-integration.yml down --remove-orphans -v --rmi local @@ -231,7 +230,7 @@ docker compose -f test-integration.yml down --remove-orphans -v --rmi local docker compose -f test-integration.yml run test-integration ``` -``` +```output Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them > hangman-api@1.0.0 pretest:integration @@ -245,7 +244,7 @@ Cleared /tmp/jest_0 PASS src/dals/games/game.dal.test.ts (8.089 s) game.dal getGames - โœ“ resturns the games related to a player (408 ms) + โœ“ returns the games related to a player (408 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total @@ -254,4 +253,4 @@ Time: 8.676 s Ran all test suites. ``` -> Exercise: Update CI pipeline to run test integration using docker compose +> Exercise: Update CI pipeline to run test integration using docker compose. diff --git a/06-containerized-containers/readme.md b/06-service-containers/readme.md similarity index 73% rename from 06-containerized-containers/readme.md rename to 06-service-containers/readme.md index 573ce5e..28a9d34 100644 --- a/06-containerized-containers/readme.md +++ b/06-service-containers/readme.md @@ -1,14 +1,14 @@ -# Contenaraized Containers +# Service Containers The previous solution for integration test works, but have some downsides. * We have added to our solution explicit files to run the integration tests: - - wait-for-it.sh - - test-integration.yml - - Dockerfile.migrations - - Dockerfile.test-integration + * wait-for-it.sh + * test-integration.yml + * Dockerfile.migrations + * Dockerfile.test-integration -This code is not related with our solution, is just there to solve the CI issue. Well is not the end of the world, but is thera another way that we can solve this? Lets introduce [Containerized containers](https://docs.github.com/en/actions/using-containerized-services/about-service-containers) +This code is not related with our solution, is just there to solve the CI issue. Well is not the end of the world, but is thera another way that we can solve this? Let's introduce [Service Containers](https://docs.github.com/en/actions/using-containerized-services/about-service-containers) > **About service containers** - Service containers are Docker containers that provide a simple and portable way for you to host services that you might need to test or operate your application in a workflow. For example, your workflow might need to run integration tests that require access to a database and memory cache. @@ -20,6 +20,7 @@ Let's start by adding a new job, that declares a `postgres` database server: # diff # test-integration: runs-on: ubuntu-latest + needs: tests services: postgres: @@ -42,24 +43,24 @@ Let's start by adding a new job, that declares a `postgres` database server: Now, before running the integration tests, we need to setup the schemas: ```yml - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 16 - - name: Create database relationships - working-directory: ./hangman-api - env: - DATABASE_PORT: 5432 - DATABASE_HOST: localhost - DATABASE_NAME: hangman_db - DATABASE_USER: postgres - DATABASE_PASSWORD: postgres - DATABASE_POOL_MIN: 2 - DATABASE_POOL_MAX: 10 - run: | - npm ci - npx knex migrate:latest --env development + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 16 + - name: Create database relationships + working-directory: ./hangman-api + env: + DATABASE_PORT: 5432 + DATABASE_HOST: localhost + DATABASE_NAME: hangman_db + DATABASE_USER: postgres + DATABASE_PASSWORD: postgres + DATABASE_POOL_MIN: 2 + DATABASE_POOL_MAX: 10 + run: | + npm ci + npx knex migrate:latest --env development ``` * Push new changes @@ -72,10 +73,9 @@ git push * Run the workflow manually from GiHub website. - If everything goes right we must see and output as follows: -``` +```output found 0 vulnerabilities Using environment: development Batch 1 run: 1 migrations @@ -85,8 +85,8 @@ Ok let's rename and add the instructions to run our integration tests: ```diff steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 16 - - name: Create database relationships @@ -116,7 +116,6 @@ git push * Run the workflow manually from GiHub website. - If everything goes right we must see and output like this one: ```bash @@ -131,7 +130,7 @@ Cleared /tmp/jest_rt PASS src/dals/games/game.dal.test.ts game.dal getGames - โœ“ resturns the games related to a player (148 ms) + โœ“ returns the games related to a player (148 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total diff --git a/07-approval-protection/readme.md b/07-approval-protection/readme.md index 8e8071f..b2ee58b 100644 --- a/07-approval-protection/readme.md +++ b/07-approval-protection/readme.md @@ -1,5 +1,7 @@ # Approval Protection -* Branch protections -* Required reviews -* Obvious approvals +* Branch protections (Settings > Branches > Add branch protection rule) + * Required reviews (Require a pull request before merging > Require approvals) + * Require conversation resolution before merging (all conversations in PR must be resolved before merging PR) + +With GitHub Free plan you can only protect branches on public repositories. diff --git a/08-continous-delivery/readme.md b/08-continous-delivery/readme.md index f6fd832..e00dc69 100644 --- a/08-continous-delivery/readme.md +++ b/08-continous-delivery/readme.md @@ -1,17 +1,15 @@ # Continous Delivery -* In this demo, upload images to Docker Hub. - -After achieve CI, the next step is get the new changes in our code and prepare them to get into production. In our case we're going to create a new image and push it to a Docker Registry, we're goingto use Docker Hub, but any other registry or any other artifactory will be analogus. +After achieve CI, the next step is get the new changes in our code and prepare them to get into production. In our case, we're going to create a new Docker image and push it to a Docker Registry. We're going to use Docker Hub, but any other registry or any other artifactory will be analogus. ## Pre requisites -* Docker or Docker Desktop installed +* Docker or Docker Desktop installed * Docker Hub account ## Building the Docker Image Locally -Before adding the required steps into our workflow, let's try it on local. +Before adding the required steps into our workflow, let's try it on local. First from `hangman-api` root directory run: @@ -29,7 +27,23 @@ docker run -d -p 3000:3000 jaimesalas/hangman-api curl localhost:3000/api/topics ``` -Now before we move into our pipeline and add the delivery job, let's have a look into our Dockerfile +We could also push it to Docker Hub + +```bash +docker login # Just if not already logged +docker push jaimesalas/hangman-api +``` + +## Building the Docker Image in a workflow + +First of all, let's create a new branch for this new feature + +```bash +git checkout -b add-cd-workflow +git push -u origin add-cd-workflow +``` + +Before we move into our workflow and add the delivery job, let's have a look into our Dockerfile ```Dockerfile #------------------------------------------------------------------------------ @@ -57,17 +71,14 @@ ENV NODE_ENV=production RUN npm install - CMD ["npm", "start"] - ``` -Notice the first part of this `Dockerfile`, is doing exctly the same as what we're already doing in our build job. It wouldn't be nice that we can use the built job here? Let's give a try. +Notice the first part of this `Dockerfile` is doing exctly the same as what we're already doing in our `build` job. It wouldn't be nice that we can use the built job here? Let's give a try. * Create `Dockerfile.workflow` ```Dockerfile -ARG source FROM node:lts-alpine as app WORKDIR /app @@ -79,14 +90,35 @@ ENV NODE_ENV=production RUN npm install - CMD ["npm", "start"] +``` + +* What if we would like to change the node image used during build time? We can make use of an `ARG` variable. +```diff ++ ARG version=lts-alpine ++ FROM node:${version} as app +- FROM node:lts-alpine as app + +WORKDIR /app +COPY dist/ . +COPY package.json . +COPY package-lock.json . + +ENV NODE_ENV=production + +RUN npm install + +CMD ["npm", "start"] ``` -* For simplicity, we're going to create a new workflow from `main` +We should use the following command to build an image with an specific Node.js version: + +```bash +docker build -t jtrillo/hangman-api -f Dockerfile.workflow --build-arg version=20.10-alpine . +``` -First we're going to use the same build job as the one on `ci.yml`, but here we're going to upload the build in orther to be used on a new `delivery` job: +First, we're going to use the same build job as the one on `ci.yml`. But here we're going to upload the build as an artifact to be used on a new `delivery` job: * Create `.github/workflows/cd-docker.yml` @@ -101,8 +133,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 16 cache: 'npm' @@ -128,20 +160,35 @@ Now we need to build the image before push it to Docker registry we can do this needs: build steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/download-artifact@v3 with: name: build-code path: hangman-api/dist/ - name: Build the Docker image working-directory: ./hangman-api - run: docker build . --file Dockerfile.workflow --tag my-image-name:$(date +%s) + run: docker build -t hangman-api:$(date +%s) -f Dockerfile.workflow . # diff # ``` -Ok, almost done, there are prebaked actions to authenticate and push Docker images, but in this case we're going to use a run command. But first of all I need to create a new secret to authenticate my self against Docker Hub. +Push the new changes: + +```bash +git add . +git commit -m "added cd workflow" +git push +``` + +We can try the job now and check how the Docker image is built. + +## Pushing the Docker Image in a workflow + +Ok, almost done. There are prebaked actions to authenticate and push Docker images, but in this case we're going to use a run command. First of all, we need to create a new secret to authenticate ourselves against Docker Hub. -[adding secret](assets/01-adding-secret.png) +> Go to Repository Settings > Secrets and variables > Actions > New repository secret \ +> When creating the secret in GitHub website, text is visible. Take care if you are sharing your screen :) + +![adding secret](assets/01-adding-secret.png) ```diff - - name: Build the Docker Image @@ -160,21 +207,21 @@ And add the multiline run operation run: | echo $DOCKER_PASSWORD | docker login --username $DOCKER_USER --password-stdin image=$DOCKER_USER/$DOCKER_REPOSITORY:$(date +%s) - docker build . --file Dockerfile.workflow --tag $image + docker build -t $image -f Dockerfile.workflow . docker push $image ``` - Push the new changes: ```bash git add . git commit -m "added push docker image step" +git push ``` -And fire the workflow from GitHub site. If everything works we must see something like this: +And fire the workflow from GitHub site. If everything works we must see something like this: -``` +```console ---> 12c19641de84 Successfully built 12c19641de84 Successfully tagged jaimesalas/hangman-api:1665501807 @@ -183,6 +230,53 @@ The push refers to repository [docker.io/jaimesalas/hangman-api] And visit Docker Hub to find out the uploaded image +## Extra: building and pushing a docker image to Docker Hub using actions + +In this case, we will use actions instead of commands. We are going to make use of the following actions: + +* [docker/login-action](https://github.com/marketplace/actions/docker-login) +* [docker/setup-buildx-action](https://github.com/marketplace/actions/docker-setup-buildx) +* [docker/build-push-action](https://github.com/marketplace/actions/build-and-push-docker-images) + +Let's add a new job to our workflow. + +```yaml + buildAndPush: + runs-on: ubuntu-latest + needs: build + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Download dist folder as artifact + uses: actions/download-artifact@v3 + - name: Docker Hub login + uses: docker/login-action@v3 + with: + # registry: by default is set to Docker Hub + username: jtrillo + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build and push Docker Image + uses: docker/build-push-action@v5 + with: + context: ./hangman-api + push: true + tags: jtrillo/hangman-api-actions:latest + file: ./hangman-api/Dockerfile.workflow +``` + +Push the new changes + +```bash +git add . +git commit -m "added buildAndPush job" +git push +``` + +And, finally, let's fire again the workflow. + ## Reference * [What is Continous Delivery?](https://aws.amazon.com/devops/continuous-delivery/) diff --git a/09-workflow-calls/01-creating-reusable-workflow/readme.md b/09-workflow-calls/01-creating-reusable-workflow/readme.md index b282ad3..5e92932 100644 --- a/09-workflow-calls/01-creating-reusable-workflow/readme.md +++ b/09-workflow-calls/01-creating-reusable-workflow/readme.md @@ -29,8 +29,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} cache: 'npm' @@ -64,8 +64,8 @@ jobs: - runs-on: ubuntu-latest - steps: -- - uses: actions/checkout@v3 -- - uses: actions/setup-node@v3 +- - uses: actions/checkout@v4 +- - uses: actions/setup-node@v4 - with: - node-version: 16 - cache: 'npm' diff --git a/09-workflow-calls/readme.md b/09-workflow-calls/readme.md index 410e62e..61f8c33 100644 --- a/09-workflow-calls/readme.md +++ b/09-workflow-calls/readme.md @@ -84,12 +84,10 @@ on: required: true ``` - 2. In the reusable workflow, reference the input or secret that you defined in the on key in the previous step. > Note: If the secrets are inherited by using secrets: inherit in the calling workflow, you can reference them even if they are not explicitly defined in the on key. For more information, see ["Workflow syntax for GitHub Actions."](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsecretsinherit) - ```yaml jobs: reusable_workflow_job: @@ -142,7 +140,7 @@ You reference reusable workflow files using on of the following syntaxes: * `{owner}/{repo}/.github/workflows/{filename}@{ref}` - reusable workflows on public repositories * `./.github/workflows/{filename}` for reusable workflows in the same repository. -`{ref}` can be a SHA, a release tag, or a branch name. Using the commit SHA is the safest for stability and security. +`{ref}` can be a SHA, a release tag, or a branch name. Using the commit SHA is the safest for stability and security. You can call multiple workflows, referencing each in a separate job. @@ -159,4 +157,3 @@ jobs: ## Demo: Creating a reusable workflow [Demo: Creating a reusable workflow](01-creating-reusable-workflow/readme.md) - diff --git a/10-custom-action/action-files/README.md b/10-custom-action/action-files/README.md new file mode 100644 index 0000000..26c2cc1 --- /dev/null +++ b/10-custom-action/action-files/README.md @@ -0,0 +1,23 @@ +# Get commodity price action + +This action prints current price per ounce for the selected commodity. + +## Inputs + +### `commodity` + +**Required** The commodity you want to know its current price per ounce. Default `"gold"`. + +## Outputs + +### `price` + +The current price for the selected commodity. + +## Example usage + +```yaml +uses: jtrillo/get-commodity-price-action@v1 +with: + commodity: 'silver' +``` diff --git a/10-custom-action/action-files/action.yml b/10-custom-action/action-files/action.yml new file mode 100644 index 0000000..add2848 --- /dev/null +++ b/10-custom-action/action-files/action.yml @@ -0,0 +1,13 @@ +name: 'Get Commodity Price' +description: 'Get gold or silver current price per ounce' +inputs: + commodity: # id of input + description: 'Commodity (gold or silver)' + required: true + default: 'gold' +outputs: + price: # id of output + description: 'The current price of the select commodity' +runs: + using: 'node16' + main: 'index.js' \ No newline at end of file diff --git a/10-custom-action/action-files/index.js b/10-custom-action/action-files/index.js new file mode 100644 index 0000000..155aec7 --- /dev/null +++ b/10-custom-action/action-files/index.js @@ -0,0 +1,25 @@ +const core = require('@actions/core'); +const github = require('@actions/github'); + +try { + // `commodity` input defined in action metadata file + const commodity = core.getInput('commodity'); + console.log(`Getting current ${commodity} price per ounce...`); + let price = 0; + if (commodity.toLowerCase() === 'gold') { + price = 2019.80; // https://www.bullionvault.com/gold-price-chart.do + console.log(`Current gold price per ounce: ${price} USD`); + } else if (commodity.toLowerCase() === 'silver') { + price = 24.07; // https://www.bullionvault.com/silver-price-chart.do + console.log(`Current silver price per ounce: ${price} USD`); + } + + // `price` output defined in action metadata file + core.setOutput('price', price); + + // Get the JSON webhook payload for the event that triggered the workflow + const payload = JSON.stringify(github.context.payload, undefined, 2) + console.log(`The event payload: ${payload}`); +} catch (error) { + core.setFailed(error.message); +} \ No newline at end of file diff --git a/10-custom-action/readme.md b/10-custom-action/readme.md new file mode 100644 index 0000000..9108eab --- /dev/null +++ b/10-custom-action/readme.md @@ -0,0 +1,148 @@ +# Custom action + +In this last demo we will create a custom action and use it in a workflow. + +## Steps + +* Create a new **public** repository on GitHub and call it *get-commodity-price-action*. Clone it to your computer and open this repo in your editor. +* Create a new Node.js project using `npm init -y`. +* Create the action metadata file. It should be named `action.yml`. + +```yaml +name: 'Get Commodity Price' +description: 'Get gold or silver current price per ounce' +inputs: + commodity: # id of input + description: 'Commodity (gold or silver)' + required: true + default: 'gold' +outputs: + price: # id of output + description: 'The current price of the select commodity' +runs: + using: 'node16' + main: 'index.js' +``` + +* Add actions toolkit packages + +```bash +npm i @actions/core @actions/github +``` + +* Write the action code. Create a new fille called `index.js`. + +```js +const core = require('@actions/core'); +const github = require('@actions/github'); + +try { + // `commodity` input defined in action metadata file + const commodity = core.getInput('commodity'); + console.log(`Getting current ${commodity} price per ounce...`); + let price = 0; + if (commodity.toLowerCase() === 'gold') { + price = 2019.80; // https://www.bullionvault.com/gold-price-chart.do + console.log(`Current gold price per ounce: ${price} USD`); + } else if (commodity.toLowerCase() === 'silver') { + price = 24.07; // https://www.bullionvault.com/silver-price-chart.do + console.log(`Current silver price per ounce: ${price} USD`); + } + + // `price` output defined in action metadata file + core.setOutput('price', price); + + // Get the JSON webhook payload for the event that triggered the workflow + const payload = JSON.stringify(github.context.payload, undefined, 2) + console.log(`The event payload: ${payload}`); +} catch (error) { + core.setFailed(error.message); +} +``` + +* Create a README to let people know how to use the action. It should be named `README.md`. +* Commit, tag and push your action + +```bash +git add action.yml index.js node_modules/* package.json package-lock.json README.md +git commit -m "Action ready for release" +git tag -a -m "Get commodity price action initial release" v1.0.1 +git push --follow-tags +``` + +> Note: `node_modules` must be pushed! + +* Create a release using previously created tag. Go to GitHub website, open your repo and check 'Releases' section in the right side panel. + +## Testing out the action + +Now the action is ready to be tested. + +* Let's go back to our main repo and create a new workflow named `test-custom-action.yml` + +```bash +git checkout -b test-custom-action +git push -u origin test-custom-action +``` + +```yaml +name: Workflow to test the custom action + +on: + workflow_dispatch: + +jobs: + get_commodity_price: + runs-on: ubuntu-latest + + steps: + - name: Get commodity price step + uses: jtrillo/get-commodity-price-action@v1.0.1 + with: + commodity: 'silver' +``` + +```bash +git add . +git commit -m "added workflow to test custom action" +git push +``` + +* Now we can fire the workflow and check if the custom action we have created works. + +* We can also make use of action's output in a different step. + +```diff +name: Workflow to test the custom action + +on: + workflow_dispatch: + +jobs: + get_commodity_price: + runs-on: ubuntu-latest + + steps: + - name: Get commodity price step ++ id: commodity_price + uses: jtrillo/get-commodity-price@v1.0.0 + with: + commodity: 'silver' ++ # Use the output from `commodity_price` step ++ - name: Get the output price ++ run: echo "Price per ounce is ${{ steps.commodity_price.outputs.price }} USD" +``` + +* Push the new changes and fire the workflow again + +```bash +git add . +git commit -m "added new step to use custom action output" +git push +``` + +## References + +* [GitHub Docs - Creating a JS action](https://docs.github.com/en/actions/creating-actions/creating-a-javascript-action) +* [Template repo for creating JS actions](https://github.com/actions/javascript-action) +* [Template repo for creating TS actions](https://github.com/actions/typescript-action) diff --git a/10-exercises/readme.md b/99-exercises/readme.md similarity index 82% rename from 10-exercises/readme.md rename to 99-exercises/readme.md index fdd1513..31bee65 100644 --- a/10-exercises/readme.md +++ b/99-exercises/readme.md @@ -1,4 +1,6 @@ -##ย Exercise 1. Create CI workflow for frontend project +# Exercises + +## Exercise 1. Create CI workflow for frontend project Copy the directory `.start-code/hangman-front` into root project. Once that you have done create a new workflow, that triggers on new pull request, and executes the folling operations: @@ -9,12 +11,12 @@ Copy the directory `.start-code/hangman-front` into root project. Once that you Create a new workflow that triggers manually that creates a new Docker Image and push it to [Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) -## Exercise 3. Create a workflow that runs e2e tests +## Exercise 3. Create a workflow that runs e2e tests Create a workflow that triggers as you wish that runs e2e tests using [Docker Compose](https://docs.docker.com/compose/gettingstarted/) or [Cypress action](https://github.com/cypress-io/github-action). * Extra - - Notice that we have two spec suits on e2e project. Can you figure out a way to run them on parallel without copy/pasting the same spec twice? + * Notice that we have two spec suits on e2e project. Can you figure out a way to run them on parallel without copy/pasting the same spec twice? ## Exercise 4. Create a Custom JavaScript action @@ -26,4 +28,3 @@ curl https://type.fit/api/quotes * [actions/javascript-action](https://github.com/actions/javascript-action) * [https://github.com/actions/typescript-action](https://github.com/actions/typescript-action) - diff --git a/hangman-api/Dockerfile.workflow b/hangman-api/Dockerfile.workflow index e978fea..f1da613 100644 --- a/hangman-api/Dockerfile.workflow +++ b/hangman-api/Dockerfile.workflow @@ -1,5 +1,5 @@ -ARG source -FROM node:lts-alpine as app +ARG version=lts-alpine +FROM node:${version} as app WORKDIR /app COPY dist/ . @@ -10,5 +10,4 @@ ENV NODE_ENV=production RUN npm install - CMD ["npm", "start"] diff --git a/hangman-api/src/dals/games/game.dal.test.ts b/hangman-api/src/dals/games/game.dal.test.ts index d821556..f08b05a 100644 --- a/hangman-api/src/dals/games/game.dal.test.ts +++ b/hangman-api/src/dals/games/game.dal.test.ts @@ -23,7 +23,7 @@ beforeEach(async () => { describe('game.dal', () => { describe('getGames', () => { - test('resturns the games related to a player', async () => { + test('returns the games related to a player', async () => { // Arrange const playersDAL = playerDALFactory(db); const wordsDAL = wordDALFactory(db);