feat: configure GitHub Pages deployment workflow
Add .github/workflows/deploy.yml with build and deploy jobs for GitHub Pages. Triggers on push to master and workflow_dispatch. Uses Node 22 with npm cache, uploads dist/ artifact, and deploys via deploy-pages@v4. Add comprehensive tests verifying workflow structure. Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
name: Deploy to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: dist/
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -0,0 +1,161 @@
|
||||
import { describe, it } from 'node:test';
|
||||
import { strict as assert } from 'node:assert';
|
||||
import { readFileSync, existsSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { parse } from 'node:url';
|
||||
|
||||
const deployPath = resolve('.github/workflows/deploy.yml');
|
||||
const azurePath = resolve('.github/workflows/azure-static-web-apps-salmon-sea-0f0c8771e.yml');
|
||||
|
||||
function readDeploy() {
|
||||
return readFileSync(deployPath, 'utf-8');
|
||||
}
|
||||
|
||||
function readAzure() {
|
||||
return readFileSync(azurePath, 'utf-8');
|
||||
}
|
||||
|
||||
// Snapshot the Azure file content before any tests run
|
||||
const azureOriginal = readAzure();
|
||||
|
||||
describe('GitHub Pages deploy workflow', () => {
|
||||
it('should exist at .github/workflows/deploy.yml', () => {
|
||||
assert.ok(existsSync(deployPath), 'deploy.yml should exist');
|
||||
});
|
||||
|
||||
it('should be valid YAML (parseable without error)', async () => {
|
||||
// Use a simple structural check - YAML should have proper structure
|
||||
const content = readDeploy();
|
||||
assert.ok(content.length > 0, 'file should not be empty');
|
||||
// Check it starts with a name field (standard workflow structure)
|
||||
assert.match(content, /^name:/, 'should start with name field');
|
||||
});
|
||||
|
||||
describe('Triggers', () => {
|
||||
it('should trigger on push to master branch', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /on:/, 'should have on: trigger');
|
||||
assert.match(content, /push:/, 'should have push trigger');
|
||||
assert.match(content, /branches:[\s\S]*?-\s*master/, 'should trigger on master branch');
|
||||
});
|
||||
|
||||
it('should trigger on workflow_dispatch', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /workflow_dispatch/, 'should have workflow_dispatch trigger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Permissions', () => {
|
||||
it('should set contents: read permission', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /contents:\s*read/, 'should have contents read permission');
|
||||
});
|
||||
|
||||
it('should set pages: write permission', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /pages:\s*write/, 'should have pages write permission');
|
||||
});
|
||||
|
||||
it('should set id-token: write permission', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /id-token:\s*write/, 'should have id-token write permission');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Concurrency', () => {
|
||||
it('should have concurrency group pages', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /concurrency:/, 'should have concurrency block');
|
||||
assert.match(content, /group:\s*['"]?pages['"]?/, 'should have pages concurrency group');
|
||||
});
|
||||
|
||||
it('should cancel in-progress deployments', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /cancel-in-progress:\s*true/, 'should cancel in-progress');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Build job', () => {
|
||||
it('should have a build job on ubuntu-latest', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /build:/, 'should have build job');
|
||||
assert.match(content, /runs-on:\s*ubuntu-latest/, 'should run on ubuntu-latest');
|
||||
});
|
||||
|
||||
it('should checkout with actions/checkout@v4', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /actions\/checkout@v4/, 'should use checkout@v4');
|
||||
});
|
||||
|
||||
it('should setup Node 22 with npm cache', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /actions\/setup-node@v4/, 'should use setup-node@v4');
|
||||
assert.match(content, /node-version:\s*['"]?22['"]?/, 'should use Node 22');
|
||||
assert.match(content, /cache:\s*['"]?npm['"]?/, 'should cache npm');
|
||||
});
|
||||
|
||||
it('should run npm ci', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /npm ci/, 'should run npm ci');
|
||||
});
|
||||
|
||||
it('should run npm run build', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /npm run build/, 'should run npm run build');
|
||||
});
|
||||
|
||||
it('should upload pages artifact from dist/', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /actions\/upload-pages-artifact@v3/, 'should use upload-pages-artifact@v3');
|
||||
assert.match(content, /path:\s*['"]?dist\/?['"]?/, 'should upload from dist/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Deploy job', () => {
|
||||
it('should have a deploy job', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /deploy:/, 'should have deploy job');
|
||||
});
|
||||
|
||||
it('should depend on build job', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /needs:\s*build/, 'should need build job');
|
||||
});
|
||||
|
||||
it('should run on ubuntu-latest', () => {
|
||||
const content = readDeploy();
|
||||
// The deploy job section should have its own runs-on
|
||||
// Extract deploy job section
|
||||
const deploySection = content.split(/\n\s+deploy:/)[1];
|
||||
assert.ok(deploySection, 'deploy section should exist');
|
||||
assert.match(deploySection, /runs-on:\s*ubuntu-latest/, 'deploy should run on ubuntu-latest');
|
||||
});
|
||||
|
||||
it('should have github-pages environment', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /environment:/, 'should have environment');
|
||||
assert.match(content, /name:\s*['"]?github-pages['"]?/, 'should use github-pages environment');
|
||||
});
|
||||
|
||||
it('should set URL from deployment output', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /url:\s*\$\{\{/, 'should set URL from deployment output');
|
||||
});
|
||||
|
||||
it('should use deploy-pages@v4', () => {
|
||||
const content = readDeploy();
|
||||
assert.match(content, /actions\/deploy-pages@v4/, 'should use deploy-pages@v4');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Existing Azure workflow', () => {
|
||||
it('should still exist', () => {
|
||||
assert.ok(existsSync(azurePath), 'Azure workflow should still exist');
|
||||
});
|
||||
|
||||
it('should be unchanged', () => {
|
||||
const current = readAzure();
|
||||
assert.equal(current, azureOriginal, 'Azure workflow content should not be modified');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user