Exercise: A Project's Build Script

Finish the Maple Street Bikes website's build.ps1 with check, test, package and publish tasks that find their tools with Get-Command, stop when a program's exit code says it failed, and read the deploy token from the environment, and let a Pester check run each task the way a build server would.

Journeyman · PowerShell · Updated

Maple Street Bikes is ready for its website to go live, and its build.ps1 can only copy the site into dist so far. Before anyone publishes it, the script should check that the tools are installed, test every page, zip a release only when the tests pass, and publish without the deploy token ever being written into it. You'll write those four tasks, and a Pester check runs each one the way a build server would.

Get the exercise code

Open this lesson's GitHub repository, github.com/ask-codey/exercise-powershell-a-projects-build-script, also linked from the Exercise box beside the lesson. Click Code, then Download ZIP, and unzip it into your terminal-practice folder. Or clone it with Git.

The folder holds:

  • src: the website, three pages and a style sheet. One page has a broken link for your test task to find.
  • tools\check-pages.ps1: a page checker, ready to use. It ends with exit code 0 when every page passes and 1 when one doesn't.
  • build.ps1: the build script, with the build task written and four tasks for you to write.
  • Check.Tests.ps1: the check. You don't need to change it.

What to do

Open PowerShell 7 in the exercise folder and open build.ps1 in VS Code or edit. Each task is a function, and each of the four you write starts as one line that stops the script:

function Invoke-CheckTask {
    throw 'The check task is not written yet.'
}

Replace each throw with your own code. The comment above each function, and README.md, say what it does:

  1. check: find each tool in $tools (git and pwsh) with Get-Command, print Found git and Found pwsh, and stop with an error that names a tool that's missing.
  2. test: run the page checker on src as its own program, pwsh -NoProfile -File $checker -Path $src, print All pages passed when its exit code is 0, and stop with an error when it isn't. Then fix the broken link it finds.
  3. package: test, then build, then zip what's inside dist into release\bike-shop-site-1.2.0.zip. A site that fails its test is never zipped.
  4. publish: stop with an error that names $env:BIKESHOP_DEPLOY_TOKEN when it isn't set; otherwise package, and copy the zip into the server folder, which stands in for the web host. Never print the token.

Try each task as you finish it, for example .\build.ps1 -Task check. To try publish, set a practice token for this window first, such as $env:BIKESHOP_DEPLOY_TOKEN = 'practice-token': any text will do.

Check your work

From the exercise folder:

Invoke-Pester

At first six of the seven tests fail. That's expected: only the build task works yet. Each task you finish turns its test green. The check copies your build.ps1 into a throwaway folder beside a small site of its own and runs each task from another folder with pwsh -File, once with good pages and once with a broken link. It sets PATH and the token for those runs only, and brings a stand-in git of its own, so it works even without Git installed. A failing test says what to look at, for example the checker ended with exit code 1, and the test task carried on as if nothing happened.

If PowerShell says the check can't be loaded because running scripts is disabled or the file is not digitally signed, run Get-ChildItem -Recurse | Unblock-File once from the exercise folder, then Invoke-Pester again.

Hints

  • One task can use another. The functions are there to be called: package needs the test and the build first, as The Scripts Every Project Has describes.
  • A missing tool gives back nothing. Get-Command with -ErrorAction SilentlyContinue returns nothing for a tool that isn't installed, so if (-not (...)) asks "is it missing?"
  • A failing program doesn't stop the script by itself. Check $LASTEXITCODE right after it, or set $PSNativeCommandUseErrorActionPreference, as in Calling Other Programs.
  • Check for the token first. Before the task builds or copies anything, as in Secrets Out of Scripts. Single quotes in the message keep the variable's name from being replaced by its value.
  • Zip what's inside the folder. Compress-Archive -Path "$dist\*" puts the pages at the top of the zip, as in Many Files as One: Compress-Archive and Expand-Archive. Make the release folder first.

When you're done

Every test is green, and Pester's last line says:

Tests Passed: 7, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0

With a practice token set, .\build.ps1 -Task publish runs every step in order:

Checked 3 pages: no problems
All pages passed
Built 4 files into dist
Packaged C:\Users\Sam\terminal-practice\exercise-powershell-a-projects-build-script\release\bike-shop-site-1.2.0.zip
Published version 1.2.0 to C:\Users\Sam\terminal-practice\exercise-powershell-a-projects-build-script\server, with the deploy token from the environment

Your last line may be worded differently. Now look back at your publish task: if a teammate cloned the repo tomorrow, what would they need to set up, and what in your script tells them?

Submit your exercise

The exercise is how you finish this lesson. When your work is done, put it on GitHub in a repo of your own, then submit that repo's address here.

  1. On GitHub, click +, then New repository. Name it (for example exercise-powershell-a-projects-build-script), choose Public, and click Create repository. Leave out the README: your folder already has one.

  2. In a terminal in your exercise folder (PowerShell works), send your work to your new repo. If you downloaded the ZIP:

    git init -b main
    git add .
    git commit -m "My solution"
    git remote add origin https://github.com/your-name/exercise-powershell-a-projects-build-script.git
    git push -u origin main
    

    If you cloned the starter instead, point your copy at your own repo, then commit and push:

    git remote set-url origin https://github.com/your-name/exercise-powershell-a-projects-build-script.git
    git add .
    git commit -m "My solution"
    git push -u origin main
    
  3. Paste your repo's address, such as https://github.com/your-name/exercise-powershell-a-projects-build-script, into Submit your exercise on this page. The site checks that the repo is public and holds your commits, and then the lesson is complete.

Changed something after you submitted? Push it, and submit again: your latest submission is the one that counts.

So what

You've written the script a real project runs a hundred times a week: it checks, tests and packages, and it publishes with a secret it never holds.

Key terms

Related