From 3f9f219b5278dffdad727e210e28f60ad55676d0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 30 Jul 2025 17:17:24 +0000
Subject: [PATCH 01/40] Initial plan
From 9d3c6a9e321fe95273affb27b53668f91847962a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 30 Jul 2025 17:48:08 +0000
Subject: [PATCH 02/40] Add Playwright e2e tests for core website functionality
Co-authored-by: GeekTrainer <6109729+GeekTrainer@users.noreply.github.com>
---
client/e2e-tests/README.md | 70 +++++++++++++++++++++
client/e2e-tests/about.spec.ts | 31 ++++++++++
client/e2e-tests/api-integration.spec.ts | 56 +++++++++++++++++
client/e2e-tests/dog-details.spec.ts | 51 ++++++++++++++++
client/e2e-tests/homepage.spec.ts | 58 ++++++++++++++++++
client/package-lock.json | 64 ++++++++++++++++++++
client/package.json | 8 ++-
client/playwright-report/index.html | 77 ++++++++++++++++++++++++
client/playwright.config.ts | 45 ++++++++++++++
client/run-tests.sh | 49 +++++++++++++++
client/test-results/.last-run.json | 4 ++
11 files changed, 512 insertions(+), 1 deletion(-)
create mode 100644 client/e2e-tests/README.md
create mode 100644 client/e2e-tests/about.spec.ts
create mode 100644 client/e2e-tests/api-integration.spec.ts
create mode 100644 client/e2e-tests/dog-details.spec.ts
create mode 100644 client/e2e-tests/homepage.spec.ts
create mode 100644 client/playwright-report/index.html
create mode 100644 client/playwright.config.ts
create mode 100755 client/run-tests.sh
create mode 100644 client/test-results/.last-run.json
diff --git a/client/e2e-tests/README.md b/client/e2e-tests/README.md
new file mode 100644
index 0000000..3c48202
--- /dev/null
+++ b/client/e2e-tests/README.md
@@ -0,0 +1,70 @@
+# End-to-End Tests for Tailspin Shelter
+
+This directory contains Playwright end-to-end tests for the Tailspin Shelter website.
+
+## Test Files
+
+- `homepage.spec.ts` - Tests for the main homepage functionality
+- `about.spec.ts` - Tests for the about page
+- `dog-details.spec.ts` - Tests for individual dog detail pages
+- `api-integration.spec.ts` - Tests for API integration and error handling
+
+## Running Tests
+
+### Prerequisites
+
+Make sure you have installed dependencies:
+```bash
+npm install
+```
+
+### Running Tests
+
+```bash
+# Run all tests
+npm run test:e2e
+
+# Run tests with UI mode (for debugging)
+npm run test:e2e:ui
+
+# Run tests in headed mode (see browser)
+npm run test:e2e:headed
+
+# Run only Chromium tests
+npm run test:e2e:chromium
+
+# Debug tests
+npm run test:e2e:debug
+```
+
+## Test Coverage
+
+The tests cover the following core functionality:
+
+### Homepage Tests
+- Page loads with correct title and content
+- Dog list displays properly
+- Loading states work correctly
+- Error handling for API failures
+
+### About Page Tests
+- About page content displays correctly
+- Navigation back to homepage works
+
+### Dog Details Tests
+- Navigation from homepage to dog details
+- Navigation back from dog details to homepage
+- Handling of invalid dog IDs
+
+### API Integration Tests
+- Successful API responses
+- Empty dog list handling
+- Network error handling
+
+## Configuration
+
+Tests are configured in `../playwright.config.ts` and automatically start the application servers using the existing `scripts/start-app.sh` script before running tests.
+
+The tests run against:
+- Client (Astro): http://localhost:4321
+- Server (Flask): http://localhost:5100
\ No newline at end of file
diff --git a/client/e2e-tests/about.spec.ts b/client/e2e-tests/about.spec.ts
new file mode 100644
index 0000000..6d955c2
--- /dev/null
+++ b/client/e2e-tests/about.spec.ts
@@ -0,0 +1,31 @@
+import { test, expect } from '@playwright/test';
+
+test.describe('About Page', () => {
+ test('should load about page and display content', async ({ page }) => {
+ await page.goto('/about');
+
+ // Check that the page title is correct
+ await expect(page).toHaveTitle(/About - Tailspin Shelter/);
+
+ // Check that the main heading is visible
+ await expect(page.getByRole('heading', { name: 'About Tailspin Shelter' })).toBeVisible();
+
+ // Check that content is visible
+ await expect(page.getByText('Nestled in the heart of Seattle')).toBeVisible();
+ await expect(page.getByText('The name "Tailspin" reflects')).toBeVisible();
+
+ // Check the fictional organization note
+ await expect(page.getByText('Tailspin Shelter is a fictional organization')).toBeVisible();
+ });
+
+ test('should navigate back to homepage from about page', async ({ page }) => {
+ await page.goto('/about');
+
+ // Click the "Back to Dogs" button
+ await page.getByRole('link', { name: 'Back to Dogs' }).click();
+
+ // Should be redirected to homepage
+ await expect(page).toHaveURL('/');
+ await expect(page.getByRole('heading', { name: 'Welcome to Tailspin Shelter' })).toBeVisible();
+ });
+});
\ No newline at end of file
diff --git a/client/e2e-tests/api-integration.spec.ts b/client/e2e-tests/api-integration.spec.ts
new file mode 100644
index 0000000..26a9afc
--- /dev/null
+++ b/client/e2e-tests/api-integration.spec.ts
@@ -0,0 +1,56 @@
+import { test, expect } from '@playwright/test';
+
+test.describe('API Integration', () => {
+ test('should fetch dogs from API', async ({ page }) => {
+ // Mock successful API response
+ await page.route('/api/dogs', route => {
+ route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify([
+ { id: 1, name: 'Buddy', breed: 'Golden Retriever' },
+ { id: 2, name: 'Luna', breed: 'Husky' },
+ { id: 3, name: 'Max', breed: 'Labrador' }
+ ])
+ });
+ });
+
+ await page.goto('/');
+
+ // Check that mocked dogs are displayed
+ await expect(page.getByText('Buddy')).toBeVisible();
+ await expect(page.getByText('Golden Retriever')).toBeVisible();
+ await expect(page.getByText('Luna')).toBeVisible();
+ await expect(page.getByText('Husky')).toBeVisible();
+ await expect(page.getByText('Max')).toBeVisible();
+ await expect(page.getByText('Labrador')).toBeVisible();
+ });
+
+ test('should handle empty dog list', async ({ page }) => {
+ // Mock empty API response
+ await page.route('/api/dogs', route => {
+ route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify([])
+ });
+ });
+
+ await page.goto('/');
+
+ // Check that empty state message is displayed
+ await expect(page.getByText('No dogs available at the moment')).toBeVisible();
+ });
+
+ test('should handle network errors', async ({ page }) => {
+ // Mock network error
+ await page.route('/api/dogs', route => {
+ route.abort('failed');
+ });
+
+ await page.goto('/');
+
+ // Check that error message is displayed
+ await expect(page.getByText(/Error:/)).toBeVisible({ timeout: 10000 });
+ });
+});
\ No newline at end of file
diff --git a/client/e2e-tests/dog-details.spec.ts b/client/e2e-tests/dog-details.spec.ts
new file mode 100644
index 0000000..2f27a34
--- /dev/null
+++ b/client/e2e-tests/dog-details.spec.ts
@@ -0,0 +1,51 @@
+import { test, expect } from '@playwright/test';
+
+test.describe('Dog Details', () => {
+ test('should navigate to dog details from homepage', async ({ page }) => {
+ await page.goto('/');
+
+ // Wait for dogs to load
+ await page.waitForSelector('.grid a[href^="/dog/"]', { timeout: 10000 });
+
+ // Get the first dog link
+ const firstDogLink = page.locator('.grid a[href^="/dog/"]').first();
+
+ // Get the dog name for verification
+ const dogName = await firstDogLink.locator('h3').textContent();
+
+ // Click on the first dog
+ await firstDogLink.click();
+
+ // Should be on a dog details page
+ await expect(page.url()).toMatch(/\/dog\/\d+/);
+
+ // Check that the page title is correct
+ await expect(page).toHaveTitle(/Dog Details - Tailspin Shelter/);
+
+ // Check for back button
+ await expect(page.getByRole('link', { name: 'Back to All Dogs' })).toBeVisible();
+ });
+
+ test('should navigate back to homepage from dog details', async ({ page }) => {
+ // Go directly to a dog details page (assuming dog with ID 1 exists)
+ await page.goto('/dog/1');
+
+ // Click the back button
+ await page.getByRole('link', { name: 'Back to All Dogs' }).click();
+
+ // Should be redirected to homepage
+ await expect(page).toHaveURL('/');
+ await expect(page.getByRole('heading', { name: 'Welcome to Tailspin Shelter' })).toBeVisible();
+ });
+
+ test('should handle invalid dog ID gracefully', async ({ page }) => {
+ // Go to a dog page with an invalid ID
+ await page.goto('/dog/99999');
+
+ // The page should still load (even if no dog is found)
+ await expect(page).toHaveTitle(/Dog Details - Tailspin Shelter/);
+
+ // Back button should still be available
+ await expect(page.getByRole('link', { name: 'Back to All Dogs' })).toBeVisible();
+ });
+});
\ No newline at end of file
diff --git a/client/e2e-tests/homepage.spec.ts b/client/e2e-tests/homepage.spec.ts
new file mode 100644
index 0000000..5e42dc7
--- /dev/null
+++ b/client/e2e-tests/homepage.spec.ts
@@ -0,0 +1,58 @@
+import { test, expect } from '@playwright/test';
+
+test.describe('Tailspin Shelter Homepage', () => {
+ test('should load homepage and display title', async ({ page }) => {
+ await page.goto('/');
+
+ // Check that the page title is correct
+ await expect(page).toHaveTitle(/Tailspin Shelter - Find Your Forever Friend/);
+
+ // Check that the main heading is visible
+ await expect(page.getByRole('heading', { name: 'Welcome to Tailspin Shelter' })).toBeVisible();
+
+ // Check that the description is visible
+ await expect(page.getByText('Find your perfect companion from our wonderful selection')).toBeVisible();
+ });
+
+ test('should display dog list section', async ({ page }) => {
+ await page.goto('/');
+
+ // Check that the "Available Dogs" heading is visible
+ await expect(page.getByRole('heading', { name: 'Available Dogs' })).toBeVisible();
+
+ // Wait for dogs to load (either loading state, error, or actual dogs)
+ await page.waitForSelector('.grid', { timeout: 10000 });
+ });
+
+ test('should show loading state initially', async ({ page }) => {
+ await page.goto('/');
+
+ // Check that loading animation is shown initially
+ // Look for the loading skeleton cards
+ const loadingElements = page.locator('.animate-pulse').first();
+
+ // Either loading should be visible initially, or dogs should load quickly
+ try {
+ await expect(loadingElements).toBeVisible({ timeout: 2000 });
+ } catch {
+ // If loading finishes too quickly, that's fine - check for dog content instead
+ await expect(page.locator('.grid')).toBeVisible();
+ }
+ });
+
+ test('should handle API errors gracefully', async ({ page }) => {
+ // Intercept the API call and make it fail
+ await page.route('/api/dogs', route => {
+ route.fulfill({
+ status: 500,
+ contentType: 'application/json',
+ body: JSON.stringify({ error: 'Internal Server Error' })
+ });
+ });
+
+ await page.goto('/');
+
+ // Check that error message is displayed
+ await expect(page.getByText(/Failed to fetch data/)).toBeVisible({ timeout: 10000 });
+ });
+});
\ No newline at end of file
diff --git a/client/package-lock.json b/client/package-lock.json
index fbfbe84..1b2f764 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -16,6 +16,7 @@
"typescript": "^5.8.2"
},
"devDependencies": {
+ "@playwright/test": "^1.49.1",
"@types/node": "^22.13.11",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.3",
@@ -1010,6 +1011,22 @@
"integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==",
"license": "MIT"
},
+ "node_modules/@playwright/test": {
+ "version": "1.54.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.1.tgz",
+ "integrity": "sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright": "1.54.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@rollup/pluginutils": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
@@ -4416,6 +4433,53 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/playwright": {
+ "version": "1.54.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.1.tgz",
+ "integrity": "sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.54.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.54.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.1.tgz",
+ "integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/playwright/node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/postcss": {
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
diff --git a/client/package.json b/client/package.json
index 1e13e95..165cae7 100644
--- a/client/package.json
+++ b/client/package.json
@@ -6,7 +6,12 @@
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
- "astro": "astro"
+ "astro": "astro",
+ "test:e2e": "playwright test",
+ "test:e2e:ui": "playwright test --ui",
+ "test:e2e:debug": "playwright test --debug",
+ "test:e2e:headed": "playwright test --headed",
+ "test:e2e:chromium": "playwright test --project=chromium"
},
"dependencies": {
"@astrojs/node": "^9.1.3",
@@ -17,6 +22,7 @@
"typescript": "^5.8.2"
},
"devDependencies": {
+ "@playwright/test": "^1.49.1",
"@types/node": "^22.13.11",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.3",
diff --git a/client/playwright-report/index.html b/client/playwright-report/index.html
new file mode 100644
index 0000000..32fa3ef
--- /dev/null
+++ b/client/playwright-report/index.html
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+ Playwright Test Report
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/playwright.config.ts b/client/playwright.config.ts
new file mode 100644
index 0000000..0cb887c
--- /dev/null
+++ b/client/playwright.config.ts
@@ -0,0 +1,45 @@
+import { defineConfig, devices } from '@playwright/test';
+
+/**
+ * @see https://playwright.dev/docs/test-configuration
+ */
+export default defineConfig({
+ testDir: './e2e-tests',
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: 'html',
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: 'http://localhost:4321',
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry',
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: 'chromium',
+ use: {
+ ...devices['Desktop Chrome'],
+ channel: 'chrome' // Use system Chrome instead of downloading Chromium
+ },
+ },
+ ],
+
+ /* Run your local dev server before starting the tests */
+ webServer: {
+ command: 'cd .. && ./scripts/start-app.sh',
+ url: 'http://localhost:4321',
+ reuseExistingServer: !process.env.CI,
+ timeout: 120 * 1000,
+ },
+});
\ No newline at end of file
diff --git a/client/run-tests.sh b/client/run-tests.sh
new file mode 100755
index 0000000..4d38e9d
--- /dev/null
+++ b/client/run-tests.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# Simple test script that starts the app and runs Playwright tests
+set -e
+
+echo "Starting application servers in background..."
+
+# Store current directory
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR/.."
+
+# Start the application using the existing script
+./scripts/start-app.sh &
+APP_PID=$!
+
+# Function to cleanup
+cleanup() {
+ echo "Cleaning up..."
+ kill $APP_PID 2>/dev/null || true
+ pkill -f "python.*app.py" 2>/dev/null || true
+ pkill -f "npm.*dev" 2>/dev/null || true
+ wait $APP_PID 2>/dev/null || true
+}
+
+# Trap signals to ensure cleanup
+trap cleanup EXIT INT TERM
+
+echo "Waiting for servers to start..."
+sleep 10
+
+# Check if servers are running
+for i in {1..30}; do
+ if curl -s http://localhost:4321 > /dev/null && curl -s http://localhost:5100/api/dogs > /dev/null; then
+ echo "Servers are ready!"
+ break
+ fi
+ if [ $i -eq 30 ]; then
+ echo "Servers failed to start"
+ exit 1
+ fi
+ echo "Waiting for servers... ($i/30)"
+ sleep 2
+done
+
+echo "Running Playwright tests..."
+cd client
+npx playwright test "$@"
+
+echo "Tests completed!"
\ No newline at end of file
diff --git a/client/test-results/.last-run.json b/client/test-results/.last-run.json
new file mode 100644
index 0000000..cbcc1fb
--- /dev/null
+++ b/client/test-results/.last-run.json
@@ -0,0 +1,4 @@
+{
+ "status": "passed",
+ "failedTests": []
+}
\ No newline at end of file
From 67ed72d0b076eb7d3aa6667b14df8d8a1e4aa92e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 30 Jul 2025 17:53:28 +0000
Subject: [PATCH 03/40] Clean up gitignore and remove test artifacts from repo
Co-authored-by: GeekTrainer <6109729+GeekTrainer@users.noreply.github.com>
---
.gitignore | 6 ++-
client/playwright-report/index.html | 77 -----------------------------
client/test-results/.last-run.json | 4 --
3 files changed, 5 insertions(+), 82 deletions(-)
delete mode 100644 client/playwright-report/index.html
delete mode 100644 client/test-results/.last-run.json
diff --git a/.gitignore b/.gitignore
index 7f10982..60498f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,4 +37,8 @@ instance/
.webassets-cache
flask_session/
.coverage
-htmlcov/
\ No newline at end of file
+htmlcov/
+
+# playwright
+client/test-results/
+client/playwright-report/
\ No newline at end of file
diff --git a/client/playwright-report/index.html b/client/playwright-report/index.html
deleted file mode 100644
index 32fa3ef..0000000
--- a/client/playwright-report/index.html
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-
-
-
-
-
-
- Playwright Test Report
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/client/test-results/.last-run.json b/client/test-results/.last-run.json
deleted file mode 100644
index cbcc1fb..0000000
--- a/client/test-results/.last-run.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "status": "passed",
- "failedTests": []
-}
\ No newline at end of file
From 2e318d067b9f12fd68ed071e5d4974c410d578b0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 30 Jul 2025 18:09:10 +0000
Subject: [PATCH 04/40] Update Playwright configuration to use only WebKit
browser
Co-authored-by: GeekTrainer <6109729+GeekTrainer@users.noreply.github.com>
---
client/e2e-tests/README.md | 4 ++--
client/package.json | 2 +-
client/playwright.config.ts | 7 ++-----
3 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/client/e2e-tests/README.md b/client/e2e-tests/README.md
index 3c48202..b7d198c 100644
--- a/client/e2e-tests/README.md
+++ b/client/e2e-tests/README.md
@@ -30,8 +30,8 @@ npm run test:e2e:ui
# Run tests in headed mode (see browser)
npm run test:e2e:headed
-# Run only Chromium tests
-npm run test:e2e:chromium
+# Run only WebKit tests
+npm run test:e2e:webkit
# Debug tests
npm run test:e2e:debug
diff --git a/client/package.json b/client/package.json
index 165cae7..48bf018 100644
--- a/client/package.json
+++ b/client/package.json
@@ -11,7 +11,7 @@
"test:e2e:ui": "playwright test --ui",
"test:e2e:debug": "playwright test --debug",
"test:e2e:headed": "playwright test --headed",
- "test:e2e:chromium": "playwright test --project=chromium"
+ "test:e2e:webkit": "playwright test --project=webkit"
},
"dependencies": {
"@astrojs/node": "^9.1.3",
diff --git a/client/playwright.config.ts b/client/playwright.config.ts
index 0cb887c..be0145c 100644
--- a/client/playwright.config.ts
+++ b/client/playwright.config.ts
@@ -27,11 +27,8 @@ export default defineConfig({
/* Configure projects for major browsers */
projects: [
{
- name: 'chromium',
- use: {
- ...devices['Desktop Chrome'],
- channel: 'chrome' // Use system Chrome instead of downloading Chromium
- },
+ name: 'webkit',
+ use: { ...devices['Desktop Safari'] },
},
],
From 5f32c3fe9f217bfaf691bd8ab16ecea848674102 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 30 Jul 2025 19:04:08 +0000
Subject: [PATCH 05/40] Update Playwright configuration to use only Chromium
browser
Co-authored-by: GeekTrainer <6109729+GeekTrainer@users.noreply.github.com>
---
client/package.json | 2 +-
client/playwright.config.ts | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/client/package.json b/client/package.json
index 48bf018..165cae7 100644
--- a/client/package.json
+++ b/client/package.json
@@ -11,7 +11,7 @@
"test:e2e:ui": "playwright test --ui",
"test:e2e:debug": "playwright test --debug",
"test:e2e:headed": "playwright test --headed",
- "test:e2e:webkit": "playwright test --project=webkit"
+ "test:e2e:chromium": "playwright test --project=chromium"
},
"dependencies": {
"@astrojs/node": "^9.1.3",
diff --git a/client/playwright.config.ts b/client/playwright.config.ts
index be0145c..19f50b8 100644
--- a/client/playwright.config.ts
+++ b/client/playwright.config.ts
@@ -27,8 +27,8 @@ export default defineConfig({
/* Configure projects for major browsers */
projects: [
{
- name: 'webkit',
- use: { ...devices['Desktop Safari'] },
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] },
},
],
From fb56683c85180d388d913048938542cc1706ae94 Mon Sep 17 00:00:00 2001
From: Christopher Harrison
Date: Tue, 26 Aug 2025 11:23:29 -0700
Subject: [PATCH 06/40] Small markdown updates
---
.gitignore | 4 +++-
content/full-day/1-code-scanning.md | 4 ++--
content/full-day/2-issues.md | 8 +++++---
content/full-day/3-codespaces.md | 6 ++++--
content/full-day/4-testing.md | 7 ++++---
content/full-day/5-context.md | 1 -
6 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7f10982..3fa2390 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,4 +37,6 @@ instance/
.webassets-cache
flask_session/
.coverage
-htmlcov/
\ No newline at end of file
+htmlcov/
+
+test-results/
\ No newline at end of file
diff --git a/content/full-day/1-code-scanning.md b/content/full-day/1-code-scanning.md
index cf074c0..ebd9625 100644
--- a/content/full-day/1-code-scanning.md
+++ b/content/full-day/1-code-scanning.md
@@ -50,8 +50,8 @@ Regardless of the reason, even seemingly innocuous tokens can create a security
Let's enable Secret scanning to detect any potential keys.
1. On the same page (**Settings** > **Code security and analysis**), towards the very bottom, locate the **Secret scanning** section.
-1. Next to **Receive alerts on GitHub for detected secrets, keys or other tokens**, select **Enable**.
-1. Next to **Push protection**, select **Enable** to block pushes to the repository which contain a [supported secret][supported-secrets].
+2. Next to **Receive alerts on GitHub for detected secrets, keys or other tokens**, select **Enable**.
+3. Next to **Push protection**, select **Enable** to block pushes to the repository which contain a [supported secret][supported-secrets].

diff --git a/content/full-day/2-issues.md b/content/full-day/2-issues.md
index aeb2bdf..c63eb6c 100644
--- a/content/full-day/2-issues.md
+++ b/content/full-day/2-issues.md
@@ -26,9 +26,9 @@ Our project needs two main updates. We want to make the updates to support devel
1. Return to the repository you created at the beginning of this workshop.
1. Select the **Issues** tab.
1. Select **New issue**.
-2. If prompted for type, select **Blank issue**.
-3. Select **Create more** at the bottom of the page to streamline the creation process.
-4. Create new issues by adding the information indicated in the table below, selecting **Submit new issue** after creating each one:
+1. If prompted for type, select **Blank issue**.
+1. Select **Create more** at the bottom of the page to streamline the creation process.
+1. Create new issues by adding the information indicated in the table below, selecting **Submit new issue** after creating each one:
| Title | Description |
| ----------------------- | ------------------------------------------------------------------------------ |
@@ -42,9 +42,11 @@ Our project needs two main updates. We want to make the updates to support devel
You've now defined all the issues for the workshop! You'll use these issues to help guide your progress through the workshop.
## Summary and next steps
+
GitHub Issues are the core to project management on GitHub. Their flexibility allows your organization to determine the best course of action to support your development lifecycle's methodology. With your issues created, it's time to turn your attention to the first big change to the project, [defining a codespace][walkthrough-next].
## Resources
+
- [GitHub Issues][issues-docs]
- [Communicate using markdown][skills-markdown]
- [GitHub Projects][projects-docs]
diff --git a/content/full-day/3-codespaces.md b/content/full-day/3-codespaces.md
index ed5538c..bf253cf 100644
--- a/content/full-day/3-codespaces.md
+++ b/content/full-day/3-codespaces.md
@@ -104,8 +104,8 @@ You've now defined a custom container!
Whenever someone uses the codespace you defined they'll have an environment with Node.js and Mongo DB, and the GitHub Copilot extension installed. Let's use this container!
1. Access the Command Palette (F1 or clicking ☰ → View → Command Palette), then start typing **dev container**.
-1. Type **rebuild** and select **Codespaces: Rebuild container**.
-1. Select **Rebuild Container** on the dialog box. Your container now rebuilds.
+2. Type **rebuild** and select **Codespaces: Rebuild container**.
+3. Select **Rebuild Container** on the dialog box. Your container now rebuilds.
> [!IMPORTANT]
> Rebuilding the container can take several minutes. Obviously this isn't an ideal situation for providing fast access to your developers, even if it's faster than creating everything from scratch. Fortunately you can [prebuild your codespaces][codespace-prebuild] to ensure developers can spin one up within seconds.
@@ -149,9 +149,11 @@ Custom containers for GitHub Codespaces become part of the source code for the r
## Summary and next steps
+
Congratulations! You have now defined a custom development environment including all services and extensions. This eliminates the initial setup hurdle normally required when contributing to a project. Let's use this codespace to [implement testing and continuous integration][walkthrough-next] for the project.
## Resources
+
- [GitHub Codespaces][codespaces]
- [Getting started with GitHub Codespaces][codespaces-docs]
- [Defining dev containers][dev-containers-docs]
diff --git a/content/full-day/4-testing.md b/content/full-day/4-testing.md
index 9146a9f..795309c 100644
--- a/content/full-day/4-testing.md
+++ b/content/full-day/4-testing.md
@@ -54,10 +54,10 @@ Now that we have an overview of the structure of a workflow, let's ask Copilot t
5. Add the test file **test_app.py** to the context by using the `#` in the Chat dialog box and beginning to type **test_app.py**, and pressing enter when it's highlighted.
6. Prompt Copilot to create a GitHub Action workflow to run the tests. Use natural language to describe the workflow you're looking to create (to run the tests defined in test_app.py), and that you want it to run on merge (for when new code is pushed), when a PR is made, and on demand.
- > [!IMPORTANT]
- > A prescriptive prompt isn't provided as part of the exercise is to become comfortable interacting with GitHub Copilot.
+> [!IMPORTANT]
+> A prescriptive prompt isn't provided as part of the exercise is to become comfortable interacting with GitHub Copilot.
-6. Add the generated code to the new file by hovering over the suggested code and selecting the **Insert at cursor** button. The generated code should resemble the following:
+7. Add the generated code to the new file by hovering over the suggested code and selecting the **Insert at cursor** button. The generated code should resemble the following:
```yml
name: Server Tests
@@ -154,6 +154,7 @@ You've now seen a workflow, and explore the details of a run!
Congratulations! You've implemented automated testing, a standard part of continuous integration, which is critical to successful DevOps. Automating these processes ensures consistency and reduces the workload required for developers and administrators. You have created a workflow to run tests on any new code for your codebase. Let's explore [context with GitHub Copilot chat][walkthrough-next].
### Resources
+
- [GitHub Actions][github-actions]
- [GitHub Actions Marketplace][actions-marketplace]
- [About continuous integration][about-ci]
diff --git a/content/full-day/5-context.md b/content/full-day/5-context.md
index 9c10edc..52642ff 100644
--- a/content/full-day/5-context.md
+++ b/content/full-day/5-context.md
@@ -127,4 +127,3 @@ Congratulations! You've explored context in GitHub Copilot, which is key to gene
[walkthrough-codespaces]: ./3-codespaces.mdvisualstudio.com/docs/copilot/copilot-chat
[walkthrough-next]: 6-code.md
[walkthrough-previous]: 4-testing.md
-
From 75abcdf86274122f331ebc817763e41bdb7de927 Mon Sep 17 00:00:00 2001
From: Christopher Harrison
Date: Tue, 26 Aug 2025 13:40:05 -0700
Subject: [PATCH 07/40] Fix numbering in testing documentation for clarity
---
content/full-day/4-testing.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/content/full-day/4-testing.md b/content/full-day/4-testing.md
index 9146a9f..1d01085 100644
--- a/content/full-day/4-testing.md
+++ b/content/full-day/4-testing.md
@@ -57,7 +57,7 @@ Now that we have an overview of the structure of a workflow, let's ask Copilot t
> [!IMPORTANT]
> A prescriptive prompt isn't provided as part of the exercise is to become comfortable interacting with GitHub Copilot.
-6. Add the generated code to the new file by hovering over the suggested code and selecting the **Insert at cursor** button. The generated code should resemble the following:
+7. Add the generated code to the new file by hovering over the suggested code and selecting the **Insert at cursor** button. The generated code should resemble the following:
```yml
name: Server Tests
From aefe4b13715c5b48583a03621b62b378fa4ea4d7 Mon Sep 17 00:00:00 2001
From: Christopher Harrison
Date: Tue, 26 Aug 2025 13:40:57 -0700
Subject: [PATCH 08/40] Add playwright report directory to .gitignore
---
.gitignore | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index 3fa2390..2477338 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,4 +39,5 @@ flask_session/
.coverage
htmlcov/
-test-results/
\ No newline at end of file
+test-results/
+playwright-report/
\ No newline at end of file
From 0433ce77904a16a48ad4d6779d9a9d7f5d557477 Mon Sep 17 00:00:00 2001
From: Christopher Harrison
Date: Tue, 26 Aug 2025 13:42:35 -0700
Subject: [PATCH 09/40] Updated folder structure to remove 1-hour version
---
content/{full-day => }/0-setup.md | 0
content/{full-day => }/1-code-scanning.md | 0
content/1-hour/0-setup.md | 86 -------------
content/1-hour/1-add-endpoint.md | 106 ----------------
content/1-hour/2-explore-project.md | 49 --------
content/1-hour/3-copilot-instructions.md | 115 ------------------
content/1-hour/4-add-feature.md | 103 ----------------
content/1-hour/5-bonus.md | 84 -------------
content/1-hour/README.md | 77 ------------
content/1-hour/images/0-setup-configure.png | Bin 209035 -> 0 bytes
content/1-hour/images/0-setup-template.png | Bin 73713 -> 0 bytes
.../copilot-agent-mode-how-it-works.png | Bin 189977 -> 0 bytes
.../1-hour/images/copilot-chat-references.png | Bin 119947 -> 0 bytes
.../1-hour/images/copilot-edits-history.png | Bin 9312 -> 0 bytes
.../images/copilot-edits-keep-undo-file.png | Bin 130271 -> 0 bytes
.../images/copilot-edits-keep-undo-global.png | Bin 45642 -> 0 bytes
.../tail-spin-shelter-terminal-theme.png | Bin 120111 -> 0 bytes
content/{full-day => }/2-issues.md | 0
content/{full-day => }/3-codespaces.md | 0
content/{full-day => }/4-testing.md | 0
content/{full-day => }/5-context.md | 0
content/{full-day => }/6-code.md | 0
content/{full-day => }/7-github-flow.md | 0
content/{full-day => }/8-deployment.md | 0
content/GitHub-Copilot-Resources.md | 47 -------
content/README.md | 69 +++++++++--
content/full-day/README.md | 67 ----------
.../images/1-code-scanning-dialog.png | Bin
.../{full-day => }/images/1-code-scanning.png | Bin
.../{full-day => }/images/1-dependabot.png | Bin
.../images/1-secret-scanning.png | Bin
.../{full-day => }/images/3-open-browser.png | Bin
content/{full-day => }/images/3-reload.png | Bin
.../images/3-secrets-variables.png | Bin
.../{full-day => }/images/4-select-file.png | Bin
.../images/5-copilot-chat-references.png | Bin
.../images/7-generate-commit-message.png | Bin
content/prompts/README.md | 17 ---
.../conversion-convert-flask-to-golang.md | 24 ----
content/prompts/fun-add-dog-animation.md | 13 --
content/prompts/fun-add-themes.md | 40 ------
content/prompts/monitoring-add-logging.md | 30 -----
42 files changed, 62 insertions(+), 865 deletions(-)
rename content/{full-day => }/0-setup.md (100%)
rename content/{full-day => }/1-code-scanning.md (100%)
delete mode 100644 content/1-hour/0-setup.md
delete mode 100644 content/1-hour/1-add-endpoint.md
delete mode 100644 content/1-hour/2-explore-project.md
delete mode 100644 content/1-hour/3-copilot-instructions.md
delete mode 100644 content/1-hour/4-add-feature.md
delete mode 100644 content/1-hour/5-bonus.md
delete mode 100644 content/1-hour/README.md
delete mode 100644 content/1-hour/images/0-setup-configure.png
delete mode 100644 content/1-hour/images/0-setup-template.png
delete mode 100644 content/1-hour/images/copilot-agent-mode-how-it-works.png
delete mode 100644 content/1-hour/images/copilot-chat-references.png
delete mode 100644 content/1-hour/images/copilot-edits-history.png
delete mode 100644 content/1-hour/images/copilot-edits-keep-undo-file.png
delete mode 100644 content/1-hour/images/copilot-edits-keep-undo-global.png
delete mode 100644 content/1-hour/images/tail-spin-shelter-terminal-theme.png
rename content/{full-day => }/2-issues.md (100%)
rename content/{full-day => }/3-codespaces.md (100%)
rename content/{full-day => }/4-testing.md (100%)
rename content/{full-day => }/5-context.md (100%)
rename content/{full-day => }/6-code.md (100%)
rename content/{full-day => }/7-github-flow.md (100%)
rename content/{full-day => }/8-deployment.md (100%)
delete mode 100644 content/GitHub-Copilot-Resources.md
delete mode 100644 content/full-day/README.md
rename content/{full-day => }/images/1-code-scanning-dialog.png (100%)
rename content/{full-day => }/images/1-code-scanning.png (100%)
rename content/{full-day => }/images/1-dependabot.png (100%)
rename content/{full-day => }/images/1-secret-scanning.png (100%)
rename content/{full-day => }/images/3-open-browser.png (100%)
rename content/{full-day => }/images/3-reload.png (100%)
rename content/{full-day => }/images/3-secrets-variables.png (100%)
rename content/{full-day => }/images/4-select-file.png (100%)
rename content/{full-day => }/images/5-copilot-chat-references.png (100%)
rename content/{full-day => }/images/7-generate-commit-message.png (100%)
delete mode 100644 content/prompts/README.md
delete mode 100644 content/prompts/conversion-convert-flask-to-golang.md
delete mode 100644 content/prompts/fun-add-dog-animation.md
delete mode 100644 content/prompts/fun-add-themes.md
delete mode 100644 content/prompts/monitoring-add-logging.md
diff --git a/content/full-day/0-setup.md b/content/0-setup.md
similarity index 100%
rename from content/full-day/0-setup.md
rename to content/0-setup.md
diff --git a/content/full-day/1-code-scanning.md b/content/1-code-scanning.md
similarity index 100%
rename from content/full-day/1-code-scanning.md
rename to content/1-code-scanning.md
diff --git a/content/1-hour/0-setup.md b/content/1-hour/0-setup.md
deleted file mode 100644
index 221e352..0000000
--- a/content/1-hour/0-setup.md
+++ /dev/null
@@ -1,86 +0,0 @@
-# Workshop setup
-
-| [← Getting started with GitHub Copilot][walkthrough-previous] | [Next: Coding with GitHub Copilot →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-To complete this workshop you will need to create a repository with a copy of the contents of this repository. While this can be done by [forking a repository][fork-repo], the goal of a fork is to eventually merge code back into the original (or upstream) source. In our case we want a separate copy as we don't intend to merge our changes. This is accomplished through the use of a [template repository][template-repo]. Template repositories are a great way to provide starters for your organization, ensuring consistency across projects.
-
-The repository for this workshop is configured as a template, so we can use it to create your repository.
-
-> [!IMPORTANT]
-> Ensure you have the [requisite software][required-software] and [requisite resources][required-resources] setup.
-
-## Create your repository
-
-Let's create the repository you'll use for your workshop.
-
-1. Navigate to [the repository root](/)
-2. Select **Use this template** > **Create a new repository**
-
- 
-
-3. Under **Owner**, select the name of your GitHub handle, or the owner specified by your workshop leader.
-4. Under **Repository**, set the name to **pets-workshop**, or the name specified by your workshop leader.
-5. Ensure **Public** is selected for the visibility, or the value indicated by your workshop leader.
-6. Select **Create repository from template**.
-
- 
-
-In a few moments a new repository will be created from the template for this workshop!
-
-## Clone the repository and start the app
-
-With the repository created, it's now time to clone the repository locally. We'll do this from a shell capable of running BASH commands.
-
-1. Copy the URL for the repository you just created in the prior set.
-2. Open your terminal or command shell.
-3. Run the following command to clone the repository locally (changing directories to a parent directory as appropriate):
-
- ```sh
- git clone
- ```
-
-4. Change directories into the cloned repository by running the following command:
-
- ```sh
- cd
- ```
-
-5. Start the application by running the following command:
-
- ```sh
- ./scripts/start-app.sh
- ```
-
-The startup script will start two applications:
-
-- The backend Flask app on [localhost:5100][flask-url]. You can see a list of dogs by opening the [dogs API][dogs-api].
-- The frontend Astro/Svelte app on [localhost:4321][astro-url]. You can see the [website][website-url] by opening that URL.
-
-## Open your editor
-
-With the code cloned locally, and the site running, let's open the codebase up in VS Code.
-
-1. Open VS Code.
-2. Select **File** > **Open Folder**.
-3. Navigate to the folder which contains the project you cloned earlier in this exercise.
-4. With the folder highlighted, select **Open folder**.
-
-## Summary and next steps
-
-You've now cloned the repository you'll use for this workshop and have your IDE setup! Next let's [add a new endpoint to the server][walkthrough-next]!
-
-
-| [← Getting started with GitHub Copilot][walkthrough-previous] | [Next: Coding with GitHub Copilot →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-[astro-url]: http://localhost:4321
-[dogs-api]: http://localhost:5100/api/dogs
-[flask-url]: http://localhost:5100
-[fork-repo]: https://docs.github.com/en/get-started/quickstart/fork-a-repo
-[required-resources]: ./README.md#required-resources
-[required-software]: ./README.md#required-local-installation
-[template-repo]: https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository
-[walkthrough-previous]: README.md
-[walkthrough-next]: ./1-add-endpoint.md
-[website-url]: http://localhost:4321
\ No newline at end of file
diff --git a/content/1-hour/1-add-endpoint.md b/content/1-hour/1-add-endpoint.md
deleted file mode 100644
index 84fbbaf..0000000
--- a/content/1-hour/1-add-endpoint.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# Coding with GitHub Copilot
-
-| [← Workshop setup][walkthrough-previous] | [Next: Helping GitHub Copilot understand context →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-
-With code completions, GitHub Copilot provides suggestions in your code editor while you're coding. This can turn comments into code, generate the next line of code, and generate an entire function just from a signature. Code completion helps reduce the amount of boilerplate code and ceremony you need to type, allowing you to focus on the important aspects of what you're creating.
-
-## Scenario
-
-It's standard to work in phases when adding functionality to an application. Given that we know we want to allow users to filter the list of dogs based on breed, we'll need to add an endpoint to provide a list of all breeds. Later we'll add the rest of the functionality, but let's focus on this part for now.
-
-The application uses a Flask app with SQLAlchemy as the backend API (in the [/server][server-code] folder), and an Astro app with Svelte as the frontend (in the [/client][client-code] folder). You will explore more of the project later; this exercise will focus solely on the Flask application.
-
-> [!NOTE]
-> As you begin making changes to the application, there is always a chance a breaking change could be created. If the page stops working, check the terminal window you used previously to start the application for any error messages. You can stop the app by using Ctl+C, and restart it by running `./scripts/start-app.sh`.
-
-## Flask routes
-
-While we won't be able to provide a full overview of [routing in Flask][flask-routing], they are defined by using the Python decorator `@app.route`. There are a couple of parameters you can provide to `@app.route`, including the path (or URL) one would use to access the route (such as **api/breeds**), and the [HTTP method(s)][http-methods] which can be used.
-
-## Code completion
-
-Code completion predicts the next block of code you're about to type based on the context Copilot has. For code completion, this includes the file you're currently working on and any tabs open in your IDE.
-
-Code completion is best for situations where you know what you want to do, and are more than happy to just start writing code with a bit of a helping hand along the way. Suggestions will be generated based both on the code you write (say a function definition) and comments you add to your code.
-
-## Create the breeds endpoint
-
-Let's build our new route in our Flask backend with the help of code completion.
-
-> [!IMPORTANT]
-> For this exercise, **DO NOT** copy and paste the code snippet provided, but rather type it manually. This will allow you to experience code completion as you would if you were coding back at your desk. You'll likely see you only have to type a few characters before GitHub Copilot begins suggesting the rest.
-
-1. Return to your IDE with the project open.
-2. Open **server/app.py**.
-3. Locate the comment which reads `## HERE`, which should be at line 68.
-4. Delete the comment to ensure there isn't any confusion for Copilot, and leave your cursor there.
-5. Begin adding the code to create the route to return all breeds from an endpoint of **api/breeds** by typing the following:
-
- ```python
- @app.route('/api/breeds', methods=['GET'])
- ```
-
-6. Once you see the full function signature, select Tab to accept the code suggestion.
-7. If it didn't already, code completion should then suggest the remainder of the function signature; just as before select Tab to accept the code suggestion.
-
- The code generated should look a little like this:
-
- ```python
- @app.route('/api/breeds', methods=['GET'])
- def get_breeds():
- # Query all breeds
- breeds_query = db.session.query(Breed.id, Breed.name).all()
-
- # Convert the result to a list of dictionaries
- breeds_list = [
- {
- 'id': breed.id,
- 'name': breed.name
- }
- for breed in breeds_query
- ]
-
- return jsonify(breeds_list)
- ```
-
-> [!IMPORTANT]
-> Because LLMs are probabilistic, not deterministic, the exact code generated can vary. The above is a representative example. If your code is different, that's just fine as long as it works!
-
-8. Add a comment to the newly created function. To do this, place your cursor inside the function (anywhere between the lines `def get_breeds...` and `return jsonify...`). Then, press Ctl+I (or cmd+I on a Mac) to open the editor inline chat. In the input box, type `/doc`. (You can optionally provide additional details, but it's not required). This will prompt GitHub Copilot to generate a documentation comment for the function. The suggested comment will appear inline in the code (highlighted in green). Click **Accept** to apply the comment to your code, or click **Close** to discard the suggestion. You just used a slash command, a shortcut to streamline a task, these commands eliminate the need for verbose prompts.
-
-9. **Save** the file.
-
-## Validate the endpoint
-
-With the code created and saved, let's quickly validate the endpoint to ensure it works.
-
-1. Navigate to [http://localhost:5100/api/breeds][breeds-endpoint] to validate the route. You should see JSON displayed which contains the list of breeds!
-
-## Summary and next steps
-
-You've added a new endpoint with the help of GitHub Copilot! You saw how Copilot predicted the next block of code you were likely looking for and provided the suggestion inline, helping save you the effort of typing it out manually. Let's start down the path of performing more complex operations by [exploring our project][walkthrough-next].
-
-## Resources
-
-- [Code suggestions in your IDE with GitHub Copilot][copilot-suggestions]
-- [Code completions with GitHub Copilot in VS Code][vscode-copilot]
-- [Prompt crafting][prompt-crafting]
-- [Inline chat][inline-chat]
-
-
-| [← Workshop setup][walkthrough-previous] | [Next: Helping GitHub Copilot understand context →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-[breeds-endpoint]: http://localhost:5100/api/breeds
-[client-code]: /client/
-[copilot-suggestions]: https://docs.github.com/en/copilot/using-github-copilot/getting-code-suggestions-in-your-ide-with-github-copilot
-[flask-routing]: https://flask.palletsprojects.com/en/stable/quickstart/#routing
-[http-methods]: https://www.w3schools.com/tags/ref_httpmethods.asp
-[prompt-crafting]: https://code.visualstudio.com/docs/copilot/prompt-crafting
-[inline-chat]: https://code.visualstudio.com/docs/copilot/chat/inline-chat
-[server-code]: /server/
-[vscode-copilot]: https://code.visualstudio.com/docs/copilot/ai-powered-suggestions
-[walkthrough-previous]: ./0-setup.md
-[walkthrough-next]: ./2-explore-project.md
\ No newline at end of file
diff --git a/content/1-hour/2-explore-project.md b/content/1-hour/2-explore-project.md
deleted file mode 100644
index 5e73d18..0000000
--- a/content/1-hour/2-explore-project.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Helping GitHub Copilot understand context
-
-| [← Coding with GitHub Copilot][walkthrough-previous] | [Next: Providing custom instructions →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-The key to success when coding (and much of life) is context. Before we add code to a codebase, we want to understand the rules and structures already in place. When working with an AI coding assistant such as GitHub Copilot the same concept applies - the quality of suggestion is directly proportional to the context Copilot has. Let's use this opportunity to both explore the project we've been given and how to interact with Copilot to ensure it has the context it needs to do its best work.
-
-## Scenario
-
-Before adding new functionality to the website, you want to explore the existing structure to determine where the updates need to be made.
-
-## Chat participants and extensions
-
-GitHub Copilot Chat has a set of available [chat participants][chat-participants] and [extensions][copilot-extensions] available to you to both provide instructions to GitHub Copilot and access external services. Chat participants are helpers which work inside your IDE and have access to your project, while extensions can call external services and provide information to you without having to open separate tools. We're going to focus on one core chat participant - `@workspace`.
-
-`@workspace` creates an index of your project and allows you to ask questions about what you're currently working on, to find resources inside the project, or add it to the context. It's best to use this when the entirety of your project should be considered or you're not entirely sure where you should start looking. In our current scenario, since we want to ask questions about our project, `@workspace` is the perfect tool for the job.
-
-> [!NOTE]
-> This exercise doesn't provide specific prompts to type, as part of the learning experience is to discover how to interact with Copilot. Feel free to talk in natural language, describing what you're looking for or need to accomplish.
-
-1. Return to your IDE with the project open.
-2. Close any tabs you may have open in your IDE to ensure the context for Copilot chat is empty.
-3. Open GitHub Copilot Chat.
-4. Select the `+` icon towards the top of Copilot chat to begin a new chat.
-5. Type `@workspace` in the chat prompt window and hit tab to select or activate it, then continue by asking Copilot about your project. You can ask what technologies are in use, what the project does, where functionality resides, etc.
-6. Spend a few minutes exploring to find the answers to the following questions:
- - Where's the database the project uses?
- - What files are involved in listing dogs?
-
-## Summary and next steps
-
-You've explored context in GitHub Copilot, which is key to generating quality suggestions. You saw how you can use chat participants to help guide GitHub Copilot, and how with natural language you can explore the project. Let's see how we can provide even more context to Copilot chat through the use of [Copilot instructions][walkthrough-next].
-
-## Resources
-
-- [Copilot Chat cookbook][copilot-cookbook]
-- [Use Copilot Chat in VS Code][copilot-chat-vscode]
-- [Copilot extensions marketplace][copilot-marketplace]
-
-| [← Coding with GitHub Copilot][walkthrough-previous] | [Next: Providing custom instructions →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-[chat-participants]: https://code.visualstudio.com/docs/copilot/copilot-chat#_chat-participants
-[copilot-chat-vscode]: https://code.visualstudio.com/docs/copilot/copilot-chat
-[copilot-cookbook]: https://docs.github.com/en/copilot/copilot-chat-cookbook
-[copilot-extensions]: https://docs.github.com/en/copilot/using-github-copilot/using-extensions-to-integrate-external-tools-with-copilot-chat
-[copilot-marketplace]: https://github.com/marketplace?type=apps&copilot_app=true
-[walkthrough-previous]: ./1-add-endpoint.md
-[walkthrough-next]: ./3-copilot-instructions.md
\ No newline at end of file
diff --git a/content/1-hour/3-copilot-instructions.md b/content/1-hour/3-copilot-instructions.md
deleted file mode 100644
index b9b07ff..0000000
--- a/content/1-hour/3-copilot-instructions.md
+++ /dev/null
@@ -1,115 +0,0 @@
-# Providing custom instructions
-
-| [← Coding with GitHub Copilot][walkthrough-previous] | [Next: Add the filter feature →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-There are always key pieces of information anyone generating code for your codebase needs to know - the technologies in use, coding standards to follow, project structure, etc. Since context is so important, as we've discussed, we likely want to ensure Copilot always has this information as well. Fortunately, we can provide this overview through the use of Copilot instructions.
-
-## Scenario
-
-Before we begin larger updates to the site with the help of Copilot, we want to ensure Copilot has a good understanding of how we're building our application. As a result, we're going to add a Copilot instructions file to the repository.
-
-## Overview of Copilot instructions
-
-Copilot instructions is a markdown file is placed in your **.github** folder. It becomes part of your project, and in turn to all contributors to your codebase. You can use this file to indicate various coding standards you wish to follow, the technologies your project uses, or anything else important for Copilot Chat to understand when generating suggestions.
-
-> [!IMPORTANT]
-> The *copilot-instructions.md* file is included in **every** call to GitHub Copilot Chat, and will be part of the context sent to Copilot. Because there is always a limited set of tokens an LLM can operate on, a large Copilot instructions file can obscure relevant information. As such, you should limit your Copilot instructions file to project-wide information, providing an overview of what you're building and how you're building it. If you need to provide more specific information for particular tasks, you can create [prompt files](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot?tool=vscode#about-prompt-files).
-
-Here are some guidelines to consider when creating a Copilot instructions file:
-
-- The Copilot instructions file becomes part of the project, meaning it will apply to every developer; anything indicated in the file should be globally applicable.
-- The file is markdown, so you can take advantage of that fact by grouping content together to improve readability.
-- Provide overview of **what** you are building and **how** you are building it, including:
- - languages, frameworks and libraries in use.
- - required assets to be generated (such as unit tests) and where they should be placed.
- - any language specific rules such as:
- - utilize [type hints][type-hints] in Python.
- - use [arrow functions][arrow-functions] rather than the `function` keyword in TypeScript.
-- If you notice GitHub Copilot consistently provides an unexpected suggestion (e.g. using class components for React), add those notes to the instructions file.
-
-## Create a Copilot instructions file
-
-Let's create a Copilot instructions file. We'll start by asking Copilot to generate a block of code, then add the instructions file, then ask the same question again to see the changes.
-
-1. Return to your IDE with your project open.
-2. Close any tabs you may have open in your IDE to ensure Copilot chat has an empty context.
-3. Select the `+` icon towards the top of Copilot chat to begin a new chat.
-4. Open Copilot Chat and send the following prompt:
-
- ```
- Create a Python function to validate dog age. Ensure age is between 0 and 20. Throw an error if it is outside this range.
- ```
-
-5. Note the function signature is similar to `def validate_dog_age(age)` without type hints.
-
-> [!NOTE]
-> Because LLMs are probabilistic rather than deterministic, the exact code will vary.
-
-6. Create a new file in the **.github** folder called **copilot-instructions.md**.
-7. Add the markdown to the file necessary which provides information about the project structure and requirements:
-
- ```markdown
- # Dog shelter
-
- This is an application to allow people to look for dogs to adopt. It is built in a monorepo, with a Flask-based backend and Astro-based frontend.
-
- ## Backend
-
- - Built using Flask and SQLAlchemy
- - Use type hints
-
- ## Frontend
-
- - Built using Astro and Svelte
- - TypeScript should use arrow functions rather than the function keyword
- - Pages should be in dark mode with a modern look and feel
- ```
-
-8. **Save** the file.
-
-## Watch the instructions file in action
-
-Whenever you make a call to Copilot chat, the references dialog indicates all files used to generate the response. Once you create a Copilot instructions file, you will see it's always included in the references section. Since you included directions to use type hints, you'll notice the code suggestions will follow this guidance.
-
-1. Close all files currently open in VS Code or your Codespace. (This will ensure we are working with an empty context.)
-2. Select the `+` icon in GitHub Copilot chat to start a new chat.
-3. Send Copilot chat the same prompt you used previously:
-
- ```
- Create a Python function to validate dog age. Ensure age is between 0 and 20. Throw an error if it is outside this range.
- ```
-
-> [!TIP]
-> You can use up arrow to resend previous prompts to Copilot chat.
-
-4. Note the references now includes the instructions file and provides information gathered from it.
-
- 
-
-5. Note the resulting Python now utilizes type hints, and the function signature will resemble the following:
-
- ```python
- def validate_dog_age(age: int):
- ```
-
-> [!NOTE]
-> The exact code generated will vary, but the new Python suggestion should now utilize type hints.
-
-## Summary and next steps
-
-Copilot instructions improves the quality of suggestions, and ensures better alignment with the desired practices you have in place. With the groundwork in place, let's [add new functionality to our website][walkthrough-next]!
-
-## Resources
-
-- [Adding repository custom instructions for GitHub Copilot][custom-instructions]
-
-
-| [← Coding with GitHub Copilot][walkthrough-previous] | [Next: Add the filter feature →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-[arrow-functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
-[custom-instructions]: https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot
-[type-hints]: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
-[walkthrough-previous]: ./2-explore-project.md
-[walkthrough-next]: ./4-add-feature.md
\ No newline at end of file
diff --git a/content/1-hour/4-add-feature.md b/content/1-hour/4-add-feature.md
deleted file mode 100644
index 52e3efc..0000000
--- a/content/1-hour/4-add-feature.md
+++ /dev/null
@@ -1,103 +0,0 @@
-# Add the filter feature
-
-| [← Providing custom instructions][walkthrough-previous] | [Next: Bonus content →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-We've explored how we can use GitHub Copilot to explore our project and to provide context to ensure the suggestions we receive are to the quality we expect. Now let's turn our attention to putting all this prep work into action by generating new code! We'll use GitHub Copilot to aid us in adding functionality to our website.
-
-## Scenario
-
-The website currently lists all dogs in the database. While this was appropriate when the shelter only had a few dogs, as time has gone on the number has grown and it's difficult for people to sift through who's available to adopt. The shelter has asked you to add filters to the website to allow a user to select a breed of dog and only display dogs which are available for adoption.
-
-## Copilot Edits
-
-Previously we utilized Copilot chat, which is great for working with an individual file or asking questions about our code. However, many updates necessitate changes to multiple files throughout a codebase. Even a seemingly basic change to a webpage likely requires updating HTML, CSS and JavaScript files. Copilot Edits allows you to modify multiple files at once.
-
-With Copilot Edits, you will add the files which need to be updated to the context. Once you provide the prompt, Copilot Edits will begin the updates across all files in the context. It also has the ability to create new files or add files to the context as it deems appropriate.
-
-## Add the filters to the dog list page
-
-Adding the filters to the page will require updating a minimum of two files - the Flask backend and the Svelte frontend. Fortunately, Copilot Edits can update multiple files! Let's get our page updated with the help of Copilot Edits.
-
-> [!NOTE]
-> Because Copilot Edits works best with auto-save enabled, we'll activate it. As we'll explore a little later in this exercise, Copilot Edits provides powerful tools to undo any changes you might not wish to keep.
-
-1. Return to your IDE with your project open.
-2. Close any tabs you have open inside your IDE.
-3. Enable Auto Save by selecting **File** > **Auto Save**.
-4. Open GitHub Copilot Chat.
-5. Switch to edit mode by selecting **Edit** in the chat mode dropdown at the bottom of Chat view (should be currently **Ask**)
-6. If available, select **Claude 3.5 Sonnet** from the list of available models
-7. Select **Add Context...** in the chat window.
-8. Select **server/app.py** and **client/src/components/DogList.svelte** files (you need to select **Add context** for each file)
-> [!TIP]
-> If you type the file names after clicking **Add context**, they will show up in the filter. You can also drag the files or right click file in explorer and select `Copilot -> Add File to Chat`)
-9. Ask Copilot to generate the update you want to the page, which is to add filters for both dog breed and if dogs are available for adoption. Use your own phrasing, ensuring the following requirements are met:
- - A dropdown list should be provided with all breeds
- - A checkbox should be available to only show available dogs
- - The page should automatically refresh whenever a change is made
-
-> [!NOTE]
-> You should use your own phrasing when generating the prompt. As highlighted previously, part of the exercise is to become comfortable creating prompts for GitHub Copilot. One key tip is it's always good to provide more guidance to ensure you get the code you are looking for.
-
-Copilot begins generating the suggestions!
-
-## Reviewing the suggestions
-
-Unlike our prior examples where we worked with an individual file, we're now working with changes across multiple files - and maybe multiple sections of multiple files. Fortunately, Copilot Edits has functionality to help streamline this process.
-
-GitHub Copilot will propose the following changes:
-
-- Update the endpoint to list all dogs to accept parameters for breed and availability.
-- Update the webpage to include the dropdown list and checkbox.
-
-As the code is generated, you will notice the files are displayed using an experience similar to diff files, with the new code highlighted in green and old code highlighted in red (by default).
-
-If you open an individual file, you can keep or undo changes by using the buttons provided.
-
-
-
-You can also keep or undo all changes made.
-
-
-
-And
-
-1. Review the code suggestions to ensure they behave the way you expect them to, making any necessary changes. Once you're satisfied, you can select **Keep** on the files individually or in Copilot Chat to accept all changes.
-2. Open the page at [http://localhost:4321][tailspin-shelter-website] to see the updates!
-3. Run the Python tests by using `python -m unittest` in the terminal as you did previously.
-4. If any changes are needed, explain the required updates to GitHub Copilot and allow it to generate the new code.
-
-> [!IMPORTANT]
-> Working iteratively a normal aspect of coding with an AI pair programmer. You can always provide more context to ensure Copilot understands, make additional requests, or rephrase your original prompts. To aid you in working iteratively, you will notice undo and redo buttons towards the top of the Copilot Edits interface, which allow you to move back and forth across prompts.
->
-> 
-
-5. Confirm the functionality works as expected, then select **Keep** to accept all the changes.
-6. Optional: Disable Auto Save by unselecting **File** > **Auto Save**.
-
-## Summary
-
-You've worked with GitHub Copilot to add new features to the website - the ability to filter the list of dogs. With the help of Copilot Edits, you updated multiple files across the project, and iteratively built the desired functionality.
-
-## Workshop review
-
-Over the course of the workshop you explore the core functionality of GitHub Copilot. You saw how to use code completion to get inline suggestions, chat participants to explore your project, Copilot instructions to add context, and Copilot Edits to update multiple files.
-
-There is no one right way to use GitHub Copilot. Continue to explore and try different prompts to discover what works best for your workflow and how GitHub Copilot can aid your productivity.
-
-## Resources
-
-- [Asking GitHub Copilot questions in your IDE][copilot-ask]
-- [Copilot Chat cookbook][copilot-cookbook]
-- [Copilot Edits][copilot-edits]
-
-| [← Providing custom instructions][walkthrough-previous] | [Next: Bonus content →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-[copilot-ask]: https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/asking-github-copilot-questions-in-your-ide
-[copilot-cookbook]: https://docs.github.com/en/copilot/copilot-chat-cookbook
-[copilot-edits]: https://code.visualstudio.com/docs/copilot/copilot-edits
-[tailspin-shelter-website]: http://localhost:4321
-[walkthrough-previous]: ./3-copilot-instructions.md
-[walkthrough-next]: ./5-bonus.md
diff --git a/content/1-hour/5-bonus.md b/content/1-hour/5-bonus.md
deleted file mode 100644
index de66dcd..0000000
--- a/content/1-hour/5-bonus.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# Bonus content
-
-| [← Add the filter feature][walkthrough-previous] | [Next: Pets workshop selection →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-## Overview of Copilot Agent Mode
-
-With chat agent mode in Visual Studio Code, you can use natural language to define a high-level task and to start an agentic code editing session to accomplish that task. In agent mode, Copilot **autonomously** plans the work needed and determines the relevant files and context. It then makes edits to your codebase and invokes tools to accomplish the request you made. Agent mode monitors the outcome of edits and tools and iterates to resolve any issues that arise.
-
-> [!IMPORTANT]
-> While Copilot autonomously determines the operations necessary to complete the requested task, as the developer you are always in charge. You will work with Copilot to ensure everything is completely correctly, reading and reviewing the code. You will also want to continue to follow proper DevOps practices, including code reviews, testing, security scans, etc.
-
-Why would you use agent mode instead of edit mode?
-
-- **Edit scope**: agent mode autonomously determines the relevant context and files to edit. In edit mode, you need to specify the context yourself.
-- **Task complexity**: agent mode is better suited for complex tasks that require not only code edits but also the invocation of tools and terminal commands.
-- **Duration**: agent mode involves multiple steps to process a request, so it might take longer to get a response. For example, to determine the relevant context and files to edit, determine the plan of action, and more.
-- **Self-healing**: agent mode evaluates the outcome of the generated edits and might iterate multiple times to resolve intermediate issues.
-- **Request quota**: in agent mode, depending on the complexity of the task, one prompt might result in many requests to the backend.
-
-### How it works
-
-
-
-## Add themes to the Tailspin Shelter website
-
-In this section, you will use Copilot's agent mode to add themes to the Tailspin Shelter website. You will be able to select a theme and apply it to the website.
-
-1. Return to your IDE with the project open.
-2. Close any tabs you may have open in your IDE to ensure the context for Copilot chat is empty.
-3. Select the `+` icon towards the top of Copilot chat to begin a new chat.
-4. Select agent mode, by selecting `Agent` (just like you did `Edit` before) in the model selector dropdown at the bottom of the chat window.
-5. Select one of models (some may not be available) `Claude 3.7 Sonnet`, `Claude 3.5 Sonnet` or `GPT-4.1 (Preview)`
-6. Navigate to [](../prompts/fun-add-themes.md)
-7. Copy the content of the prompt
-8. Paste the content in the copilot prompt input
-9. The agent mode will take its time, since it searches by itself the relevant files to modify, and then do multiple passes including talking with itself to refine the task at hand
-10. While Agent is doing it's thing, take the opportunity to examine the content of prompt that was used.
-11. When the agent is done (you no longer see any spinners and the thumb up/down icons will be visible), open a browser to see the results
- - Open the page at [http://localhost:4321][tailspin-shelter-website] to see the updates!
- - Examine the changes made to the files if you like
- - Was it good? If you are not happy with the results, you can refine the prompt by crafting extra prompts in the chat to improve the end results. Don't start a new session, it's an interactive process.
-12. Press `Done` when you are happy with the results
-
-You _may_ have gotten something like this for the Terminal Theme (generated with claude 3.7)
-
-
-
-> [!IMPORTANT]
-> Because LLMs are probabilistic, not deterministic, the exact code generated can vary. The above is a representative example. If your code is different, that's just fine as long as it works!
-
-## Play a bit with Copilot
-
-You've made it to the end of the one hour workshop. Congratulations! You've explored the core skills to help you get the most out of GitHub Copilot. From here you can explore various challenges on your own, and see how GitHub Copilot can support you as you continue developing.
-
-The suggestions listed here are exactly that - suggestions. You're free to come up with your own scenarios or features you think the application should have.
-
-You'll also notice there aren't step-by-step instructions here. You've already seen how you can use Copilot to aid you in development. Part of the challenge put forth with these extra suggestions is to apply what you've learned to create code!
-
-### Some prompts to play with
-
-We have provided you some prompts in [prompts][github-prompts-path] folder, which you can use directly as inspiration for your explorations.
-
-> [!TIP]
-> These prompts are meant to be used as one shot, but if have prompts that can be are generic, reusable prompt are a great way to share prompts with the team members. They can be placed in a well know folder and be invoked directly in the Copilot Chat by referencing them.
-> Learn more about [reusable prompts in Visual Studio Code][vscode-prompts]
-
-### Potential next steps
-
-Here's some ideas of how you could continue to grow and build upon what you've done:
-
-- Return to the API endpoints you updated previously in Flask and add unit tests.
-- Add paging support to the full list of dogs or any results page with more than 5 results.
-- Add a form to allow a user to apply to adopt a dog if the dog is available.
-- Add a form to allow users to register a dog they found.
-
-| [← Add the filter feature][walkthrough-previous] | [Next: Pets workshop selection →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-[walkthrough-previous]: ./4-add-feature.md
-[walkthrough-next]: ../README.md
-[tailspin-shelter-website]: http://localhost:4321
-[github-prompts-path]: ../prompts/
-[vscode-prompts]: https://aka.ms/vscode-ghcp-prompt-snippets
\ No newline at end of file
diff --git a/content/1-hour/README.md b/content/1-hour/README.md
deleted file mode 100644
index 28a5d94..0000000
--- a/content/1-hour/README.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# Getting started with GitHub Copilot
-
-| [← Pets workshop selection][walkthrough-previous] | [Next: Workshop setup →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-Built to be your AI pair programmer, [GitHub Copilot][copilot] helps you generate code and focus on what's important. Through the use of code completion you can create code from comments, and functions from just a signature. With Copilot chat you can ask questions about your codebase, create new files and update existing ones, and even perform operations which update files across your entire codebase.
-
-As with any tool, there are a set of skills which need to be acquired, which is the purpose of this (roughly) one hour workshop. You'll explore the most common workloads available to you by exploring and updating an existing application to add functionality.
-
-## Prerequisites
-
-The application for the workshop uses is built primarily with Python (Flask and SQLAlchemy) and Astro (using Tailwind and Svelte). While experience with these frameworks and languages is helpful, you'll be using Copilot to help you understand the project and generate the code. As a result, as long as you are familiar with programming you'll be able to complete the exercises!
-
-> [!NOTE]
-> When in doubt, you can always highlight a block of code you're unfamiliar with and ask GitHub Copilot chat for an explanation!
-
-## Required resources
-
-To complete this workshop, you will need the following:
-
-- A [GitHub account][github-account].
-- Access to [GitHub Copilot][copilot] (which is available for free for individuals!)
-
-## Required local installation
-
-You will also need the following available and installed locally:
-
-### Code editor
-
-- [Visual Studio Code][vscode-link].
-- [Copilot extension installed in your IDE][copilot-extension].
-
-### Local services
-
-- A recent [Node.js runtime][nodejs-link].
-- A recent version of [Python][python-link].
- - For Windows, you can install [Python via the Windows store](https://apps.microsoft.com/detail/9pjpw5ldxlz5?hl=en-US&gl=US).
-- The [git CLI][git-link].
-- A shell capable of running BASH commands.
-
-> [!NOTE]
-> Linux and macOS are able to run BASH commands without additional configuration. For Windows, you will need either [Windows Subsystem for Linux (WS)][windows-subsystem-linux] or the BASH shell available via [git][git-link].
-
-## Getting started
-
-Ready to get started? Let's go! The workshop scenario imagines you as a developer volunteering your time for a pet adoption center. You've been asked to add a filter to the website to allow people to limit their search results by breed and adoption status. You'll work over the next 5 exercises to perform the tasks!
-
-0. [Clone the repository and start the app][walkthrough-next] for the workshop.
-1. [Add an endpoint to the server][stage-1] to list all breeds.
-2. [Explore the project][stage-2] to get a better understanding of what needs to be done.
-3. [Create custom instructions][stage-3] to ensure Copilot chat has additional context.
-4. [Add the new feature][stage-4] to the website, and ensure it works!
-
-## Check out these resources to dive in and learn more
-Check out the resources in [**GitHub-Copilot-Resources.md**][GitHub-Copilot-Resources].
-
-This resource list has been carefully curated to help you to learn more about GitHub Copilot, how to use it effectively, what is coming in the future and more. There are even YouTube playlists that include the latest videos from the GitHub Developer Relations team and others from GitHub.
-
-| [← Pets workshop selection][walkthrough-previous] | [Next: Workshop setup →][walkthrough-next] |
-|:-----------------------------------|------------------------------------------:|
-
-[copilot]: https://github.com/features/copilot
-[copilot-extension]: https://docs.github.com/en/copilot/managing-copilot/configure-personal-settings/installing-the-github-copilot-extension-in-your-environment
-[git-link]: https://git-scm.com/
-[github-account]: https://github.com/join
-[nodejs-link]: https://nodejs.org/en
-[python-link]: https://www.python.org/
-[stage-1]: ./1-add-endpoint.md
-[stage-2]: ./2-explore-project.md
-[stage-3]: ./3-copilot-instructions.md
-[stage-4]: ./4-add-feature.md
-[walkthrough-previous]: ../README.md
-[walkthrough-next]: ./0-setup.md
-[windows-python-link]: https://apps.microsoft.com/detail/9pjpw5ldxlz5
-[windows-subsystem-linux]: https://learn.microsoft.com/en-us/windows/wsl/about
-[vscode-link]: https://code.visualstudio.com/
-[GitHub-Copilot-Resources]: ../GitHub-Copilot-Resources.md
diff --git a/content/1-hour/images/0-setup-configure.png b/content/1-hour/images/0-setup-configure.png
deleted file mode 100644
index e6810be6e25a644e746a47da10e9874b3e334cb3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 209035
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