Practical: Deploying a Next application

Initial Due Date: 2025-03-25 9:45AM
Final Due Date: 2025-04-08 4:15PM

Goals

Today you will add a feature to the color picker to enable the user to enter the color component by number. As part of that process we will practice testing, CI and automated deployment. Check out a deployed version of the final result.

Prerequisites

  1. Create the git repository for your practical by accepting the assignment from GitHub Classroom. This will create a new repository for you with a skeleton application already setup for you.
  2. Clone the repository to you computer with 💻 git clone (get the name of the repository from GitHub).
  3. Open up the package.json file and add your name as the author of the package.
  4. Install the module dependencies by executing 💻 pnpm install in the terminal.

Add CI with Github Actions

Before you make any changes, create a feature branch named “editable-number” to isolate your modifications from the main branch:

💻 git checkout -b editable-number

This should be the new default action that you take when working on your code to get you in the habit. When you start a feature, create a corresponding feature branch. Work until it is stable and only then merge it into the main branch.

Create the CI config file

GitHub actions allow us to execute a wide variety of actions in response to git events. If you are looking at the repository on Github, you will see there is an Actions tab, which will allow you to add a number of different actions designed by GitHub and the community. However, all these do is create a special configuration file in your repository, so we will do that directly.

At the top level of your package directory, you should have a .github directory with a workflows directory inside (if not, you should create them). Inside of workflows, create a new file called node.js.yml, i.e., .github/workflows/node.js.yml (the important part of the file name is the .yml on the end, but use the full name) with the contents shown below.

YAML (pronounced like “camel”) is a popular file format for text-based configuration files. It won’t be important to understand all of its ins and outs, for now the key thing to know is that like Python, indentation matters.

name: Node.js CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

env:
  HUSKY: 0

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Install pnpm
      uses: pnpm/action-setup@v4
      with:
        version: 10
    - name: Use Node.js 22.x
      uses: actions/setup-node@v3
      with:
        node-version: 22.x
        cache: 'pnpm'
    - run: pnpm install
    - run: pnpm test
    - run: pnpm run build

There are two main sections here: on and jobs. The on section tells GitHub Actions when to execute this action (when we push to main or make a PR to main). The jobs section describes the steps to carry out. In this case, it

  1. Checks out our code into a linux virtual machine
  2. Installs the desired versions of PNPM and node
  3. Runs pnpm install to install all of the dependencies specified in the pnpm-lock.yaml file
  4. Runs pnpm test
  5. Runs pnpm run build to ensure a production version of your application will build

If any of the commands fail, e.g., there are testing errors, GitHub actions will report the errors so we know we need to fix the pull request.

Add a status badge to your README.md

As you browse different repositories on GitHub, you may have seen flashy status badges in the README files that indicate that the tests are passing (or not). You can add one to your project as well.

As described in the documentation, the URL of the image is:

https://github.com/<OWNER>/<REPOSITORY>/actions/workflows/<WORKFLOW_FILE>/badge.svg

We need to put this into Markdown syntax to add an image. So for example, I might add the following line to the README.md to render the image. Do so in your README.md, but change the URL to point to your repository.

![workflow status](https://github.com/csci312a-s25/practical06-devops-mlinderm/actions/workflows/node.js.yml/badge.svg)

Create a PR

Let’s commit this change and push it to GitHub:

💻 git add .
💻 git commit -m "Add actions config file"
💻 git push -u origin editable-number

The last command tells git to find the local branch named editable-number and push its contents to a branch named editable-number in the remote origin repository. Recall that origin is the name automatically given to the repository we cloned from (on GitHub in this case).

Visit the repository on GitHub (reloading the page, if needed). There should be a yellow banner across the top notifying you of a change to a branch and asking if you would like to “Compare & pull request”. Do so. If you don’t see the banner, you can always create a new PR from the ‘Pull requests’ tab.

On the new page that comes up you will see a form for starting the PR. Make sure you are comparing branches, not forks, i.e., it shows the base as the main branch and the compared as the editable-number branch in your practical repository, not the skeleton. You should only see the one commit you just created included the PR. Type in a message and click the button to create the PR.

You will see a message that it is OK to merge with main. This is unsurprising since no one has done anything to main since you made a branch, so the merge just involved adding the changes in this branch on top of main. If you wait a moment (you may also need to reload), however, you will see a new message appear as GitHub Actions kicks off. Give it a moment to run, and then it should come back and tell you that the checks have failed. This is also unsurprising since you haven’t changed the code yet. If you click on “Details” you can see the run log and the output from running the tests.

Enhancing the color picker with controllable number

Now let’s make our change the the ColorPicker. Start the development server (💻 pnpm run dev) so you can see the effects of your changes. You should see the familiar ColorPicker appear in the web view. You can also run the tests with 💻 pnpm test, and they should fail.

You are now ready to make the changes to the LabeledSlider in src/components/LabeledSlider.js. Remove the current span which reports the value (<span>{value}</span>) and replace it with a number input element. The numerical input will be very similar to its slider counterpart. Its value should be controlled by the React state (so that all the elements that depend on or modify that value remain in sync), it should update the color component as specified, and have appropriate min and max values. The differences are it will be of type “number” and it will have an appropriate data-testid, e.g.,

data-testid={`${label}_number`}

You should now see your new inputs at the end of the sliders, and the tests should all pass.

Revisit the PR

Now that you have working code, add, commit and push it on the same feature branch you have been working on, e.g., 💻 git push origin editable-number

Return to the PR page on GitHub. You should see your new commit added to the PR and after a moment you should see the action kick off again. This time you should get a message that “All checks have passed” (it may take a few minute the first time due to caching behavior). If not, make sure that the tests were passing locally and that the new code has actually been pushed to the branch.

Click the “Merge pull request” button. it should give you a chance to add a message to the merge and then you can click “Confirm merge”. After the merge is complete, it will give you a “Delete branch” button. Click the “Delete branch” button to remove the feature branch from GitHub.

Clean up your local repository after the merge

Return to your terminal and switch back to the “main” branch (💻 git checkout main). You now want to pull the changes from GitHub, pruning to delete remote tracking references (💻 git pull --prune) and then delete your local branch (💻 git branch -d editable-number).

To avoid mistakes when deleting branches, you can add the --dry-run option to the pull --prune command , e.g. 💻 git pull --prune --dry-run to double check before actually pruning anything (note you will still need to run the actual command when you are sure it correct).

The full command sequence is:

💻 git checkout main
💻 git pull --prune
💻 git branch -d editable-number

Deploy to csci312.dev

To support deployment without requiring you to enter a credit card or running into limits on team sizes, etc. we have our own simple cloud deployment platform csci312.dev. Similar to Heroku or fly.io, you will push your code to a deployment repository at csci312.dev, which will then build and deploy your application at https://<project name>.csci312.dev.

Before you deploy, I encourage you to test the production version of your application locally. You can do so with:

💻 pnpm run build
💻 pnpm run start

This will build the production version of your application and start it the same way the server will (e.g., setting the production environment). If this doesn’t work locally, it is unlikely to work remotely!

  1. As a prerequisite, you should have added an SSH key to GitHub as described in the getting started instructions. Doing so is necessary to obtain deploy permissions. If you have not created a key yet, or if you attempt the below and get permission-related errors, contact the instructor to make sure your key has been added to the deployment server.
  2. Add the deployment repository as a remote in your repository with the name deploy via 💻 git remote add deploy git@csci312.dev:<midd username>-practical06 replacing <midd username> with your Middlebury username, e.g., 💻 git remote add deploy git@csci312.dev:mlinderman-practical06. Note that the name matters, it must be your Middlebury username followed by “-practical06”.
  3. Push the main branch to the deploy repository: 💻 git push deploy main. This should automatically build and deploy your application at https://<midd username>-practical06.csci312.dev. Note that the push will not complete until the application deploys, so it will take a minute or so. Any errors should (hopefully) be reported in the terminal as the push proceeds.
  4. To view the most recent logs from your application execute 💻 ssh git@csci312.dev logs <midd username>-practical06. You can optionally add a --lines argument, e.g., --line 50 to look at more lines.
  5. If you need to make a change or want to update your application, merge new commits into the main branch and push them to the deploy remote as you did above. That will re-deploy your application automatically.

When the deployment completes successfully, open https://<midd username>-practical06.csci312.dev in the browser, e.g., https://mlinderman-practical06.csci312.dev, to see your application live! Note that these sites are visible to anyone (i.e., you can send your awesome color picker to friends, family or anyone you want impress😀).

csci312.dev caveats

There are some more features of this platform that we will use when we deploy our projects. For that process, we will follow these similar, but more detailed, instructions.

⚠️ This platform is home-rolled, and while adequate for the needs of 5 concurrent projects, I am not sure it will hold up to 30 simultaneous deployments. We will see how it goes...

Finishing up

Make sure all of the provided tests pass and you don’t have any lint errors. Commit any additional changes you may have made and then push your changes to GitHub. You should then submit your repository to Gradescope as described here.

Grading

Required functionality:

Recall that the Practical exercises are evaluated as “Satisfactory/Not yet satisfactory”. Your submission will need to implement all of the required functionality (i.e., pass all the tests) to be Satisfactory (2 points).