├── .DS_Store
├── .github
├── CODEOWNERS
└── dependabot.yml
├── .gitignore
├── .vscode
└── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── SUPPORT.md
├── client
├── .dockerignore
├── Dockerfile
├── README.md
├── astro.config.mjs
├── package-lock.json
├── package.json
├── public
│ └── favicon.svg
├── src
│ ├── assets
│ │ ├── astro.svg
│ │ └── background.svg
│ ├── components
│ │ ├── DogDetails.svelte
│ │ ├── DogList.svelte
│ │ └── Header.astro
│ ├── layouts
│ │ └── Layout.astro
│ ├── middleware.ts
│ ├── pages
│ │ ├── about.astro
│ │ ├── dog
│ │ │ └── [id].astro
│ │ └── index.astro
│ └── styles
│ │ └── global.css
├── svelte.config.js
└── tsconfig.json
├── content
├── .DS_Store
├── 1-hour
│ ├── 0-setup.md
│ ├── 1-add-endpoint.md
│ ├── 2-explore-project.md
│ ├── 3-copilot-instructions.md
│ ├── 4-add-feature.md
│ ├── 5-bonus.md
│ ├── README.md
│ └── images
│ │ ├── 0-setup-configure.png
│ │ ├── 0-setup-template.png
│ │ ├── copilot-agent-mode-how-it-works.png
│ │ ├── copilot-chat-references.png
│ │ ├── copilot-edits-history.png
│ │ ├── copilot-edits-keep-undo-file.png
│ │ ├── copilot-edits-keep-undo-global.png
│ │ └── tail-spin-shelter-terminal-theme.png
├── GitHub-Copilot-Resources.md
├── README.md
├── full-day
│ ├── 0-setup.md
│ ├── 1-code-scanning.md
│ ├── 2-issues.md
│ ├── 3-codespaces.md
│ ├── 4-testing.md
│ ├── 5-context.md
│ ├── 6-code.md
│ ├── 7-github-flow.md
│ ├── 8-deployment.md
│ ├── README.md
│ └── images
│ │ ├── 1-code-scanning-dialog.png
│ │ ├── 1-code-scanning.png
│ │ ├── 1-dependabot.png
│ │ ├── 1-secret-scanning.png
│ │ ├── 3-open-browser.png
│ │ ├── 3-reload.png
│ │ ├── 3-secrets-variables.png
│ │ ├── 4-select-file.png
│ │ ├── 5-copilot-chat-references.png
│ │ └── 7-generate-commit-message.png
├── how-github-uses-github.md
└── prompts
│ ├── README.md
│ ├── conversion-convert-flask-to-golang.md
│ ├── fun-add-dog-animation.md
│ ├── fun-add-themes.md
│ └── monitoring-add-logging.md
├── scripts
├── start-app.ps1
└── start-app.sh
└── server
├── app.py
├── dogshelter.db
├── models
├── __init__.py
├── base.py
├── breed.py
├── breeds.csv
├── dog.py
└── dogs.csv
├── requirements.txt
├── test_app.py
└── utils
└── seed_database.py
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/.DS_Store
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # For more information, see [docs](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-syntax)
2 |
3 | # This repository is maintained by:
4 | * @geektrainer @peckjon @chrisreddington
5 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # This is the dependabot configuration file that automates dependency updates
2 | # Updates section configures how dependabot should handle dependency updates:
3 | # - Monitors NPM dependencies in the root directory
4 | # - Checks for updates weekly
5 | # - Groups updates based on their type (dev grouped by minor/patch or prod grouped by patch)
6 | #
7 | # Learn more at https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#configuration-options-for-the-dependabotyml-file
8 | version: 2
9 | updates:
10 | - package-ecosystem: npm
11 | directory: /
12 | schedule:
13 | interval: weekly
14 | groups:
15 | npm-development:
16 | dependency-type: development
17 | update-types:
18 | - minor
19 | - patch
20 | npm-production:
21 | dependency-type: production
22 | update-types:
23 | - patch
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # build output
4 | dist/
5 |
6 | # generated types
7 | .astro/
8 |
9 | # dependencies
10 | node_modules/
11 |
12 | # logs
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | pnpm-debug.log*
17 |
18 | # environment variables
19 | .env
20 | .env.production
21 |
22 | # macOS-specific files
23 | .DS_Store
24 |
25 | # jetbrains setting folder
26 | .idea/
27 |
28 | # python
29 | venv
30 | .venv
31 | __pycache__/
32 | *.py[cod]
33 | *$py.class
34 |
35 | # flask
36 | instance/
37 | .webassets-cache
38 | flask_session/
39 | .coverage
40 | htmlcov/
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "CODEOWNERS",
4 | "codespace",
5 | "Codespaces",
6 | "containerapp",
7 | "creds",
8 | "devcontainer",
9 | "devcontainers",
10 | "prebuild"
11 | ],
12 | "github.copilot.nextEditSuggestions.enabled": true,
13 | }
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at opensource@github.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | [fork]: https://github.com/github/startups-content/fork
4 | [pr]: https://github.com/github/startups-content/compare
5 | [code-of-conduct]: CODE_OF_CONDUCT.md
6 |
7 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
8 |
9 | Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE.md).
10 |
11 | Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms.
12 |
13 | ## Prerequisites for running and testing code
14 |
15 | These are one time installations required to be able to test your changes locally as part of the pull request (PR) submission process.
16 |
17 | 1. install Go [through download](https://go.dev/doc/install) | [through Homebrew](https://formulae.brew.sh/formula/go)
18 | 1. [install golangci-lint](https://golangci-lint.run/usage/install/#local-installation)
19 |
20 | ## Submitting a pull request
21 |
22 | 1. [Fork][fork] and clone the repository
23 | 2. Make your change
24 | 3. Push to your fork and [submit a pull request][pr]
25 | 4. Pat your self on the back and wait for your pull request to be reviewed and merged.
26 |
27 | - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
28 | - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
29 |
30 | ## Resources
31 |
32 | - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
33 | - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
34 | - [GitHub Help](https://help.github.com)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 GitHub
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pets workshop
2 |
3 | This repository contains the project for two guided workshops to explore various GitHub features. The project is a website for a fictional dog shelter, with a [Flask](https://flask.palletsprojects.com/en/stable/) backend using [SQLAlchemy](https://www.sqlalchemy.org/) and [Astro](https://astro.build/) frontend using [Svelte](https://svelte.dev/) for dynamic pages.
4 |
5 | ## Getting started
6 |
7 | > **[Get started learning about development with GitHub!](./content/README.md)**
8 |
9 | ## License
10 |
11 | This project is licensed under the terms of the MIT open source license. Please refer to [MIT](./LICENSE.txt) for the full terms.
12 |
13 | ## Maintainers
14 |
15 | You can find the list of maintainers in [CODEOWNERS](./.github/CODEOWNERS).
16 |
17 | ## Support
18 |
19 | This project is provided as-is, and may be updated over time. If you have questions, please open an issue.
20 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | Thanks for helping make GitHub safe for everyone.
2 |
3 | ## Security
4 |
5 | GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub).
6 |
7 | Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation.
8 |
9 | ## Reporting Security Issues
10 |
11 | If you believe you have found a security vulnerability in any GitHub-owned repository, please report it to us through coordinated disclosure.
12 |
13 | **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
14 |
15 | Instead, please send an email to opensource-security[@]github.com.
16 |
17 | Please include as much of the information listed below as you can to help us better understand and resolve the issue:
18 |
19 | * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
20 | * Full paths of source file(s) related to the manifestation of the issue
21 | * The location of the affected source code (tag/branch/commit or direct URL)
22 | * Any special configuration required to reproduce the issue
23 | * Step-by-step instructions to reproduce the issue
24 | * Proof-of-concept or exploit code (if possible)
25 | * Impact of the issue, including how an attacker might exploit the issue
26 |
27 | This information will help us triage your report more quickly.
28 |
29 | ## Policy
30 |
31 | See [GitHub's Safe Harbor Policy](https://docs.github.com/en/github/site-policy/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms)
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # Support
2 |
3 | ## How to file issues and get help
4 |
5 | This project uses GitHub issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new issue.
6 |
7 | For help or questions about using this project, please [file an issue](/issues)
8 |
9 | **TODO: REPO MAINTAINERS** Please include one of the following statements file:
10 |
11 | - **GitHub for Startups Workshops** is under active development and maintained by GitHub staff **AND THE COMMUNITY**. We will do our best to respond to support, feature requests, and community questions in a timely manner.
12 |
13 | ## GitHub Support Policy
14 |
15 | Support for this project is limited to the resources listed above.
--------------------------------------------------------------------------------
/client/.dockerignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist
--------------------------------------------------------------------------------
/client/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:lts AS runtime
2 | WORKDIR /app
3 |
4 | COPY . .
5 |
6 | RUN npm install
7 | RUN npm run build
8 |
9 | ENV HOST=0.0.0.0
10 | ENV PORT=4321
11 | EXPOSE 4321
12 | CMD node ./dist/server/entry.mjs
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | # Astro Starter Kit: Basics
2 |
3 | ```sh
4 | npm create astro@latest -- --template basics
5 | ```
6 |
7 | [](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
8 | [](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
9 | [](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
10 |
11 | > 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
12 |
13 | 
14 |
15 | ## 🚀 Project Structure
16 |
17 | Inside of your Astro project, you'll see the following folders and files:
18 |
19 | ```text
20 | /
21 | ├── public/
22 | │ └── favicon.svg
23 | ├── src/
24 | │ ├── layouts/
25 | │ │ └── Layout.astro
26 | │ └── pages/
27 | │ └── index.astro
28 | └── package.json
29 | ```
30 |
31 | To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/).
32 |
33 | ## 🧞 Commands
34 |
35 | All commands are run from the root of the project, from a terminal:
36 |
37 | | Command | Action |
38 | | :------------------------ | :----------------------------------------------- |
39 | | `npm install` | Installs dependencies |
40 | | `npm run dev` | Starts local dev server at `localhost:4321` |
41 | | `npm run build` | Build your production site to `./dist/` |
42 | | `npm run preview` | Preview your build locally, before deploying |
43 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
44 | | `npm run astro -- --help` | Get help using the Astro CLI |
45 |
46 | ## 👀 Want to learn more?
47 |
48 | Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
49 |
--------------------------------------------------------------------------------
/client/astro.config.mjs:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import { defineConfig } from 'astro/config';
3 | import tailwindcss from '@tailwindcss/vite';
4 | import svelte from '@astrojs/svelte';
5 |
6 | import node from '@astrojs/node';
7 |
8 | // https://astro.build/config
9 | export default defineConfig({
10 | output: 'server',
11 | integrations: [
12 | svelte(),
13 | ],
14 | vite: {
15 | plugins: [tailwindcss(), svelte()]
16 | },
17 |
18 | adapter: node({
19 | mode: 'standalone'
20 | }),
21 | });
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dog-shelter",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "build": "astro build",
8 | "preview": "astro preview",
9 | "astro": "astro"
10 | },
11 | "dependencies": {
12 | "@astrojs/node": "^9.1.3",
13 | "@astrojs/svelte": "^7.0.6",
14 | "@tailwindcss/vite": "^4.0.13",
15 | "astro": "^5.4.3",
16 | "svelte": "^5.23.0",
17 | "typescript": "^5.8.2"
18 | },
19 | "devDependencies": {
20 | "@types/node": "^22.13.11",
21 | "autoprefixer": "^10.4.21",
22 | "postcss": "^8.5.3",
23 | "tailwindcss": "^4.0.14"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/client/src/assets/astro.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/client/src/assets/background.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/client/src/components/DogDetails.svelte:
--------------------------------------------------------------------------------
1 |
50 |
51 | {#if loading}
52 |
31 |
32 |
33 |
34 |
35 |
50 |
--------------------------------------------------------------------------------
/client/src/middleware.ts:
--------------------------------------------------------------------------------
1 | import { defineMiddleware } from "astro:middleware";
2 |
3 | // Get server URL from environment variable with fallback for local development
4 | const API_SERVER_URL = process.env.API_SERVER_URL || 'http://localhost:5100';
5 |
6 | // Middleware to handle API requests
7 | export const onRequest = defineMiddleware(async (context, next) => {
8 | console.log('Request URL:', context.request.url);
9 |
10 | // Guard clause: if not an API request, pass through to regular Astro handling
11 | if (!context.request.url.includes('/api/')) {
12 | return await next();
13 | }
14 |
15 | // API request handling
16 | console.log('Forwarding request to server:', API_SERVER_URL);
17 |
18 | const url = new URL(context.request.url);
19 | const apiPath = url.pathname + url.search;
20 |
21 | // Create a new request to the backend server
22 | const serverRequest = new Request(`${API_SERVER_URL}${apiPath}`, {
23 | method: context.request.method,
24 | headers: context.request.headers,
25 | body: context.request.method !== 'GET' && context.request.method !== 'HEAD' ?
26 | await context.request.clone().arrayBuffer() : undefined,
27 | });
28 |
29 | try {
30 | // Forward the request to the API server
31 | const response = await fetch(serverRequest);
32 | const data = await response.arrayBuffer();
33 |
34 | // Return the response from the API server
35 | return new Response(data, {
36 | status: response.status,
37 | statusText: response.statusText,
38 | headers: response.headers,
39 | });
40 | } catch (error) {
41 | console.error('Error forwarding request to API:', error);
42 | return new Response(JSON.stringify({ error: 'Failed to reach API server' }), {
43 | status: 502,
44 | headers: { 'Content-Type': 'application/json' }
45 | });
46 | }
47 | });
--------------------------------------------------------------------------------
/client/src/pages/about.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from '../layouts/Layout.astro';
3 | import "../styles/global.css";
4 | // about page
5 | ---
6 |
7 |
8 |
9 |
10 |
About Tailspin Shelter
11 |
12 |
13 |
14 | Nestled in the heart of Seattle, Tailspin Shelter is a warm, welcoming haven for dogs of all breeds and backgrounds. Founded in 2015 by a small group of dog lovers and rescue advocates, our mission is to give every dog a second chance at a happy, healthy life. Whether it's finding forever homes, providing medical care, or offering behavioral training, our dedicated team works tirelessly to ensure each dog's journey has a joyful destination. Inspired by Seattle's vibrant and compassionate community, we've grown from a small foster network into a full-service shelter and adoption center.
15 |
16 |
17 |
18 | The name "Tailspin" reflects both the whirlwind of emotions dogs often experience when they first arrive — and the joyful, spinning tails we see when they find their perfect match. For us, a "tailspin" is a reminder of the transformations we witness daily: from uncertainty and fear to trust, love, and boundless energy. It's this journey that fuels our work and reminds us why we do what we do. Every wagging tail is a testament to resilience and hope.
19 |
20 |
21 |
22 |
23 |
24 | Note: Tailspin Shelter is a fictional organization, created for this workshop.
25 |
Find your perfect companion from our wonderful selection of dogs looking for their forever homes.
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/client/src/styles/global.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss";
2 |
--------------------------------------------------------------------------------
/client/svelte.config.js:
--------------------------------------------------------------------------------
1 | import { vitePreprocess } from '@astrojs/svelte';
2 |
3 | export default {
4 | preprocess: vitePreprocess(),
5 | }
6 |
--------------------------------------------------------------------------------
/client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict",
3 | "include": [".astro/types.d.ts", "**/*"],
4 | "exclude": ["dist"]
5 | }
6 |
--------------------------------------------------------------------------------
/content/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/.DS_Store
--------------------------------------------------------------------------------
/content/1-hour/0-setup.md:
--------------------------------------------------------------------------------
1 | # Workshop setup
2 |
3 | | [← Getting started with GitHub Copilot][walkthrough-previous] | [Next: Coding with GitHub Copilot →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | 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.
7 |
8 | The repository for this workshop is configured as a template, so we can use it to create your repository.
9 |
10 | > [!IMPORTANT]
11 | > Ensure you have the [requisite software][required-software] and [requisite resources][required-resources] setup.
12 |
13 | ## Create your repository
14 |
15 | Let's create the repository you'll use for your workshop.
16 |
17 | 1. Navigate to [the repository root](/)
18 | 2. Select **Use this template** > **Create a new repository**
19 |
20 | 
21 |
22 | 3. Under **Owner**, select the name of your GitHub handle, or the owner specified by your workshop leader.
23 | 4. Under **Repository**, set the name to **pets-workshop**, or the name specified by your workshop leader.
24 | 5. Ensure **Public** is selected for the visibility, or the value indicated by your workshop leader.
25 | 6. Select **Create repository from template**.
26 |
27 | 
28 |
29 | In a few moments a new repository will be created from the template for this workshop!
30 |
31 | ## Clone the repository and start the app
32 |
33 | 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.
34 |
35 | 1. Copy the URL for the repository you just created in the prior set.
36 | 2. Open your terminal or command shell.
37 | 3. Run the following command to clone the repository locally (changing directories to a parent directory as appropriate):
38 |
39 | ```sh
40 | git clone
41 | ```
42 |
43 | 4. Change directories into the cloned repository by running the following command:
44 |
45 | ```sh
46 | cd
47 | ```
48 |
49 | 5. Start the application by running the following command:
50 |
51 | ```sh
52 | ./scripts/start-app.sh
53 | ```
54 |
55 | The startup script will start two applications:
56 |
57 | - The backend Flask app on [localhost:5100][flask-url]. You can see a list of dogs by opening the [dogs API][dogs-api].
58 | - The frontend Astro/Svelte app on [localhost:4321][astro-url]. You can see the [website][website-url] by opening that URL.
59 |
60 | ## Open your editor
61 |
62 | With the code cloned locally, and the site running, let's open the codebase up in VS Code.
63 |
64 | 1. Open VS Code.
65 | 2. Select **File** > **Open Folder**.
66 | 3. Navigate to the folder which contains the project you cloned earlier in this exercise.
67 | 4. With the folder highlighted, select **Open folder**.
68 |
69 | ## Summary and next steps
70 |
71 | 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]!
72 |
73 |
74 | | [← Getting started with GitHub Copilot][walkthrough-previous] | [Next: Coding with GitHub Copilot →][walkthrough-next] |
75 | |:-----------------------------------|------------------------------------------:|
76 |
77 | [astro-url]: http://localhost:4321
78 | [dogs-api]: http://localhost:5100/api/dogs
79 | [flask-url]: http://localhost:5100
80 | [fork-repo]: https://docs.github.com/en/get-started/quickstart/fork-a-repo
81 | [required-resources]: ./README.md#required-resources
82 | [required-software]: ./README.md#required-local-installation
83 | [template-repo]: https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository
84 | [walkthrough-previous]: README.md
85 | [walkthrough-next]: ./1-add-endpoint.md
86 | [website-url]: http://localhost:4321
--------------------------------------------------------------------------------
/content/1-hour/1-add-endpoint.md:
--------------------------------------------------------------------------------
1 | # Coding with GitHub Copilot
2 |
3 | | [← Workshop setup][walkthrough-previous] | [Next: Helping GitHub Copilot understand context →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 |
7 | 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.
8 |
9 | ## Scenario
10 |
11 | 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.
12 |
13 | 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.
14 |
15 | > [!NOTE]
16 | > 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`.
17 |
18 | ## Flask routes
19 |
20 | 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.
21 |
22 | ## Code completion
23 |
24 | 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.
25 |
26 | 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.
27 |
28 | ## Create the breeds endpoint
29 |
30 | Let's build our new route in our Flask backend with the help of code completion.
31 |
32 | > [!IMPORTANT]
33 | > 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.
34 |
35 | 1. Return to your IDE with the project open.
36 | 2. Open **server/app.py**.
37 | 3. Locate the comment which reads `## HERE`, which should be at line 68.
38 | 4. Delete the comment to ensure there isn't any confusion for Copilot, and leave your cursor there.
39 | 5. Begin adding the code to create the route to return all breeds from an endpoint of **api/breeds** by typing the following:
40 |
41 | ```python
42 | @app.route('/api/breeds', methods=['GET'])
43 | ```
44 |
45 | 6. Once you see the full function signature, select Tab to accept the code suggestion.
46 | 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.
47 |
48 | The code generated should look a little like this:
49 |
50 | ```python
51 | @app.route('/api/breeds', methods=['GET'])
52 | def get_breeds():
53 | # Query all breeds
54 | breeds_query = db.session.query(Breed.id, Breed.name).all()
55 |
56 | # Convert the result to a list of dictionaries
57 | breeds_list = [
58 | {
59 | 'id': breed.id,
60 | 'name': breed.name
61 | }
62 | for breed in breeds_query
63 | ]
64 |
65 | return jsonify(breeds_list)
66 | ```
67 |
68 | > [!IMPORTANT]
69 | > 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!
70 |
71 | 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.
72 |
73 | 9. **Save** the file.
74 |
75 | ## Validate the endpoint
76 |
77 | With the code created and saved, let's quickly validate the endpoint to ensure it works.
78 |
79 | 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!
80 |
81 | ## Summary and next steps
82 |
83 | 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].
84 |
85 | ## Resources
86 |
87 | - [Code suggestions in your IDE with GitHub Copilot][copilot-suggestions]
88 | - [Code completions with GitHub Copilot in VS Code][vscode-copilot]
89 | - [Prompt crafting][prompt-crafting]
90 | - [Inline chat][inline-chat]
91 |
92 |
93 | | [← Workshop setup][walkthrough-previous] | [Next: Helping GitHub Copilot understand context →][walkthrough-next] |
94 | |:-----------------------------------|------------------------------------------:|
95 |
96 | [breeds-endpoint]: http://localhost:5100/api/breeds
97 | [client-code]: /client/
98 | [copilot-suggestions]: https://docs.github.com/en/copilot/using-github-copilot/getting-code-suggestions-in-your-ide-with-github-copilot
99 | [flask-routing]: https://flask.palletsprojects.com/en/stable/quickstart/#routing
100 | [http-methods]: https://www.w3schools.com/tags/ref_httpmethods.asp
101 | [prompt-crafting]: https://code.visualstudio.com/docs/copilot/prompt-crafting
102 | [inline-chat]: https://code.visualstudio.com/docs/copilot/chat/inline-chat
103 | [server-code]: /server/
104 | [vscode-copilot]: https://code.visualstudio.com/docs/copilot/ai-powered-suggestions
105 | [walkthrough-previous]: ./0-setup.md
106 | [walkthrough-next]: ./2-explore-project.md
--------------------------------------------------------------------------------
/content/1-hour/2-explore-project.md:
--------------------------------------------------------------------------------
1 | # Helping GitHub Copilot understand context
2 |
3 | | [← Coding with GitHub Copilot][walkthrough-previous] | [Next: Providing custom instructions →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | 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.
7 |
8 | ## Scenario
9 |
10 | Before adding new functionality to the website, you want to explore the existing structure to determine where the updates need to be made.
11 |
12 | ## Chat participants and extensions
13 |
14 | 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`.
15 |
16 | `@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.
17 |
18 | > [!NOTE]
19 | > 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.
20 |
21 | 1. Return to your IDE with the project open.
22 | 2. Close any tabs you may have open in your IDE to ensure the context for Copilot chat is empty.
23 | 3. Open GitHub Copilot Chat.
24 | 4. Select the `+` icon towards the top of Copilot chat to begin a new chat.
25 | 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.
26 | 6. Spend a few minutes exploring to find the answers to the following questions:
27 | - Where's the database the project uses?
28 | - What files are involved in listing dogs?
29 |
30 | ## Summary and next steps
31 |
32 | 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].
33 |
34 | ## Resources
35 |
36 | - [Copilot Chat cookbook][copilot-cookbook]
37 | - [Use Copilot Chat in VS Code][copilot-chat-vscode]
38 | - [Copilot extensions marketplace][copilot-marketplace]
39 |
40 | | [← Coding with GitHub Copilot][walkthrough-previous] | [Next: Providing custom instructions →][walkthrough-next] |
41 | |:-----------------------------------|------------------------------------------:|
42 |
43 | [chat-participants]: https://code.visualstudio.com/docs/copilot/copilot-chat#_chat-participants
44 | [copilot-chat-vscode]: https://code.visualstudio.com/docs/copilot/copilot-chat
45 | [copilot-cookbook]: https://docs.github.com/en/copilot/copilot-chat-cookbook
46 | [copilot-extensions]: https://docs.github.com/en/copilot/using-github-copilot/using-extensions-to-integrate-external-tools-with-copilot-chat
47 | [copilot-marketplace]: https://github.com/marketplace?type=apps&copilot_app=true
48 | [walkthrough-previous]: ./1-add-endpoint.md
49 | [walkthrough-next]: ./3-copilot-instructions.md
--------------------------------------------------------------------------------
/content/1-hour/3-copilot-instructions.md:
--------------------------------------------------------------------------------
1 | # Providing custom instructions
2 |
3 | | [← Coding with GitHub Copilot][walkthrough-previous] | [Next: Add the filter feature →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | 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.
7 |
8 | ## Scenario
9 |
10 | 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.
11 |
12 | ## Overview of Copilot instructions
13 |
14 | 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.
15 |
16 | > [!IMPORTANT]
17 | > 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).
18 |
19 | Here are some guidelines to consider when creating a Copilot instructions file:
20 |
21 | - 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.
22 | - The file is markdown, so you can take advantage of that fact by grouping content together to improve readability.
23 | - Provide overview of **what** you are building and **how** you are building it, including:
24 | - languages, frameworks and libraries in use.
25 | - required assets to be generated (such as unit tests) and where they should be placed.
26 | - any language specific rules such as:
27 | - utilize [type hints][type-hints] in Python.
28 | - use [arrow functions][arrow-functions] rather than the `function` keyword in TypeScript.
29 | - If you notice GitHub Copilot consistently provides an unexpected suggestion (e.g. using class components for React), add those notes to the instructions file.
30 |
31 | ## Create a Copilot instructions file
32 |
33 | 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.
34 |
35 | 1. Return to your IDE with your project open.
36 | 2. Close any tabs you may have open in your IDE to ensure Copilot chat has an empty context.
37 | 3. Select the `+` icon towards the top of Copilot chat to begin a new chat.
38 | 4. Open Copilot Chat and send the following prompt:
39 |
40 | ```
41 | Create a Python function to validate dog age. Ensure age is between 0 and 20. Throw an error if it is outside this range.
42 | ```
43 |
44 | 5. Note the function signature is similar to `def validate_dog_age(age)` without type hints.
45 |
46 | > [!NOTE]
47 | > Because LLMs are probabilistic rather than deterministic, the exact code will vary.
48 |
49 | 6. Create a new file in the **.github** folder called **copilot-instructions.md**.
50 | 7. Add the markdown to the file necessary which provides information about the project structure and requirements:
51 |
52 | ```markdown
53 | # Dog shelter
54 |
55 | 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.
56 |
57 | ## Backend
58 |
59 | - Built using Flask and SQLAlchemy
60 | - Use type hints
61 |
62 | ## Frontend
63 |
64 | - Built using Astro and Svelte
65 | - TypeScript should use arrow functions rather than the function keyword
66 | - Pages should be in dark mode with a modern look and feel
67 | ```
68 |
69 | 8. **Save** the file.
70 |
71 | ## Watch the instructions file in action
72 |
73 | 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.
74 |
75 | 1. Close all files currently open in VS Code or your Codespace. (This will ensure we are working with an empty context.)
76 | 2. Select the `+` icon in GitHub Copilot chat to start a new chat.
77 | 3. Send Copilot chat the same prompt you used previously:
78 |
79 | ```
80 | Create a Python function to validate dog age. Ensure age is between 0 and 20. Throw an error if it is outside this range.
81 | ```
82 |
83 | > [!TIP]
84 | > You can use up arrow to resend previous prompts to Copilot chat.
85 |
86 | 4. Note the references now includes the instructions file and provides information gathered from it.
87 |
88 | 
89 |
90 | 5. Note the resulting Python now utilizes type hints, and the function signature will resemble the following:
91 |
92 | ```python
93 | def validate_dog_age(age: int):
94 | ```
95 |
96 | > [!NOTE]
97 | > The exact code generated will vary, but the new Python suggestion should now utilize type hints.
98 |
99 | ## Summary and next steps
100 |
101 | 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]!
102 |
103 | ## Resources
104 |
105 | - [Adding repository custom instructions for GitHub Copilot][custom-instructions]
106 |
107 |
108 | | [← Coding with GitHub Copilot][walkthrough-previous] | [Next: Add the filter feature →][walkthrough-next] |
109 | |:-----------------------------------|------------------------------------------:|
110 |
111 | [arrow-functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
112 | [custom-instructions]: https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot
113 | [type-hints]: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
114 | [walkthrough-previous]: ./2-explore-project.md
115 | [walkthrough-next]: ./4-add-feature.md
--------------------------------------------------------------------------------
/content/1-hour/4-add-feature.md:
--------------------------------------------------------------------------------
1 | # Add the filter feature
2 |
3 | | [← Providing custom instructions][walkthrough-previous] | [Next: Bonus content →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | 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.
7 |
8 | ## Scenario
9 |
10 | 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.
11 |
12 | ## Copilot Edits
13 |
14 | 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.
15 |
16 | 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.
17 |
18 | ## Add the filters to the dog list page
19 |
20 | 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.
21 |
22 | > [!NOTE]
23 | > 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.
24 |
25 | 1. Return to your IDE with your project open.
26 | 2. Close any tabs you have open inside your IDE.
27 | 3. Enable Auto Save by selecting **File** > **Auto Save**.
28 | 4. Open GitHub Copilot Chat.
29 | 5. Switch to edit mode by selecting **Edit** in the chat mode dropdown at the bottom of Chat view (should be currently **Ask**)
30 | 6. If available, select **Claude 3.5 Sonnet** from the list of available models
31 | 7. Select **Add Context...** in the chat window.
32 | 8. Select **server/app.py** and **client/src/components/DogList.svelte** files (you need to select **Add context** for each file)
33 | > [!TIP]
34 | > 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`)
35 | 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:
36 | - A dropdown list should be provided with all breeds
37 | - A checkbox should be available to only show available dogs
38 | - The page should automatically refresh whenever a change is made
39 |
40 | > [!NOTE]
41 | > 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.
42 |
43 | Copilot begins generating the suggestions!
44 |
45 | ## Reviewing the suggestions
46 |
47 | 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.
48 |
49 | GitHub Copilot will propose the following changes:
50 |
51 | - Update the endpoint to list all dogs to accept parameters for breed and availability.
52 | - Update the webpage to include the dropdown list and checkbox.
53 |
54 | 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).
55 |
56 | If you open an individual file, you can keep or undo changes by using the buttons provided.
57 |
58 | 
59 |
60 | You can also keep or undo all changes made.
61 |
62 | 
63 |
64 | And
65 |
66 | 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.
67 | 2. Open the page at [http://localhost:4321][tailspin-shelter-website] to see the updates!
68 | 3. Run the Python tests by using `python -m unittest` in the terminal as you did previously.
69 | 4. If any changes are needed, explain the required updates to GitHub Copilot and allow it to generate the new code.
70 |
71 | > [!IMPORTANT]
72 | > 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.
73 | >
74 | > 
75 |
76 | 5. Confirm the functionality works as expected, then select **Keep** to accept all the changes.
77 | 6. Optional: Disable Auto Save by unselecting **File** > **Auto Save**.
78 |
79 | ## Summary
80 |
81 | 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.
82 |
83 | ## Workshop review
84 |
85 | 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.
86 |
87 | 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.
88 |
89 | ## Resources
90 |
91 | - [Asking GitHub Copilot questions in your IDE][copilot-ask]
92 | - [Copilot Chat cookbook][copilot-cookbook]
93 | - [Copilot Edits][copilot-edits]
94 |
95 | | [← Providing custom instructions][walkthrough-previous] | [Next: Bonus content →][walkthrough-next] |
96 | |:-----------------------------------|------------------------------------------:|
97 |
98 | [copilot-ask]: https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/asking-github-copilot-questions-in-your-ide
99 | [copilot-cookbook]: https://docs.github.com/en/copilot/copilot-chat-cookbook
100 | [copilot-edits]: https://code.visualstudio.com/docs/copilot/copilot-edits
101 | [tailspin-shelter-website]: http://localhost:4321
102 | [walkthrough-previous]: ./3-copilot-instructions.md
103 | [walkthrough-next]: ./5-bonus.md
104 |
--------------------------------------------------------------------------------
/content/1-hour/5-bonus.md:
--------------------------------------------------------------------------------
1 | # Bonus content
2 |
3 | | [← Add the filter feature][walkthrough-previous] | [Next: Pets workshop selection →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | ## Overview of Copilot Agent Mode
7 |
8 | 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.
9 |
10 | > [!IMPORTANT]
11 | > 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.
12 |
13 | Why would you use agent mode instead of edit mode?
14 |
15 | - **Edit scope**: agent mode autonomously determines the relevant context and files to edit. In edit mode, you need to specify the context yourself.
16 | - **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.
17 | - **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.
18 | - **Self-healing**: agent mode evaluates the outcome of the generated edits and might iterate multiple times to resolve intermediate issues.
19 | - **Request quota**: in agent mode, depending on the complexity of the task, one prompt might result in many requests to the backend.
20 |
21 | ### How it works
22 |
23 | 
24 |
25 | ## Add themes to the Tailspin Shelter website
26 |
27 | 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.
28 |
29 | 1. Return to your IDE with the project open.
30 | 2. Close any tabs you may have open in your IDE to ensure the context for Copilot chat is empty.
31 | 3. Select the `+` icon towards the top of Copilot chat to begin a new chat.
32 | 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.
33 | 5. Select one of models (some may not be available) `Claude 3.7 Sonnet`, `Claude 3.5 Sonnet` or `GPT-4.1 (Preview)`
34 | 6. Navigate to [](../prompts/fun-add-themes.md)
35 | 7. Copy the content of the prompt
36 | 8. Paste the content in the copilot prompt input
37 | 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
38 | 10. While Agent is doing it's thing, take the opportunity to examine the content of prompt that was used.
39 | 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
40 | - Open the page at [http://localhost:4321][tailspin-shelter-website] to see the updates!
41 | - Examine the changes made to the files if you like
42 | - 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.
43 | 12. Press `Done` when you are happy with the results
44 |
45 | You _may_ have gotten something like this for the Terminal Theme (generated with claude 3.7)
46 |
47 | 
48 |
49 | > [!IMPORTANT]
50 | > 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!
51 |
52 | ## Play a bit with Copilot
53 |
54 | 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.
55 |
56 | 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.
57 |
58 | 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!
59 |
60 | ### Some prompts to play with
61 |
62 | We have provided you some prompts in [prompts][github-prompts-path] folder, which you can use directly as inspiration for your explorations.
63 |
64 | > [!TIP]
65 | > 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.
66 | > Learn more about [reusable prompts in Visual Studio Code][vscode-prompts]
67 |
68 | ### Potential next steps
69 |
70 | Here's some ideas of how you could continue to grow and build upon what you've done:
71 |
72 | - Return to the API endpoints you updated previously in Flask and add unit tests.
73 | - Add paging support to the full list of dogs or any results page with more than 5 results.
74 | - Add a form to allow a user to apply to adopt a dog if the dog is available.
75 | - Add a form to allow users to register a dog they found.
76 |
77 | | [← Add the filter feature][walkthrough-previous] | [Next: Pets workshop selection →][walkthrough-next] |
78 | |:-----------------------------------|------------------------------------------:|
79 |
80 | [walkthrough-previous]: ./4-add-feature.md
81 | [walkthrough-next]: ../README.md
82 | [tailspin-shelter-website]: http://localhost:4321
83 | [github-prompts-path]: ../prompts/
84 | [vscode-prompts]: https://aka.ms/vscode-ghcp-prompt-snippets
--------------------------------------------------------------------------------
/content/1-hour/README.md:
--------------------------------------------------------------------------------
1 | # Getting started with GitHub Copilot
2 |
3 | | [← Pets workshop selection][walkthrough-previous] | [Next: Workshop setup →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | 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.
7 |
8 | 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.
9 |
10 | ## Prerequisites
11 |
12 | 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!
13 |
14 | > [!NOTE]
15 | > When in doubt, you can always highlight a block of code you're unfamiliar with and ask GitHub Copilot chat for an explanation!
16 |
17 | ## Required resources
18 |
19 | To complete this workshop, you will need the following:
20 |
21 | - A [GitHub account][github-account].
22 | - Access to [GitHub Copilot][copilot] (which is available for free for individuals!)
23 |
24 | ## Required local installation
25 |
26 | You will also need the following available and installed locally:
27 |
28 | ### Code editor
29 |
30 | - [Visual Studio Code][vscode-link].
31 | - [Copilot extension installed in your IDE][copilot-extension].
32 |
33 | ### Local services
34 |
35 | - A recent [Node.js runtime][nodejs-link].
36 | - A recent version of [Python][python-link].
37 | - For Windows, you can install [Python via the Windows store](https://apps.microsoft.com/detail/9pjpw5ldxlz5?hl=en-US&gl=US).
38 | - The [git CLI][git-link].
39 | - A shell capable of running BASH commands.
40 |
41 | > [!NOTE]
42 | > 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].
43 |
44 | ## Getting started
45 |
46 | 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!
47 |
48 | 0. [Clone the repository and start the app][walkthrough-next] for the workshop.
49 | 1. [Add an endpoint to the server][stage-1] to list all breeds.
50 | 2. [Explore the project][stage-2] to get a better understanding of what needs to be done.
51 | 3. [Create custom instructions][stage-3] to ensure Copilot chat has additional context.
52 | 4. [Add the new feature][stage-4] to the website, and ensure it works!
53 |
54 | ## Check out these resources to dive in and learn more
55 | Check out the resources in [**GitHub-Copilot-Resources.md**][GitHub-Copilot-Resources].
56 |
57 | 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.
58 |
59 | | [← Pets workshop selection][walkthrough-previous] | [Next: Workshop setup →][walkthrough-next] |
60 | |:-----------------------------------|------------------------------------------:|
61 |
62 | [copilot]: https://github.com/features/copilot
63 | [copilot-extension]: https://docs.github.com/en/copilot/managing-copilot/configure-personal-settings/installing-the-github-copilot-extension-in-your-environment
64 | [git-link]: https://git-scm.com/
65 | [github-account]: https://github.com/join
66 | [nodejs-link]: https://nodejs.org/en
67 | [python-link]: https://www.python.org/
68 | [stage-1]: ./1-add-endpoint.md
69 | [stage-2]: ./2-explore-project.md
70 | [stage-3]: ./3-copilot-instructions.md
71 | [stage-4]: ./4-add-feature.md
72 | [walkthrough-previous]: ../README.md
73 | [walkthrough-next]: ./0-setup.md
74 | [windows-python-link]: https://apps.microsoft.com/detail/9pjpw5ldxlz5
75 | [windows-subsystem-linux]: https://learn.microsoft.com/en-us/windows/wsl/about
76 | [vscode-link]: https://code.visualstudio.com/
77 | [GitHub-Copilot-Resources]: ../GitHub-Copilot-Resources.md
78 |
--------------------------------------------------------------------------------
/content/1-hour/images/0-setup-configure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/1-hour/images/0-setup-configure.png
--------------------------------------------------------------------------------
/content/1-hour/images/0-setup-template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/1-hour/images/0-setup-template.png
--------------------------------------------------------------------------------
/content/1-hour/images/copilot-agent-mode-how-it-works.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/1-hour/images/copilot-agent-mode-how-it-works.png
--------------------------------------------------------------------------------
/content/1-hour/images/copilot-chat-references.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/1-hour/images/copilot-chat-references.png
--------------------------------------------------------------------------------
/content/1-hour/images/copilot-edits-history.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/1-hour/images/copilot-edits-history.png
--------------------------------------------------------------------------------
/content/1-hour/images/copilot-edits-keep-undo-file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/1-hour/images/copilot-edits-keep-undo-file.png
--------------------------------------------------------------------------------
/content/1-hour/images/copilot-edits-keep-undo-global.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/1-hour/images/copilot-edits-keep-undo-global.png
--------------------------------------------------------------------------------
/content/1-hour/images/tail-spin-shelter-terminal-theme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/1-hour/images/tail-spin-shelter-terminal-theme.png
--------------------------------------------------------------------------------
/content/GitHub-Copilot-Resources.md:
--------------------------------------------------------------------------------
1 | # GitHub Copilot Resources
2 |
3 | Checkout the resources below to dive in and learn more about [GitHub Copilot](https://gh.io/copilot).
4 |
5 | ## Getting started
6 |
7 | New to GitHub Copilot? Start here!
8 |
9 | - [GitHub Copilot - Your AI pair programmer](https://github.com/features/copilot) - See all that GitHub Copilot can do. This feature summary highlights all that you can do with GitHub Copilot. See a comparison of what is available in each pricing plan.
10 | - [How AI can make you an awesome developer](https://github.com/orgs/community/discussions/153056) - Staying relevant in this era of AI requires not only adapting to new technologies, but also honing in on your skills. It is extremely relevant to address the elephant in the room, how AI is not going to replace us, but make us much better developers. Let’s explore five key strategies to help you stay relevant and thrive in this new era of AI-driven development.
11 | - [Essential GitHub Copilot resources for enterprise teams](https://resources.github.com/enterprise/essential-copilot-resources/) - GitHub Resources - We've gathered everything enterprise teams need to hit the ground running with GitHub Copilot. From initial setup to advanced features, this guide will walk you through the essential resources to make your Copilot implementation successful.
12 |
13 | ## Documentation
14 |
15 | [GitHub Copilot Documentation](https://docs.github.com/en/copilot) contains a robust collection of articles to help you get the most out of the tool. Some key articles to start with include:
16 |
17 | - [Prompt engineering for GitHub Copilot](https://docs.github.com/en/copilot/using-github-copilot/prompt-engineering-for-github-copilot) - A prompt is a request that you make to GitHub Copilot. For example, a question that you ask Copilot Chat, or a code snippet that you ask Copilot to complete. In addition to your prompt, Copilot uses additional context, like the code in your current file and the chat history, to generate a response. Follow the tips in this article to write prompts that generate better responses from Copilot.
18 | - [Asking GitHub Copilot questions in GitHub.com](https://docs.github.com/en/enterprise-cloud@latest/copilot/using-github-copilot/asking-github-copilot-questions-in-githubcom#asking-exploratory-questions-about-a-repository) – See how you can use GitHub Copilot Chat in GitHub.com to answer general questions about software development, or specific questions about the code, issues, security alerts, pull requests, etc. in a repository. For example: open a specific file and ask Copilot, “How could I improve this code?”. Trying to understand a new codebase? Copilot can help with that. You can ask Copilot questions to help quickly understand the structure and key components of repositories. For example, “What does the code in this repo do? What is the tech stack?.
19 | - [Copilot Chat Cookbook](https://docs.github.com/en/copilot/example-prompts-for-github-copilot-chat) - Find examples of prompts to use with GitHub Copilot Chat.
20 | - [Changing the AI model for Copilot Chat](https://docs.github.com/en/enterprise-cloud@latest/copilot/using-github-copilot/ai-models/changing-the-ai-model-for-copilot-chat) & [Changing the AI model for Copilot code completions](https://docs.github.com/en/enterprise-cloud@latest/copilot/using-github-copilot/ai-models/changing-the-ai-model-for-copilot-code-completion) - You are not limited to using the default models for Copilot chat and code completions. You can choose from a selection of other models, each with its own particular strengths. You may have a favorite model that you like to use, or you might prefer to use a particular model for inquiring about a specific subject. Here are some notable recent updates:
21 |
22 | ## Copilot in VS Code
23 |
24 | As you're exploring using VS Code in this workshop, here are some articles particular to using [GitHub Copilot in VS Code](https://code.visualstudio.com/docs/copilot/overview):
25 |
26 | - [Context for Code Completion](https://code.visualstudio.com/docs/copilot/ai-powered-suggestions#_context) - Get more out of GitHub Copilot by understanding how it uses context from multiple locations in VS Code to provide more relevant suggestions.
27 | - [Making Copilot Chat an expert in your workspace](https://code.visualstudio.com/docs/copilot/workspace-context) - Referencing @workspace in Copilot Chat lets you ask questions about your entire codebase. Based on the question, Copilot intelligently retrieves relevant files and symbols, which it then references in its answer as links and code examples. Grounded in @workspace references, Copilot Chat becomes a domain expert for tasks like:
28 | - Finding existing code in your codebase
29 | - Making plans for complex code edits
30 | - Explaining higher-level concepts in a codebase
31 | - [Best Practices / Prompt Crafting](https://code.visualstudio.com/docs/copilot/prompt-crafting) - This article covers best practices for using GitHub Copilot in Visual Studio Code by using prompt crafting and providing the right context to GitHub Copilot.
32 |
33 | ## Videos
34 |
35 | The [GitHub YouTube channel](https://www.youtube.com/@GitHub/videos) hosts many videos highlighting the latest features:
36 |
37 | - [GitHub Copilot Playlist](http://gh.io/GitHub-Copilot-on-YouTube) for **GitHub Copilot** demos and informational videos.
38 | - [GitHub for Beginners](https://www.youtube.com/playlist?list=PL0lo9MOBetEFcp4SCWinBdpml9B2U25-f) - Season 2 of **GitHub for Beginners** is focused on **GitHub Copilot**.
39 |
40 | ## Other resources
41 |
42 | Continue your journey:
43 |
44 | - [Essentials of GitHub Copilot - GitHub Resources](https://resources.github.com/learn/pathways/copilot/essentials/essentials-of-github-copilot/) - In this learning pathway module, we’ll cover the most common questions about GitHub Copilot, and we’ll hear from engineering leaders at the top organizations about how they use GitHub Copilot to accelerate the pace of software development and deliver more value to their customers. This has resources for developers and leaders.
45 | - [GitHub Copilot product updates](https://github.blog/changelog/label/copilot) - We are continually adding capabilities and improving GitHub Copilot. Check out the **GitHub Changelog** to stay up to date on everything we ship.
46 | - [The GitHub Blog](https://github.blog/tag/github-copilot) Be sure to check out the most recent GitHub Copilot related blog posts.
47 | - [GitHub Copilot Discussions](https://github.com/orgs/community/discussions/categories/copilot) - Share your feedback, feature suggestions, etc. via **GitHub public feedback discussions** and influence what we’re building.
48 |
--------------------------------------------------------------------------------
/content/README.md:
--------------------------------------------------------------------------------
1 | # Pets workshop
2 |
3 | This repository contains two workshops:
4 |
5 | - a [one hour](./1-hour/README.md) workshop focused on GitHub Copilot.
6 | - a [full-day](./full-day/README.md) workshop which covers a full day-in-the-life of a developer using GitHub for their DevOps processes.
7 |
8 | Both workshops are built around a fictional dog shelter, where you are a volunteer helping them build out their website.
9 |
10 | ## Get started
11 |
12 | To get started, you choose the option above based on the event you're attending, or as indicated by your workshop mentor.
13 |
--------------------------------------------------------------------------------
/content/full-day/0-setup.md:
--------------------------------------------------------------------------------
1 | # Workshop setup
2 |
3 | | [← Modern DevOps with GitHub][walkthrough-previous] | [Next: Enable Code Scanning →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | 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.
7 |
8 | The repository for this workshop is configured as a template, so we can use it to create your repository.
9 |
10 | ## Create your repository
11 | Let's create the repository you'll use for your workshop.
12 |
13 | 1. Navigate to [the repository root][repo-root]
14 | 2. Select **Use this template** > **Create a new repository**
15 | 
16 | 3. Under **Owner**, select the name of your GitHub handle, or the owner specified by your workshop leader.
17 | 4. Under **Repository**, set the name to **pets-workshop**, or the name specified by your workshop leader.
18 | 5. Ensure **Public** is selected for the visibility, or the value indicated by your workshop leader.
19 | 6. Select **Create repository from template**.
20 | 
21 |
22 | In a few moments a new repository will be created from the template for this workshop!
23 |
24 | ## Summary and next steps
25 | You've now created the repository you'll use for this workshop! Next let's [enable Code Scanning][walkthrough-next] to secure the code we write.
26 |
27 | | [← Modern DevOps with GitHub][walkthrough-previous] | [Next: Enable Code Scanning →][walkthrough-next] |
28 | |:-----------------------------------|------------------------------------------:|
29 |
30 | [fork-repo]: https://docs.github.com/en/get-started/quickstart/fork-a-repo
31 | [template-repo]: https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository
32 | [repo-root]: /
33 | [walkthrough-previous]: README.md
34 | [walkthrough-next]: 1-code-scanning.md
35 |
--------------------------------------------------------------------------------
/content/full-day/1-code-scanning.md:
--------------------------------------------------------------------------------
1 | # Securing the development pipeline
2 |
3 | | [← Workshop setup][walkthrough-previous] | [Next: Project management with GitHub Issues →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | Ensuring code security is imperative in today's environment. When we think about how we create code today, there's three main areas to focus on:
7 |
8 | - The code we write
9 | - The code we use through libraries and packages
10 | - The credentials needed to access services
11 |
12 | To help support developers and security teams, [GitHub Advanced Security][advanced-security] provides a suite of tools which cover these focus areas. Code Scanning will check the code you write, Dependabot ensures the libraries you use are secure, and Secret Scanning looks for any keys or tokens which are checked into code.
13 |
14 | Let's explore each of these, and enable them on our repository. We'll see them in action when we create a pull request with new code later in the workshop.
15 |
16 | ## Scenario
17 |
18 | Security is important in every application. By detecting potential vulnerabilities early, teams are able to make updates before infiltrations occur. To help secure the website, the shelter wants to update the repository to ensure insecure code and libraries are detected as early as possible. You'll enable Dependabot, secret scanning, and code scanning to meet these needs.
19 |
20 | ## Dependabot
21 |
22 | Most projects take dependencies on open source and other external libraries. While modern development would seemingly be impossible without these resources, we always need to ensure the dependencies we take are secure. [Dependabot][dependabot-quickstart] will look at the dependencies your repository has and raise alerts or even create [pull requests][about-prs] (PRs) to update your dependencies to a secure version.
23 |
24 | ### Configuring Dependabot
25 |
26 | Public repositories on GitHub automatically have Dependabot alerts. This feature will generate alerts whenever an insecure package is detected, and generate an alert. Let's configure Dependabot to create PRs to update a library's version when an insecure one is detected.
27 |
28 | 1. Navigate to the repository you created for this workshop.
29 | 1. Select the **Settings** tab.
30 | 2. On the left side, select **Code security**.
31 | 3. Locate the **Dependabot** section towards the middle of the page:
32 |
33 | 
34 |
35 | 4. Select **Enable** next to **Dependabot security updates** to configure Dependabot to create PRs to resolve alerts.
36 |
37 | You have now enabled Dependabot alerts and security updates! Should an insecure library be detected, you will both receive an alert, and Dependabot will create a new pull request to update the version number to a secure version of the library.
38 |
39 | > [!IMPORTANT]
40 | > After enabling Dependabot security updates you may notice new [pull requests][about-prs] created for potentially outdated packages. For this workshop you can ignore these pull requests.
41 |
42 | ## Secret scanning
43 |
44 | Many developers have checked in code with a token or username and passwords. Sometimes this is because the developer was trying to take a shortcut, sometimes it was because they didn't know the proper mechanism to secure the key, and sometimes it was done under the assumption they'll clean it up later but never do.
45 |
46 | Regardless of the reason, even seemingly innocuous tokens can create a security issue. We always want to take care to not publish tokens and keys, and detect any issues as quickly as possible. Secret scanning is built to do exactly this. When a token is detected in your source code, an alert will be raised. You can even enable push protection, ensuring any code with a [supported secret][supported-secrets] can't be pushed to your repository.
47 |
48 | ### Enabling secret scanning
49 |
50 | Let's enable Secret scanning to detect any potential keys.
51 |
52 | 1. On the same page (**Settings** > **Code security and analysis**), towards the very bottom, locate the **Secret scanning** section.
53 | 1. Next to **Receive alerts on GitHub for detected secrets, keys or other tokens**, select **Enable**.
54 | 1. Next to **Push protection**, select **Enable** to block pushes to the repository which contain a [supported secret][supported-secrets].
55 |
56 | 
57 |
58 | You've now enabled secret scanning and push protection. This helps you both block keys from being pushed to your repository and quickly detect when a key has been added to your source code.
59 |
60 | ## Code scanning
61 |
62 | There is a direct relationship between the amount of code an organization creates and potential attack vectors. We always want to check our source code for vulnerabilities. [Code scanning][about-code-scanning] checks your source code for known vulnerabilities. When an issue is detected on a pull request, a new comment is added highlighting the line of source code providing contextual information for the developer. This allows for the issue to be quickly resolved.
63 |
64 | > [!NOTE]
65 | > Code scanning is built atop [GitHub Actions][github-actions], the automation platform for GitHub. We'll explore the specifics of GitHub Actions later in this workshop and create our own workflows.
66 |
67 | ### Enabling code scanning
68 |
69 | Let's enable Code scanning to detect vulnerabilities in our source code. We're going to use the default implementation, which runs whenever code is pushed to `main` or a [pull request][about-prs] is made to `main`. It will also run on a set schedule to ensure any newly discovered potential vulnerabilities are detected.
70 |
71 | 1. On the same page (**Settings** > **Code security and analysis**), towards the very bottom, locate the **Code scanning** section.
72 | 1. Next to **CodeQL analysis**, select **Set up** > **Default**.
73 |
74 | 
75 |
76 | 1. On the **CodeQL default configuration** dialog, select **Enable CodeQL**.
77 |
78 | 
79 |
80 | > [!IMPORTANT]
81 | > Your list of languages may be different
82 |
83 | A background process starts, and will configure a workflow for analyzing your code using [CodeQL and code scanning][about-code-scanning].
84 |
85 | ## Summary and next steps
86 |
87 | In this exercise, you enabled GitHub Advanced Security. You enabled Dependabot to check the libraries your project takes dependencies on, secret scanning to look for keys and tokens, and code scanning to examine your source code. These tools help ensure your application is secure. Next it's time to [file an issue][walkthrough-next] to add feature requests.
88 |
89 | ### Additional resources
90 |
91 | - [About GitHub Advanced Security][advanced-security-docs]
92 | - [GitHub Skills: Secure your repository's supply chain][skills-supply-chain]
93 | - [GitHub Skills: Secure code game][skills-secure-code]
94 |
95 | | [← Workshop setup][walkthrough-previous] | [Next: Project management with GitHub Issues →][walkthrough-next] |
96 | |:-----------------------------------|------------------------------------------:|
97 |
98 | [advanced-security]: https://github.com/features/security
99 | [advanced-security-docs]: https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security
100 | [about-code-scanning]: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning
101 | [about-prs]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests
102 | [dependabot-quickstart]: https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide
103 | [github-actions]: https://github.com/features/actions
104 | [supported-secrets]: https://docs.github.com/en/code-security/secret-scanning/secret-scanning-patterns#supported-secrets
105 | [skills-supply-chain]: https://github.com/skills/secure-repository-supply-chain
106 | [skills-secure-code]: https://github.com/skills/secure-code-game
107 | [walkthrough-previous]: 0-setup.md
108 | [walkthrough-next]: 2-issues.md
109 |
--------------------------------------------------------------------------------
/content/full-day/2-issues.md:
--------------------------------------------------------------------------------
1 | # Project management with GitHub Issues
2 |
3 | | [← Securing the development pipeline][walkthrough-previous] | [Next: Cloud-based development with GitHub Codespaces →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | "URL or it didn't happen" is a common mantra at GitHub, which is used to highlight the importance of documenting the development process. Feature requests should have a history; who made the request, what was the rationale, who was involved in the process, what decisions were made, why were they made, was the feature implemented, how was it implemented... All of this information helps provide context to both drive future decisions and avoid repeating old mistakes.
7 |
8 | GitHub provides various features to enable collaboration and project management, including [GitHub Discussions][discussions], [wikis][wikis], [pull requests][about-prs] and [GitHub Issues][issues]. Each of these can help your organization drive the creation process. We're going to focus on GitHub Issues, which is the foundation of project management on GitHub.
9 |
10 | At their core, issues document some form of an action. They can be a request for a feature, a bug report, or another operation taken by the team. There's no prescribed methodology for using GitHub Issues, allowing your team to determine the best way to manage and drive your projects. A common flow teams will implement on issues is:
11 |
12 | 1. File an issue to request a new feature or file a bug report.
13 | 1. Discuss the issue, and determine the correct people and mechanism to resolve the request.
14 | 1. Create a pull request with a proposed implementation of the request.
15 | 1. Further discuss and review the pull request.
16 | 1. Once everyone is satisfied and has signed off, merge the pull request and close the issue.
17 |
18 | ## Scenario
19 |
20 | The shelter wants to begin pushing new features to the website. They want to start by displaying the hours for the current day on the landing page. There's also a need to make updates to help support development and DevOps for both current and future updates. You want to track these updates to document the work being done. You'll do this by creating issues in the repository.
21 |
22 | ## Creating issues to manage feature requests
23 |
24 | Our project needs two main updates. We want to make the updates to support development for our project, and add a new component to the website to display the shelter's hours. Let's create the issues for each of these. In the next few exercises we'll begin making the appropriate updates to our project to resolve these requests.
25 |
26 | 1. Return to the repository you created at the beginning of this workshop.
27 | 1. Select the **Issues** tab.
28 | 1. Select **New issue**.
29 | 2. If prompted for type, select **Blank issue**.
30 | 3. Select **Create more** at the bottom of the page to streamline the creation process.
31 | 4. Create new issues by adding the information indicated in the table below, selecting **Submit new issue** after creating each one:
32 |
33 | | Title | Description |
34 | | ----------------------- | ------------------------------------------------------------------------------ |
35 | | Define codespace | Create the necessary definitions for the codespace to enable cloud development |
36 | | Implement testing | Create a workflow to automate testing for continuous integration |
37 | | Add filters to dog list | Add the code to allow users to filter for dogs by breed and availability |
38 |
39 | > [!TIP]
40 | > You can also save an issue by pressing Ctl - Enter (or Cmd - Return on a Mac) in the title or description fields.
41 |
42 | You've now defined all the issues for the workshop! You'll use these issues to help guide your progress through the workshop.
43 |
44 | ## Summary and next steps
45 | 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].
46 |
47 | ## Resources
48 | - [GitHub Issues][issues-docs]
49 | - [Communicate using markdown][skills-markdown]
50 | - [GitHub Projects][projects-docs]
51 |
52 | | [← Securing the development pipeline][walkthrough-previous] | [Next: Cloud-based development with GitHub Codespaces →][walkthrough-next] |
53 | |:-----------------------------------|------------------------------------------:|
54 |
55 | [discussions]: https://github.com/features/discussions
56 | [wikis]: https://docs.github.com/en/communities/documenting-your-project-with-wikis/about-wikis
57 | [about-prs]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests
58 | [issues]: https://github.com/features/issues
59 | [issues-docs]: https://docs.github.com/en/issues/tracking-your-work-with-issues/about-issues
60 | [projects-docs]: https://docs.github.com/en/issues/planning-and-tracking-with-projects/learning-about-projects/quickstart-for-projects
61 | [skills-markdown]: https://github.com/skills/communicate-using-markdown
62 | [walkthrough-next]: 3-codespaces.md
63 | [walkthrough-previous]: 1-code-scanning.md
--------------------------------------------------------------------------------
/content/full-day/3-codespaces.md:
--------------------------------------------------------------------------------
1 | # Cloud-based development with GitHub Codespaces
2 |
3 | | [← Project management with GitHub Issues][walkthrough-previous] | [Next: Continuous integration and testing →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | One of the biggest challenges organizations face is onboarding new developers to projects. There are libraries to install, services to configure, version issues, obscure error messages... It can literally take days to get everything running before a developer is able to write their first line of code. [GitHub Codespaces][codespaces] is built to streamline this entire process. You can configure a container for development which your developers can access with just a couple of clicks from basically anywhere in the world. The container runs in the cloud, has everything already setup, and ready to go. Instead of days your developers can start writing code in seconds.
7 |
8 | GitHub Codespaces allows you to develop using the cloud-based container and Visual Studio Code in your browser window, meaning no local installation is required; you can do development with a tablet and a keyboard! You can also connect your local instance of [Visual Studio Code][vscode-codespaces].
9 |
10 | Let's explore how to create and configure a codespaces for your project, and see how you can develop in your browser.
11 |
12 | ## Using the default container
13 |
14 | GitHub provides a [default container][github-universal-container] for all repositories. This container is based on a Linux image, and contains many popular runtimes including Node.js, Python, PHP and .NET. In many scenarios, this default container might be all you need. You also have the ability to configure a custom container for the repository, as you'll see later in this exercise. For now, let's explore how to use the default container.
15 |
16 | 1. If not already open, open your repository in your browser.
17 | 1. From the **Code** tab (suggest to open a new browser tab) in your repo, access the green **<> Code** dropdown button and from the **Codespaces** tab click **Create codespace on main**.
18 | 1. Allow the Codespace to load; it should take less than 30 seconds because we are using the default image.
19 |
20 | ## Defining a custom container
21 |
22 | One thing that's really great is the [default dev container][github-universal-container-definition] has **.NET 7**, **node**, **python**, **mvn**, and more. But what if you need other tools? Or in our case, we want don't want to have each developer install the **[GitHub Copilot Extension][copilot-extension]**; we want to have everything pre-configured from the start!
23 |
24 | Let's create our own dev container! The [dev container is configured][dev-containers-docs] by creating the Docker files Codespaces will use to create and configure the container, and providing any customizations in the `devcontainer.json` file. Customizations provided in `devcontainer.json` can include ports to open, commands to run, and extension to install in Visual Studio Code (either running locally on the desktop or in the browser). This configuration becomes part of the repository. All developers who wish to contribute can then create a new instance of the container based on the configuration you provided.
25 |
26 | 1. Access the Command Palette (F1 or clicking ☰ → View → Command Palette), then start typing **dev container**.
27 | 2. Select **Codespaces: Add Development Container Configuration Files...** .
28 | 3. Select **Create a new configuration...**.
29 | 4. Scroll down and select **Node.js & TypeScript**.
30 | 5. Select **22-bookworm (default)**.
31 | 6. Select the following features to add into your container:
32 | - **Azure CLI**
33 | - **GitHub CLI**
34 | - **Python**
35 |
36 | > [!NOTE]
37 | > You can type the name of the feature you want to filter the list.
38 |
39 | 7. Select **OK** to add the features.
40 | 8. Select **Keep defaults** to use the default configuration.
41 | 9. If you receive the prompt **File './.github/dependabot.yml' already exists, overwrite?**, select **Skip**.
42 |
43 | > [!IMPORTANT]
44 | > Your new container definition files will be created into the **.devcontainer** folder. **DO NOT** select **Rebuild Now**; we'll do that in just a moment.
45 |
46 | You have now defined the container to be used by your codespace. This contains the necessary services and tools for your code.
47 |
48 | ## Customize the extensions
49 |
50 | Creating a development environment isn't solely focused on the services. Developers rely on various extensions and plugins for their [integrated development environments (IDEs)][IDE]. To ensure consistency, you may want to define a set of extensions to automatically install. When using GitHub Codespaces and either a local instance of Visual Studio Code or the browser-based version, you can add a list of [extensions][vscode-extensions] to the **devcontainer.json** file.
51 |
52 | Before rebuilding the container, let's add **GitHub.copilot** to the list of extensions.
53 |
54 | 1. Remaining in the codespace, open **devcontainer.json** inside the **.devcontainer** folder.
55 | 2. Locate the following section:
56 |
57 | ```json
58 | "features": {
59 | "ghcr.io/devcontainers/features/github-cli:1": {},
60 | "ghcr.io/devcontainers/features/python:1": {}
61 | }
62 | ```
63 |
64 | 3. Add a comma (`,`) to the end of the last `}`, which should be line 10.
65 | 4. Immediately below that line, paste the following code to provide the list of extensions you wish to have for your dev container:
66 |
67 | ```json
68 | "customizations": {
69 | "vscode": {
70 | "extensions": [
71 | "GitHub.copilot",
72 | "GitHub.copilot-chat",
73 | "ms-azuretools.vscode-azure-github-copilot",
74 | "alexcvzz.vscode-sqlite",
75 | "astro-build.astro-vscode",
76 | "svelte.svelte-vscode",
77 | "ms-python.python",
78 | "ms-python.vscode-pylance"
79 | ]
80 | }
81 | },
82 | ```
83 |
84 | 5. Just below the customizations, paste the following code to provide the list of ports which should be made available for development by the codespace:
85 |
86 | ```json
87 | "forwardPorts": [
88 | 4321,
89 | 5100,
90 | 5000
91 | ],
92 | ```
93 |
94 | 6. Just below the list of ports, add the command to run the startup script to the container definition:
95 |
96 | ```json
97 | "postStartCommand": "chmod +x /workspaces/dog-shelter/scripts/start-app.sh && /workspaces/dog-shelter/scripts/start-app.sh",
98 | ```
99 |
100 | You've now defined a custom container!
101 |
102 | ## Use the newly defined custom container
103 |
104 | 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!
105 |
106 | 1. Access the Command Palette (F1 or clicking ☰ → View → Command Palette), then start typing **dev container**.
107 | 1. Type **rebuild** and select **Codespaces: Rebuild container**.
108 | 1. Select **Rebuild Container** on the dialog box. Your container now rebuilds.
109 |
110 | > [!IMPORTANT]
111 | > 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.
112 | >
113 | > You may also be prompted to reload the window as extensions install. Reload the window as prompted.
114 |
115 | ## Interacting with the repository
116 |
117 | Custom containers for GitHub Codespaces become part of the source code for the repository. Thus they are maintained through standard source control, and will follow the repository as it's forked in the future. This allows this definition to be shared across all developers contributing to the project. Let's upload our new configuration, closing the [issue you created][walkthrough-previous] for defining a development environment.
118 |
119 | > [!IMPORTANT]
120 | > For purposes of this exercise we are pushing code updates directly to `main`, our default branch. Normally you would follow the [GitHub flow][github-flow], which we will do in a [later exercise][github-flow-exercise].
121 |
122 | 1. Open a new terminal window in the codespace by selecting Ctl + Shift + ` or clicking ☰ → View → Terminal.
123 | 2. Find the issue number for defining the codespace by entering the following command:
124 |
125 | ```bash
126 | gh issue list
127 | ```
128 |
129 | > [!NOTE]
130 | > It will likely be #1. You'll use this number later in this exercise.
131 |
132 | 3. Stage all files, commit the changes with a message to resolve the issue, and push to main by entering the following command in the terminal window, replacing `` with the number you obtained in the previous step:
133 |
134 | ```bash
135 | git add .
136 | git commit -m "Resolves #"
137 | git push
138 | ```
139 | > [!NOTE]
140 | > If prompted, select **Allow** to enable copy/paste for the codespace.
141 |
142 | 4. When the command completes, enter the following to list all open issues:
143 |
144 | ```bash
145 | gh issue list
146 | ```
147 |
148 | 5. Note the issue for defining a codespace is no longer listed; you completed it and marked it as such with your pull request!
149 |
150 |
151 | ## Summary and next steps
152 | 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.
153 |
154 | ## Resources
155 | - [GitHub Codespaces][codespaces]
156 | - [Getting started with GitHub Codespaces][codespaces-docs]
157 | - [Defining dev containers][dev-containers-docs]
158 | - [GitHub Skills: Code with Codespaces][skills-codespaces]
159 |
160 | | [← Project management with GitHub Issues][walkthrough-previous] | [Next: Continuous integration and testing →][walkthrough-next] |
161 | |:-----------------------------------|------------------------------------------:|
162 |
163 | [codespaces]: https://github.com/features/codespaces
164 | [copilot-extension]: https://marketplace.visualstudio.com/items?itemName=GitHub.copilot
165 | [codespaces-docs]: https://docs.github.com/en/codespaces/overview
166 | [codespace-prebuild]: https://docs.github.com/en/codespaces/prebuilding-your-codespaces
167 | [dev-containers-docs]: https://docs.github.com/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers
168 | [github-flow]: https://docs.github.com/en/get-started/quickstart/github-flow
169 | [github-flow-exercise]: ./7-github-flow.md
170 | [github-universal-container]: https://docs.github.com/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers#using-the-default-dev-container-configuration
171 | [github-universal-container-definition]: https://github.com/devcontainers/images/blob/main/src/universal/.devcontainer/Dockerfile
172 | [IDE]: https://en.wikipedia.org/wiki/Integrated_development_environment
173 | [skills-codespaces]: https://github.com/skills/code-with-codespaces
174 | [vscode-codespaces]: https://docs.github.com/en/codespaces/developing-in-codespaces/using-github-codespaces-in-visual-studio-code
175 | [vscode-extensions]: https://code.visualstudio.com/docs/editor/extension-marketplace
176 | [walkthrough-previous]: 2-issues.md
177 | [walkthrough-next]: 4-testing.md
178 |
--------------------------------------------------------------------------------
/content/full-day/4-testing.md:
--------------------------------------------------------------------------------
1 | # Continuous integration and testing
2 |
3 | | [← Cloud-based development with GitHub Codespaces][walkthrough-previous] | [Next: Helping GitHub Copilot understand context →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | Chances are you've heard the abbreviation CI/CD, which stands for continuous integration and continuous delivery (or sometimes continuous deployment). CI is centered on incorporating new code into the existing codebase, and typically includes running tests and performing builds. CD focuses on the next logical step, taking the now validated code and generating the necessary outputs to be pushed to the cloud or other destinations. This is probably the most focused upon component of DevOps.
7 |
8 | CI/CD fosters a culture of rapid development, collaboration, and continuous improvement, allowing organizations to deliver software updates and new features more reliably and quickly. It ensures consistency, and allows developers to focus on writing code rather than performing manual processes.
9 |
10 | [GitHub Actions][github-actions] is an automation platform upon which you can build your CI/CD process. It can also be used to automate other tasks, such as resizing images and validating machine learning models.
11 |
12 | ## Scenario
13 |
14 | A set of unit tests exist for the Python server for the project. You want to ensure those tests are run whenever someone makes a [pull request][about-prs] (PR). To meet this requirement, you'll need to define a workflow for the project, and ensure there is a [trigger][workflow-triggers] for pull requests to main. Fortunately, [GitHub Copilot][copilot] can aid you in creating the necessary YML file!
15 |
16 | ## Exploring the test
17 |
18 | Let's take a look at the tests defined for the project.
19 |
20 | > [!NOTE]
21 | > There are only a few tests defined for this project. Many projects will have hundreds or thousands of tests to ensure reliability.
22 |
23 | 1. Return to your codespace, or reopen it by navigating to your repository and selecting **Code** > **Codespaces** and the name of your codespace.
24 | 2. In **Explorer**, navigate to **server** and open **test_app.py**.
25 | 3. Open GitHub Copilot Chat and ask for an explanation of the file.
26 |
27 | > [!NOTE]
28 | > Consider using the following GitHub Copilot tips to gain an understanding of the tests:
29 | >
30 | > - `/explain` is a [slash command][copilot-slash-commands] to quickly ask for an explanation
31 | > - Highlight specific sections of the file to focus on areas you may have questions about
32 |
33 | ## Understanding workflows
34 |
35 | To ensure the tests run whenever a PR is made you'll define a workflow for the project. Workflows can perform numerous tasks, such as checking for security vulnerabilities, deploying projects, or (in our case) running unit tests. They're central to any CI/CD.
36 |
37 | Creating a YML file can be a little tricky. Fortunately, GitHub Copilot can help streamline the process! Before we work with Copilot to create the file, let's explore some core sections of a workflow:
38 |
39 | - `name`: Provides a name for the workflow, which will display in the logs.
40 | - `on`: Defines what will cause the workflow to run. Some common triggers include `pull_request` (when a PR is made), `merge` (when code is merged into a branch), and `workflow_dispatch` (manual run).
41 | - `jobs`: Defines a series of jobs for this workflow. Each job is considered a unit of work and has a name.
42 | - **name**: Name and container for the job.
43 | - `runs-on`: Where the operations for the job will be performed.
44 | - `steps`: The operations to be performed.
45 |
46 | ## Create the workflow file
47 |
48 | Now that we have an overview of the structure of a workflow, let's ask Copilot to generate it for us!
49 |
50 | 1. Create a new folder under **.github** named **workflows**.
51 | 2. Create a new file named **server-test.yml** and ensure the file is open.
52 | 3. If prompted to install the **GitHub Actions** extension, select **Install**.
53 | 4. Open GitHub Copilot Chat.
54 | 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.
55 | 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.
56 |
57 | > [!IMPORTANT]
58 | > A prescriptive prompt isn't provided as part of the exercise is to become comfortable interacting with GitHub Copilot.
59 |
60 | 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:
61 |
62 | ```yml
63 | name: Server Tests
64 |
65 | on:
66 | push:
67 | branches: [ main ]
68 | paths:
69 | - 'server/**'
70 | pull_request:
71 | branches: [ main ]
72 | paths:
73 | - 'server/**'
74 |
75 | jobs:
76 | server-test:
77 | runs-on: ubuntu-latest
78 |
79 | steps:
80 | - uses: actions/checkout@v3
81 |
82 | - name: Set up Python
83 | uses: actions/setup-python@v4
84 | with:
85 | python-version: '3.10'
86 |
87 | - name: Install dependencies
88 | run: |
89 | python -m pip install --upgrade pip
90 | if [ -f server/requirements.txt ]; then pip install -r server/requirements.txt; fi
91 | pip install pytest
92 |
93 | - name: Run tests
94 | working-directory: ./server
95 | run: |
96 | python -m pytest test_app.py -v
97 | ```
98 |
99 | > [!IMPORTANT]
100 | > Note, the file generated may differ from the example above. Because GitHub Copilot uses generative AI, there results will be probabilistic rather than deterministic.
101 |
102 | > [!TIP]
103 | > If you want to learn more about the workflow you just created, ask GitHub Copilot!
104 |
105 | ## Push the workflow to the repository
106 |
107 | With the workflow created, let's push it to the repository. Typically you would create a PR for any new code (which this is). To streamline the process, we're going to push straight to main as we'll be exploring pull requests and the [GitHub flow][github-flow] in a [later exercise][github-flow-exercise]. You'll start by obtaining the number of the [issue you created earlier][issues-exercise], creating a commit for the new code, then pushing it to main.
108 |
109 | > [!NOTE]
110 | > All commands are entered using the terminal window in the codespace.
111 |
112 | 1. Use the open terminal window in your codespace, or open it (if necessary) by pressing Ctl + `.
113 | 1. List all issues for the repository by entering the following command in the terminal window:
114 |
115 | ```bash
116 | gh issue list
117 | ```
118 |
119 | 1. Note the issue number for the one titled **Implement testing**.
120 | 1. Stage all files by entering the following command in the terminal window:
121 |
122 | ```bash
123 | git add .
124 | ```
125 |
126 | 1. Commit all changes with a message by entering the following command in the terminal window, replacing **** with the number for the **Implement testing** issue:
127 |
128 | ```bash
129 | git commit -m "Resolves #"
130 | ```
131 |
132 | 1. Push all changes to the repository by entering the following command in the terminal window:
133 |
134 | ```bash
135 | git push
136 | ```
137 |
138 | Congratulations! You've now implemented testing, a core component of continuous integration (CI)!
139 |
140 | ## Seeing the workflow in action
141 |
142 | Pushing the workflow definition to the repository counts as a push to `main`, meaning the workflow will be triggered. You can see the workflow in action by navigating to the **Actions** tab in your repository.
143 |
144 | 1. Return to your repository.
145 | 2. Select the **Actions** tab.
146 | 3. Select **Server test** on the left side.
147 | 4. Select the workflow run on the right side with a message of **Resolves #**, matching the commit message you used.
148 | 5. Explore the workflow run by selecting the job name
149 |
150 | You've now seen a workflow, and explore the details of a run!
151 |
152 | ## Summary and next steps
153 |
154 | 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].
155 |
156 | ### Resources
157 | - [GitHub Actions][github-actions]
158 | - [GitHub Actions Marketplace][actions-marketplace]
159 | - [About continuous integration][about-ci]
160 | - [GitHub Skills: Test with Actions][skills-test-actions]
161 |
162 | | [← Cloud-based development with GitHub Codespaces][walkthrough-previous] | [Next: Helping GitHub Copilot understand context →][walkthrough-next] |
163 | |:-----------------------------------|------------------------------------------:|
164 |
165 | [about-ci]: https://docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration
166 | [about-prs]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests
167 | [actions-marketplace]: https://github.com/marketplace?type=actions
168 | [workflow-triggers]: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows
169 | [copilot]: https://gh.io/copilot
170 | [copilot-slash-commands]: https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/github-copilot-chat-cheat-sheet
171 | [github-actions]: https://github.com/features/actions
172 | [github-flow]: https://docs.github.com/en/get-started/quickstart/github-flow
173 | [github-flow-exercise]: ./7-github-flow.md
174 | [issues-exercise]: ./2-issues.md
175 | [skills-test-actions]: https://github.com/skills/test-with-actions
176 | [walkthrough-previous]: 3-codespaces.md
177 | [walkthrough-next]: 5-context.md
178 |
--------------------------------------------------------------------------------
/content/full-day/5-context.md:
--------------------------------------------------------------------------------
1 | # Helping GitHub Copilot understand context
2 |
3 | | [← Implement testing][walkthrough-previous] | [Next: Coding with GitHub Copilot →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | 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.
7 |
8 | ## Scenario
9 |
10 | Before adding new functionality to the website, you want to explore the existing structure to determine where the updates need to be made. You also want to provide Copilot some context in the form of [custom instructions][copilot-custom-instructions] so it has a better idea of how best to generate code.
11 |
12 | ## Getting started with GitHub Copilot
13 |
14 | GitHub Copilot is a cloud-based service offered for both individuals and businesses. As an individual, you can [sign up for a free account][copilot-signup] of the service. After enrolling you will typically install the extension for your IDE, which is available for [Visual Studio][copilot-vs], [Visual Studio Code][copilot-vscode], [NeoVIM][copilot-vim], the [JetBrains IDEs][copilot-jetbrains], [XCode](copilot-xcode) and [Eclipse][copilot-eclipse]. Because we'll be using the [Codespace][walkthrough-codespaces] you defined in the previous exercise, you won't need to manually install the extension - you did that when you configured the dev container!
15 |
16 | 1. If you don't already have access to GitHub Copilot, [sign up for a free trial][copilot-signup].
17 | 2. In the [previous exercise][walkthrough-codespaces] you configured your [devcontainer][devcontainer-docs] to automatically install the extension for GitHub Copilot, so you're all set and ready to go!
18 |
19 | ## Chat participants and extensions
20 |
21 | GitHub Copilot Chat has a set of available chat participants and 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`.
22 |
23 | `@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.
24 |
25 | > [!NOTE]
26 | > 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.
27 |
28 | 1. Return to your codespace, or reopen it by navigating to your repository and selecting **Code** > **Codespaces** and the name of your codespace.
29 | 2. Open GitHub Copilot Chat.
30 | 3. Select the `+` icon towards the top to begin a new chat.
31 | 4. 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.
32 | 5. Spend a few minutes exploring to find the answers to the following questions:
33 | - What frameworks are currently in use?
34 | - Where's the database the project uses?
35 | - How is the frontend built?
36 | - How is the backend built?
37 | - What files are involved in listing dogs?
38 |
39 | ## Providing custom instructions
40 |
41 | Context is key to ensuring the code suggestions you receive from GitHub Copilot align with your expectations. When operating with limited information, Copilot makes assumptions about what you're looking for, and can sometimes guess incorrectly. By providing context, you allow Copilot to better align with your objectives. One great way to do this is by building a [copilot-instructions.md][copilot-custom-instructions] file. This markdown file is placed in your **.github** folder and becomes part of your project. 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.
42 |
43 | > [!IMPORTANT]
44 | > 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 set of Copilot instructions 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][copilot-prompt-files] as needed.
45 |
46 | Here are some guidelines to consider when creating a Copilot instructions file:
47 |
48 | - 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.
49 | - The file is markdown, so you can take advantage of that fact by grouping content together to improve readability.
50 | - Provide overview of **what** you are building and **how** you are building it, including:
51 | - languages, frameworks and libraries in use.
52 | - required assets to be generated (such as unit tests) and where they should be placed.
53 | - any language specific rules such as:
54 | - Python code should always follow PEP8 rules.
55 | - use arrow functions rather than the `function` keyword.
56 | - If you notice GitHub Copilot consistently provides an unexpected suggestion (e.g. using class components for React), add those notes to the instructions file.
57 |
58 | Let's create a Copilot instructions file. Just as before, because we want you to explore and experiment, we won't provide exact directions on what to type, but will give enough context to create one on your own.
59 |
60 | 1. Create a new file in the **.github** folder called **copilot-instructions.md**.
61 | 2. Add the markdown to the file necessary to provide information about the project structure and requirements, including:
62 | - an overview of the project itself (based on the information you gathered earlier in this exercise).
63 | - the languages and frameworks in use to create both the server and client.
64 | - unit tests are required for routes in the Flask app, and must mock the database calls.
65 | - the website should be in dark mode and have a modern look and feel.
66 | 3. Save the file!
67 |
68 | Your Copilot instructions file could resemble the following (but again - use your own words and style!):
69 |
70 | ```markdown
71 | # Dog shelter
72 |
73 | 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.
74 |
75 | ## Backend
76 |
77 | - Built using Flask and SQLAlchemy
78 | - All routes require unit tests, which are created in *test_file.py* in the same folder as the file
79 | - When creating tests, always mock database calls
80 |
81 | ## Frontend
82 |
83 | - Built using Astro and Svelte
84 | - Pages should be in dark mode with a modern look and feel
85 | ```
86 |
87 | ## Watch the instructions file in action
88 |
89 | Whenever you make a call to Copilot chat, the response will always include the context being used. The context can automatically include the open file (focused on any code you highlight), and individual files or folders you add by using `#file` or `#folder`. You can also include the an index of your workspace by using `@workspace`, as highlighted earlier. The references dialog is a great way to check what information Copilot was using when generating its suggestions and response. Once you create a Copilot instructions file, you will see it's always included in the references section.
90 |
91 | 1. Close all files currently open in VS Code or your Codespace.
92 | 2. Select the `+` icon in GitHub Copilot chat to start a new chat.
93 | 3. Ask Copilot chat **What are the guidelines for the flask app?**
94 | 4. Note the references now includes the instructions file and provides information gathered from it.
95 |
96 | 
97 |
98 | ## Summary and next steps
99 |
100 | Congratulations! 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 create a Copilot instructions file to provide an overview of what you're building and how you're building it. With this in place, it's time to turn our attention to [adding new functionality to our website][walkthrough-next]!
101 |
102 | ## Resources
103 |
104 | - [Getting started with GitHub Copilot][copilot-getting-started]
105 | - [Adding repository custom instructions for GitHub Copilot][copilot-custom-instructions]
106 | - [Adding personal custom instructions for GitHub Copilot][copilot-personal-instructions]
107 | - [Copilot Chat cookbook][copilot-chat-cookbook]
108 | - [Use Copilot Chat in VS Code][vscode-copilot-chat]
109 |
110 | | [← Implement testing][walkthrough-previous] | [Next: Coding with GitHub Copilot →][walkthrough-next] |
111 | |:-----------------------------------|------------------------------------------:|
112 |
113 | [copilot-chat-cookbook]: https://docs.github.com/en/copilot/copilot-chat-cookbook
114 | [copilot-custom-instructions]: https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot
115 | [copilot-eclipse]: https://marketplace.eclipse.org/content/github-copilot
116 | [copilot-getting-started]: https://docs.github.com/en/copilot/getting-started-with-github-copilot
117 | [copilot-jetbrains]: https://plugins.jetbrains.com/plugin/17718-github-copilot
118 | [copilot-prompt-files]: https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot?tool=vscode#about-prompt-files
119 | [copilot-personal-instructions]: https://docs.github.com/en/copilot/customizing-copilot/adding-personal-custom-instructions-for-github-copilot
120 | [copilot-signup]: https://github.com/github-copilot/signup
121 | [copilot-vim]: https://github.com/github/copilot.vim#getting-startedins.com/plugin/17718-github-copilot
122 | [copilot-vs]: https://marketplace.visualstudio.com/items?itemName=GitHub.copilotvs
123 | [copilot-vscode]: https://marketplace.visualstudio.com/items?itemName=GitHub.copilot
124 | [copilot-xcode]: https://github.com/github/CopilotForXcode
125 | [devcontainer-docs]: https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containersopilot/adding-personal-custom-instructions-for-github-copilot
126 | [vscode-copilot-chat]: https://code.visualstudio.com/docs/copilot/copilot-chat
127 | [walkthrough-codespaces]: ./3-codespaces.mdvisualstudio.com/docs/copilot/copilot-chat
128 | [walkthrough-next]: 6-code.md
129 | [walkthrough-previous]: 4-testing.md
130 |
131 |
--------------------------------------------------------------------------------
/content/full-day/6-code.md:
--------------------------------------------------------------------------------
1 | # Coding with GitHub Copilot
2 |
3 | | [← Helping GitHub Copilot understand context][walkthrough-previous] | [Next: GitHub flow →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | 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 and generate the necessary unit tests.
7 |
8 | ## Scenario
9 |
10 | 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.
11 |
12 | ## Overview of this exercise
13 |
14 | In the next handful of steps, you will:
15 |
16 | - create a new Flask endpoint to list the breeds available.
17 | - add the associated unit test.
18 | - update the backend and frontend to display the list and add the filters as required in the scenario.
19 |
20 | ## GitHub Copilot interfaces
21 |
22 | Until now, we've primarily focused on GitHub Copilot chat. This will likely be the most common way you'll interact with GitHub Copilot. It allows you to interactively ask questions, and has an ability to perform operations across an individual and (with Copilot Edits) multiple files. You can also get support from GitHub Copilot with code completion, which provides suggestions as you code. We're going to explore each of these three capabilities.
23 |
24 | ## Create a new Flask route with Code completion
25 |
26 | 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.
27 |
28 | > [!IMPORTANT]
29 | > At this time, the Copilot instructions file is only available to Copilot chat.
30 |
31 | 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.
32 |
33 | > [!NOTE]
34 | > One great way to provide context for GitHub Copilot is to add comments to your code. While comments describing what is done can sometimes be superfluous, it helps Copilot get a better idea of what you're building.
35 |
36 | Let's build our new route in our Flask backend with the help of code completion.
37 |
38 | 1. Return to your codespace, or reopen it by navigating to your repository and selecting **Code** > **Codespaces** and the name of your codespace.
39 | 2. Open **server/app.py**.
40 | 3. Locate the section of code at the very bottom which launches the server, and put your cursor just above it. This should be line 70, and the code will be:
41 |
42 | ```python
43 | if __name__ == '__main__':
44 | app.run(debug=True, port=5100) # Port 5100 to avoid macOS conflicts
45 | ```
46 |
47 | 4. Create the route which will call the database to find all breeds, and returns a JSON array with their names and IDs. If you begin typing `@app.route` or add a comment with the requirements like `# Route to get all breeds`, you should notice italicized text generated by GitHub Copilot.
48 | 5. Select Tab to accept the code suggestion.
49 | 6. Navigate to [http://localhost:5100/api/breeds][localhost-breeds] to validate the route.
50 |
51 | > [!NOTE]
52 | > As with the prior exercise, we don't provide specific prompts to use with Copilot, as part of the learning experience is to discover how to interact with Copilot. If you are unfamiliar with Flask or how to add routes, you can look at the routes defined above for inspiration, or ask Copilot chat for guidance!
53 |
54 | ## Generate the unit tests
55 |
56 | With the route created, we want to now add the tests to ensure the code is correct. We can use GitHub Copilot chat's slash command **/tests** to create the test for us!
57 |
58 | 1. Return to your Codespace or VS Code.
59 | 2. Highlight the code you generated in the prior step.
60 | 3. Open GitHub Copilot chat.
61 | 4. Select the `+` button to start a new chat.
62 | 5. Type **/tests** and select tab to activate the command, then press enter to run the command. GitHub Copilot will generate the tests!
63 | 6. Select the **Apply edits** button just above the generated code suggestion to apply the changes to **test_app.py**.
64 | 7. Review and validate the code, making any necessary changes. Select **Keep** once you're satisfied.
65 | > [!IMPORTANT]
66 | > GitHub Copilot, like any generative AI solution, can make mistakes. Always review the generated code, making any necessary changes to ensure it's accurate and performs as expected.
67 | 8. Open a terminal window in your codespace or VS Code by selecting Ctl+Shift+`
68 | 9. Ensure the virtual server is activated by running the terminal command `source ./venv/bin/activate`
69 | 10. Navigate to the **server** folder by running the terminal command `cd server`
70 | 11. Run the tests by running the terminal command `python -m unittest`
71 | 12. Ensure all tests pass!
72 |
73 | ## Add the filters
74 |
75 | Adding the filters to the page will require updating a minimum of three files - the Flask backend, the unit tests for our 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.
76 |
77 | 1. Open the following files in your IDE (which we'll point Copilot chat to for context):
78 | - **server/app.py**
79 | - **server/test_app.py**
80 | - **client/src/components/DogList.svelte**
81 | 2. Open GitHub Copilot Chat.
82 | 3. Switch to edit mode by selecting **Edit** in the chat mode dropdown at the bottom of Chat view (should be currently **Ask**)
83 | 4. If available, select **Claude 3.7 Sonnet** for the model.
84 | 5. Select **Add Context...** in the chat window.
85 | 6. Select **server/app.py**, **client/src/components/DogList.svelte** and **server/test_app.py** files (you need to select **Add context** for each file)
86 | > [!TIP]
87 | > 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`)
88 | 7. Ask Copilot to perform the operation you want, to update the page to add the filters. It should meet the following requirements:
89 | - A dropdown list should be provided with all breeds
90 | - A checkbox should be available to only show available dogs
91 | - The page should automatically refresh whenever a change is made
92 | - Tests should be updated for any changes to the endpoint.
93 | 8. 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.
94 | 9. Open the page at [http://localhost:4321][localhost] to see the updates!
95 | 10. Run the Python tests by using `python -m unittest` in the terminal as you did previously.
96 | 11. If any changes are needed, explain the required updates to GitHub Copilot and allow it to generate the new code.
97 |
98 | > [!IMPORTANT]
99 | > 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.
100 |
101 | ## Summary and next steps
102 | Congratulations! You've worked with GitHub Copilot to add new features to the website - the ability to filter the list of dogs. Let's close out by [creating a pull request with our new functionality][walkthrough-next]!
103 |
104 | ## Resources
105 | - [Asking GitHub Copilot questions in your IDE][copilot-questions]
106 | - [Copilot Edits][copilot-chat-edits]
107 | - [Copilot Chat cookbook][copilot-chat-cookbook]
108 |
109 | | [← Helping GitHub Copilot understand context][walkthrough-previous] | [Next: GitHub flow →][walkthrough-next] |
110 | |:-----------------------------------|------------------------------------------:|
111 |
112 | [copilot-chat-cookbook]: https://docs.github.com/en/copilot/copilot-chat-cookbook
113 | [copilot-chat-edits]: https://code.visualstudio.com/docs/copilot/copilot-edits
114 | [copilot-questions]: https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/asking-github-copilot-questions-in-your-ide
115 | [localhost]: http://localhost:4321
116 | [localhost-breeds]: http://localhost:5100/api/breeds
117 | [walkthrough-previous]: 5-context.md
118 | [walkthrough-next]: 7-github-flow.md
119 |
--------------------------------------------------------------------------------
/content/full-day/7-github-flow.md:
--------------------------------------------------------------------------------
1 | # GitHub flow
2 |
3 | | [← Add new functionality][walkthrough-previous] | [Next: Deploy the application →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | The [GitHub flow][github-flow] is a lightweight, [branch-based][about-branches] workflow. It's designed to allow for free testing and exploration of ideas and novel approaches which are then reviewed and, if accepted, brought into the codebase. At a high level, the GitHub flow follows this pattern:
7 |
8 | 1. Create a branch
9 | 1. Make the desired changes
10 | 1. Create a [pull request][about-prs]
11 | 1. Review changes, gather feedback and make updates
12 | 1. Review results of automated operations such as testing for continuous integration
13 | 1. If changes are approved, merge into codebase
14 |
15 | The GitHub flow is designed to work as a cycle, where contributors continuously explore, test, review, and build upon their work and the work of others.
16 |
17 | > [!NOTE]
18 | > One key philosophy for GitHub flow is not every pull request needs to be merged. Sometimes exploration is the goal, the feature isn't one which is desired by the greater team, or wholesale changes need to be made necessitating starting over. This is part of the process, and allows for free experimentation.
19 |
20 | ## Scenario
21 |
22 | With the code changes created in the [prior exercise][code-exercise], it's time to walk through the GitHub flow to create a pull request and incorporate the updates into the codebase. While the changes have already been made (meaning we are slightly out of order from the "traditional" flow), you can still perform the steps to explore.
23 |
24 | ## Creating a branch
25 |
26 | A [branch][about-branches] is a copy of the code stored in the same repository. By using branches to test updates you have a safe space to explore while keeping all code in the same repository.
27 |
28 | There are different ways to create a branch when using [GitHub Codespaces][github-codespaces]. You can utilize the command-line to run [git](https://git-scm.com/docs/git-branch) commands. You can use the Source Control pane in your codespace to get the support of the UI for creating your branch. In our example we're going to use the command-line to create the branch.
29 |
30 | 1. Return to your codespace, or reopen it by navigating to your repository and selecting **Code** > **Codespaces** and the name of your codespace.
31 | 2. Open a **terminal window** by pressing Ctl + `.
32 | 3. In the terminal window, enter the following command to create and switch to a new branch named `add-filter`:
33 |
34 | ```bash
35 | git checkout -b add-filter
36 | ```
37 |
38 | 4. Stage all code to be committed to the new branch by entering the following command in the terminal window:
39 |
40 | ```bash
41 | git add .
42 | ```
43 |
44 | 5. Let Copilot generate a commit message by selecting the **Quick fix** icon (represented by sparkles) and **Generate Commit Message**.
45 |
46 | .
47 |
48 | 6. Press enter to run the command.
49 | 7. Finally, push the new branch to the repository by entering the following command in the terminal window:
50 |
51 | ```bash
52 | git push -u origin add-filter
53 | ```
54 |
55 | ## Create the pull request to suggest updates
56 |
57 | A [pull request][about-prs] is a request to pull or incorporate new code into the existing codebase. When a pull request is made it's customary to have other team members review the code and make comments, and for [CI/CD][cicd-resources] processes to run. Once everything is completed and the code is in a stage where everyone has signed-off, it's then merged into the codebase.
58 |
59 | Pull requests can be made through the source control pane in the codespace, the repository's website, or through the command-line using the [GitHub CLI][github-cli]. In our example we're going to create the pull request in the CLI, then navigate to the website to see the pull request and the actions running, and merge the code into the codebase.
60 |
61 | 1. Return to your codespace.
62 | 1. Find the number for the [issue you created earlier][issues-exercise] titled **Add component to display hours** by entering the following command in the terminal window:
63 |
64 | ```bash
65 | gh issue list
66 | ```
67 |
68 | 1. Create a pull request with the title **Add hours component** and body **Resolves #\**, replacing **\** with the issue number you obtained in the previous step by entering the following command in the terminal window:
69 |
70 | ```bash
71 | gh pr create -t "Add hours component" -b "Resolves #"
72 | ```
73 |
74 | ## Explore and merge the pull request
75 |
76 | When the pull request is created, you will see a link appear to the page for the pull request. From there you can add comments, see any workflows running, and decide to close or merge the pull request. You can also see any workflows associated with the pull request run.
77 |
78 | In our scenario, we created an automated workflow for front-end tests for our application, which runs whenever a push or pull request is made to `main`. We also enabled [code scanning][security-exercise], which was set to run on the same triggers. We've just created a pull request, which will cause both of those workflows to run!
79 |
80 | Let's explore the pull request and watch the workflows run. We'll ensure the tests now run successfully and, assuming they do, merge the pull request.
81 |
82 | 1. Follow the link displayed in the terminal window by using Ctl - **Click** (or Cmd - **Click** on a Mac).
83 | 1. In the page displayed, note the workflow running the [end-to-end tests created earlier][testing-exercise] and [code scanning][security-exercise].
84 | 1. When the workflows complete successfully, select **Merge pull request** to merge your changes into the **main** branch.
85 |
86 | Congratulations! You've now used the GitHub flow to suggest changes, perform a review, and merge those into your codebase.
87 |
88 | ## Summary and next steps
89 |
90 | The GitHub flow is a workflow for managing changes and incorporating new features into a codebase. GitHub flow gives you the freedom to explore and experiment, while ensuring all code follows a validation process before being merged. Let's get our [application deployed][walkthrough-next].
91 |
92 | ## Resources
93 |
94 | - [GitHub flow][github-flow]
95 | - [GitHub Skills: Review pull requests][skills-review-prs]
96 | - [GitHub Skills: Release based workflow][skills-release-workflow]
97 |
98 | | [← Add new functionality][walkthrough-previous] | [Next: Deploy the application →][walkthrough-next] |
99 | |:-----------------------------------|------------------------------------------:|
100 |
101 | [about-branches]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches
102 | [about-prs]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests
103 | [cicd-resources]: https://resources.github.com/ci-cd/
104 | [code-exercise]: ./6-code.md
105 | [github-codespaces]: https://github.com/features/codespaces
106 | [github-cli]: https://cli.github.com/
107 | [github-flow]: https://docs.github.com/en/get-started/quickstart/github-flow
108 | [issues-exercise]: ./2-issues.md
109 | [security-exercise]: ./1-code-scanning.md
110 | [skills-review-prs]: https://github.com/skills/review-pull-requests
111 | [skills-release-workflow]: https://github.com/skills/release-based-workflow
112 | [testing-exercise]: ./4-testing.md
113 | [walkthrough-previous]: 6-code.md
114 | [walkthrough-next]: 8-deployment.md
115 |
--------------------------------------------------------------------------------
/content/full-day/8-deployment.md:
--------------------------------------------------------------------------------
1 | # Deploying the project to the cloud
2 |
3 | | [← GitHub flow][walkthrough-previous] | [Next: Pets workshop selection →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | The CD portion of CI/CD is continuous delivery or continuous deployment. In a nutshell, it's about taking the product you're building and putting it somewhere to be accessed by the people who need it. There's numerous ways to do this, and the process can become rather involved. We're going to focus on taking our application and deploying it to Azure.
7 |
8 | > [!NOTE]
9 | > We've taken a couple of shortcuts with the application structure to ensure things run smoothly in this workshop.
10 |
11 | ## Scenario
12 |
13 | With the prototype built, the shelter is ready to begin gathering feedback from external users. They want to deploy the project to the internet, and ensure any updates merged into main are available as quickly as possible.
14 |
15 | ## Return to main
16 |
17 | To streamline the process, we're going to work directly with the **main** branch. Let's change back to the **main** branch and obtain the updates we pushed previously.
18 |
19 | 1. Return to your codespace, or reopen it by navigating to your repository and selecting **Code** > **Codespaces** and the name of your codespace.
20 | 2. Open a new terminal window by selecting Ctl+Shift+`.
21 | 3. Run the following commands to checkout the main branch and obtain the updates from the repository:
22 |
23 | ```sh
24 | git checkout main
25 | git pull
26 | ```
27 |
28 | ## Identity management
29 |
30 | Whenever you're interacting with an external service, you of course need credentials to perform any actions. This holds true when you're creating any form of automated tasks, such as a workflow in GitHub. There are several ways to manage identities, including access tokens, shared passwords, and [Open ID Connect (OIDC)][oidc-docs], with the latter being the newest and preferred mechanism. The advantage to OIDC is it uses short-lived tokens and provides granular control over the operations which can be performed.
31 |
32 | Creating and setting up the credentials is typically a task performed by administrators. However, there are tools which can manage this for you, one of which we'll be taking advantage of!
33 |
34 | ## Asking Azure how to deploy to Azure
35 |
36 | We previously talked about [extensions for GitHub Copilot chat][extensions-copilot-chat], which allow you to interact with external services. These external services could provide access to information about your DevOps flow, database, and other resources. One such extension is the [Azure extension][azure-copilot-extension], which as the name implies allows you to interact with Azure. You can use the extension to get advice on how to deploy your application, check the status of services, and perform other operations. We'll use this extension to ask how to deploy our application.
37 |
38 | As we've done with other tasks, we don't have a specific prompt to use when talking with Azure, as part of the experience is to learn how best to interact with GitHub Copilot. The requirements for the deployment are:
39 |
40 | - Deploy the project to the cloud
41 | - Use a GitHub action to manage the deployment process
42 |
43 | 1. Open GitHub Copilot Chat.
44 | 2. Activate the Azure extension by typing `@azure`, selecting Tab then asking the extension how to perform the task you wish to perform (see the requirements above).
45 |
46 | > [!NOTE]
47 | > Since this is your first time using the extension, you will be prompted to signin to Azure. Follow the prompts as they appear.
48 |
49 | 3. You should receive a response which highlights the `azd` command, which can be used to both initialize a cloud environment and create the workflow.
50 |
51 | ## Overview of the response from Copilot
52 |
53 | The response from GitHub Copilot will likely contain instructions to use the following commands:
54 |
55 | - `azd init --from-code` to create the Azure configuration files using [bicep][bicep-docs].
56 | - `azd auth login` to authenticate to Azure.
57 | - `azd pipeline config` to create the GitHub Workflow.
58 |
59 | [azd][azd-docs] is a commandline utility to help streamline the deployment process to Azure. We'll use it to:
60 |
61 | - generate the bicep file.
62 | - create the workflow file.
63 | - create and configure OIDC for the workflow.
64 |
65 | If you're curious about **azd** or Azure, you can always ask the extension using GitHub Copilot!
66 |
67 | ## Install azd
68 |
69 | Let's start by installing **azd**.
70 |
71 | 1. Run the command in the terminal to install **azd**:
72 |
73 | ```sh
74 | curl -fsSL https://aka.ms/install-azd.sh | bash
75 | ```
76 |
77 | ## Create and configure the bicep file
78 |
79 | Bicep is a domain specific language (DSL) for defining Azure resources. It's dynamic, allowing you to ensure your environment is configured exactly as you need it. We're going to start by allowing **azd** create the bicep file, then make an update to ensure we have an environment variable available for the client to connect to the server.
80 |
81 | 1. Run the `init` command to create the bicep file.
82 |
83 | ```sh
84 | azd init --from-code
85 | ```
86 |
87 | 2. Follow the prompts, accepting any defaults provided by the tool, and naming your namespace (which will be used to name the resource group and various resources in Azure) something unique.
88 | 3. Open the bicep file located at **infra**/**resources.bicep**.
89 | 4. Find the section (around line 130) which reads:
90 |
91 | ```bicep
92 | {
93 | name: 'PORT'
94 | value: '4321'
95 | }
96 | ```
97 |
98 | 5. Create a new line below the closing `}` and add the following to create an environment variable with the URL of the newly created Flask server:
99 |
100 | ```bicep
101 | {
102 | name: 'API_SERVER_URL'
103 | value: 'https://${server.outputs.fqdn}'
104 | }
105 | ```
106 |
107 | > [!NOTE]
108 | > While the syntax resembles JSON, it's not JSON. As a result, resist the urge to add commas to separate the values!
109 |
110 | ## Create the workflow
111 |
112 | `azd` can create and configure a workflow (or sometimes called a pipeline) for deploying your project. In particular it will:
113 |
114 | - create OIDC credentials to use for deployment.
115 | - define the YML file in the **workflows** folder.
116 |
117 | Let's let `azd` do its work!
118 |
119 | 1. Return to your terminal window, and run the following command to authenticate with `azd`
120 |
121 | ```sh
122 | azd auth login
123 | ```
124 |
125 | 2. Follow the prompts to authenticate to Azure using the credentials you specified previously.
126 | 3. Create the pipeline by running the following command:
127 |
128 | ```sh
129 | azd pipeline config
130 | ```
131 |
132 | 4. Follow the prompts, accepting the defaults. One of the prompts will ask if you wish to perform the deployment now - say yes!
133 | 5. Away your application goes to the cloud!
134 |
135 | ## Track the deployment and test your application
136 |
137 | The `azd pipeline config` command will create a new workflow file at **.github/workflows/azure-dev.yml**. Let's explore the workflow, track the action as it runs (this will take a few minutes), and test the application!
138 |
139 | 1. Open the workflow at **.github/workflows/azure-dev.yml**.
140 | 2. Note the `on` section, which contains the flags for `workflow_dispatch` (to support manual deployment), and `push` to automatically deploy when code is pushed to the **main** branch.
141 | 3. Note the core steps, which checkout your code, authenticate to Azure, create or update the infrastructure, then deploy the application.
142 | 4. If you have questions about what the workflow is doing, ask GitHub Copilot!
143 | 5. Navigate to your repository on GitHub.
144 | 6. Open the **Actions** tab, then the action named **.github/workflows/azure-dev.yml**. You should see the action running (the icon will be yellow under the **workflow runs** section).
145 | 7. Select the running workflow (which should be named **Configure Azure Developer Pipeline**).
146 | 8. Select the **build** step.
147 | 9. Track the deployment process, which will take about 5-10 minutes (good time for a water break!).
148 | 10. Once the process completes, expand the **Deploy Application** section. You should see the log indicating the client and server were both deployed:
149 |
150 | ```
151 | Deploying service client
152 | Deploying service client (Building Docker image)
153 | Deploying service client (Tagging container image)
154 | Deploying service client (Tagging container image)
155 | Deploying service client (Logging into container registry)
156 | Deploying service client (Pushing container image)
157 | Deploying service client (Updating container app revision)
158 | Deploying service client (Fetching endpoints for container app service)
159 | (✓) Done: Deploying service client
160 | - Endpoint: https://client.delightfulfield-8f7ef050.westus.azurecontainerapps.io/
161 |
162 | Deploying service server
163 | Acquiring pack cli
164 | Deploying service server (Building Docker image from source)
165 | Deploying service server (Tagging container image)
166 | Deploying service server (Tagging container image)
167 | Deploying service server (Logging into container registry)
168 | Deploying service server (Pushing container image)
169 | Deploying service server (Updating container app revision)
170 | Deploying service server (Fetching endpoints for container app service)
171 | (✓) Done: Deploying service server
172 | - Endpoint: https://server.delightfulfield-8f7ef050.westus.azurecontainerapps.io/
173 | ```
174 |
175 | 11. Select the Endpoint for the client. You should see your application!
176 |
177 | You've now deployed your project!
178 |
179 | ## Summary
180 |
181 | You've now created and configured a full CI/CD process. You implemented security checks, testing, and now deployment. As highlighted previously, enterprise CI/CD processes can be rather complex, but at their core they use the skills you explored during this workshop.
182 |
183 | ## Wrap-up and challenge
184 |
185 | Congratulations! You've gone through an entire DevOps process. You began by creating an issue to document the required work, then ensured everything was in place to run automatically. You performed the updates to the application, pushed everything to your repository, and merged it in!
186 |
187 | If you wish to continue exploring from here, there are a couple of tasks you could pursue:
188 |
189 | - Add more functionality to the website! There's a lot you could do, like adding on an adoption form or the ability to store images.
190 | - Migrate the database to something more powerful such as Postgres or SQL Server.
191 |
192 | Work with the workshop leaders as needed to ask questions and get guidance as you continue to build on the skills you learned today!
193 |
194 | ## Resources
195 |
196 | - [About security hardening with OpenID Connect][oidc-docs]
197 | - [Deploying with GitHub Actions][actions-deploy]
198 | - [What is the Azure Developer CLI?][azd-docs]
199 |
200 | | [← GitHub flow][walkthrough-previous] | [Next: Pets workshop selection →][walkthrough-next] |
201 | |:-----------------------------------|------------------------------------------:|
202 |
203 | [actions-deploy]: https://docs.github.com/en/actions/use-cases-and-examples/deploying/deploying-with-github-actions
204 | [azd-docs]: https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/overview?tabs=linux
205 | [azure-copilot-extension]: https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azure-github-copilot
206 | [bicep-docs]: https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep
207 | [extensions-copilot-chat]: ./5-context.md
208 | [oidc-docs]: https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect
209 | [walkthrough-previous]: 7-github-flow.md
210 | [walkthrough-next]: ../README.md
--------------------------------------------------------------------------------
/content/full-day/README.md:
--------------------------------------------------------------------------------
1 | # Modern DevOps with GitHub
2 |
3 | | [← Pets workshop selection][walkthrough-previous] | [Next: Workshop setup →][walkthrough-next] |
4 | |:-----------------------------------|------------------------------------------:|
5 |
6 | [DevOps][devops] is a [portmanteau][portmanteau] of **development** and **operations**. At its core is a desire to bring development practices more inline with operations, and operations practices more inline with development. This fosters better communication and collaboration between teams, breaks down barriers, and gives everyone an investment in ensuring customers are delighted by the software we ship.
7 |
8 | This workshop is built to help guide you through some of the most common DevOps tasks on GitHub. You'll explore:
9 |
10 | - Managing projects with [GitHub Issues][github-issues]
11 | - Creating a development environment with [GitHub Codespaces][github-codespaces]
12 | - Using [GitHub Copilot][github-copilot] as your AI pair programmer
13 | - Securing the development pipeline with [GitHub Advanced Security][github-security]
14 | - Automating tasks and CI/CD with [GitHub Actions][github-actions]
15 |
16 | ## Prerequisites
17 |
18 | 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!
19 |
20 | ## Required resources
21 |
22 | To complete this workshop, you will need the following:
23 |
24 | - A [GitHub account][github-signup]
25 | - Access to [GitHub Copilot][github-copilot]
26 |
27 | ## Getting started
28 |
29 | Ready to get started? Let's go! The workshop scenario imagines you as a developer volunteering your time for a pet adoption center. You will work through the process of creating a development environment, creating code, enabling security, and automating processes.
30 |
31 | 0. [Setup your environment][walkthrough-next] for the workshop
32 | 1. [Enable Code Scanning][code-scanning] to ensure new code is secure
33 | 2. [Create an issue][issues] to document a feature request
34 | 3. [Create a codespace][codespaces] to start writing code
35 | 4. [Implement testing][testing] to supplement continuous integration
36 | 5. [Provide Copilot context][context] to generate quality code suggestions
37 | 6. [Add features to your app][code] with GitHub Copilot
38 | 7. [Use the GitHub flow][github-flow] to incorporate changes into your codebase
39 | 8. [Deploy your application][deployment] to Azure to make your application available to users
40 |
41 | ## Check out these resources to dive in and learn more
42 | Check out the resources in [**GitHub-Copilot-Resources.md**][GitHub-Copilot-Resources].
43 |
44 | 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.
45 |
46 | | [← Pets workshop selection][walkthrough-previous] | [Next: Workshop setup →][walkthrough-next] |
47 | |:-----------------------------------|------------------------------------------:|
48 |
49 | [code]: ./6-code.md
50 | [code-scanning]: ./1-code-scanning.md
51 | [codespaces]: ./3-codespaces.md
52 | [context]: ./5-context.md
53 | [deployment]: ./8-deployment.md
54 | [devops]: https://en.wikipedia.org/wiki/DevOps
55 | [github-actions]: https://github.com/features/actions
56 | [github-codespaces]: https://github.com/features/codespaces
57 | [github-copilot]: https://github.com/features/copilot
58 | [github-flow]: ./7-github-flow.md
59 | [github-issues]: https://github.com/features/issues
60 | [github-security]: https://github.com/features/security
61 | [github-signup]: https://github.com/join
62 | [issues]: ./2-issues.md
63 | [portmanteau]: https://www.merriam-webster.com/dictionary/portmanteau
64 | [testing]: ./4-testing.md
65 | [walkthrough-next]: ./0-setup.md
66 | [walkthrough-previous]: ../README.md
67 | [GitHub-Copilot-Resources]: ../GitHub-Copilot-Resources.md
68 |
--------------------------------------------------------------------------------
/content/full-day/images/1-code-scanning-dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/1-code-scanning-dialog.png
--------------------------------------------------------------------------------
/content/full-day/images/1-code-scanning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/1-code-scanning.png
--------------------------------------------------------------------------------
/content/full-day/images/1-dependabot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/1-dependabot.png
--------------------------------------------------------------------------------
/content/full-day/images/1-secret-scanning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/1-secret-scanning.png
--------------------------------------------------------------------------------
/content/full-day/images/3-open-browser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/3-open-browser.png
--------------------------------------------------------------------------------
/content/full-day/images/3-reload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/3-reload.png
--------------------------------------------------------------------------------
/content/full-day/images/3-secrets-variables.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/3-secrets-variables.png
--------------------------------------------------------------------------------
/content/full-day/images/4-select-file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/4-select-file.png
--------------------------------------------------------------------------------
/content/full-day/images/5-copilot-chat-references.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/5-copilot-chat-references.png
--------------------------------------------------------------------------------
/content/full-day/images/7-generate-commit-message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/content/full-day/images/7-generate-commit-message.png
--------------------------------------------------------------------------------
/content/prompts/README.md:
--------------------------------------------------------------------------------
1 | # Pets Workshop Prompts
2 |
3 | This directory contains various prompts designed for different aspects of development and enhancement of the Pets Workshop project. These prompts are meant for illustration purposes only.
4 |
5 | ## Prompt Overview
6 |
7 | ### Interface and User Experience
8 |
9 | - **[fun-add-themes](./fun-add-themes.md)**: Adds a theme selector dropdown that allows users to switch between multiple visual themes including 80s Retro, Terminal Classic, Hand-Sketched, Steampunk, and Fantasy Realm. Enhances user customization and visual appeal.
10 |
11 | - **[fun-add-dog-animation](./fun-add-dog-animation.md)**: Implements an interactive cartoon dog animation in the bottom-right corner of the website that follows the user's cursor with its eyes. The dog remains visible while scrolling and has extra animations on mouse clicks, adding a playful element to the user experience.
12 |
13 | ### Backend Development
14 |
15 | - **[conversion-convert-flask-to-golang](./conversion-convert-flask-to-golang.md)**: Provides instructions for migrating the existing Python Flask server to a Go-based implementation while maintaining identical functionality, API endpoints, and response formats. The goal is to create a functionally equivalent server using Go's standard library.
16 |
17 | - **[monitoring-add-logging](./monitoring-add-logging.md)**: Details requirements for implementing a comprehensive logging system in the Python Flask server with multiple logging levels, consistent formatting, configuration options, and performance considerations. This improves monitoring, debugging, and operational visibility.
18 |
--------------------------------------------------------------------------------
/content/prompts/conversion-convert-flask-to-golang.md:
--------------------------------------------------------------------------------
1 | # Flask to Go Server Migration Project
2 |
3 | ## Objective
4 |
5 | Convert the existing Python Flask server implementation to a Go-based server with identical functionality and API endpoints. The Go implementation should maintain the same request handling, routes, data processing, and response formats as the original Flask server.
6 |
7 | The Python Flask is stored in #folder:server
8 |
9 | ## Requirements
10 | 1. Create a functionally equivalent Go server implementation
11 | 2. Match all existing API endpoints, query parameters, and HTTP methods
12 | 3. Preserve all current data processing logic and response formats
13 | 4. Implement the same error handling and status codes
14 | 5. Maintain any authentication mechanisms present in the Flask implementation
15 | 6. Use only the Go standard library where possible, with minimal external dependencies
16 | 7. Include appropriate comments explaining the code and any implementation decisions
17 |
18 | ## Deliverables
19 | 1. Complete Go source code organized in a folder named `go_server`
20 | 2. A main.go file with server initialization and configuration
21 | 3. Separate handler files for different API endpoint groups
22 | 4. Any utility or helper functions required
23 | 5. A README.md with setup and usage instructions
24 |
25 |
--------------------------------------------------------------------------------
/content/prompts/fun-add-dog-animation.md:
--------------------------------------------------------------------------------
1 | # Puppy Cursor Follower
2 |
3 | Add an adorable cartoon dog to the bottom-right corner of the website that follows the user's cursor with its eyes, similar to the classic XEyes program from X11.
4 |
5 | ## Requirements:
6 | - The dog should be cute and cartoony with expressive eyes
7 | - Eyes should smoothly track the cursor position across the entire screen
8 | - Position the dog in the bottom-right corner as a fixed element (sticky positioning)
9 | - Dog should remain visible even when the page is scrolled
10 | - Add a slight head tilt or ear wiggle on mouse clicks for extra charm
11 | - Optional: Make the dog occasionally blink or perform a random animation
12 |
13 | Let's make browsing fun again with this interactive canine companion! 🐶
--------------------------------------------------------------------------------
/content/prompts/fun-add-themes.md:
--------------------------------------------------------------------------------
1 | # 🎨 Theme-tastic Interface Enhancement!
2 |
3 | ## 🎯 Your Mission
4 | Transform our boring interface into a playground of visual delights! Let users express themselves through awesome themes.
5 |
6 | ## 🔍 Key Requirements
7 | 1. **Theme Selector Dropdown**
8 | - Position: ↗️ Top-right corner of the screen
9 | - Behavior: Interface instantly refreshes when a new theme is selected
10 | - Default label: "Default" (our current look)
11 |
12 | ## 🌈 Required Themes
13 | Add these fabulous theme options:
14 |
15 | * **80s Retro** 🕹️
16 | - Think neon colors, bold patterns, geometric shapes
17 | - Inspiration: Miami Vice, arcade games, synthwave
18 |
19 | * **Terminal Classic** 💻
20 | - Nostalgic VT100 green-on-black terminal look
21 | - Features: Monospace fonts, scan lines, command prompt aesthetic
22 |
23 | * **Hand-Sketched** ✏️
24 | - UI elements that appear hand-drawn with a playful, creative feel
25 | - Think: Doodles, sketch lines, paper texture backgrounds
26 |
27 | * **Steampunk** ⚙️
28 | - Brass, gears, leather, and Victorian-era aesthetics mixed with futuristic elements
29 | - Inspiration: Jules Verne, The League of Extraordinary Gentlemen, Bioshock Infinite
30 |
31 | * **Fantasy Realm** 🧙
32 | - Mystical forests, glowing runes, and enchanted elements
33 | - Inspiration: Lord of the Rings, Dungeons & Dragons, Skyrim
34 |
35 |
36 | ## 🚀 Bonus Points
37 | - Add subtle animations for theme transitions
38 | - Include a small preview of each theme in the dropdown
39 | - Make sure all themes maintain accessibility standards
40 |
41 |
--------------------------------------------------------------------------------
/content/prompts/monitoring-add-logging.md:
--------------------------------------------------------------------------------
1 | Add logging commands to server application which is written in python
2 |
3 | The Python Flask is stored in #folder:server
4 |
5 | Create a standardized logging system for the Python Flask with the following requirements:
6 |
7 | 1. LOGGING LEVELS: Implement five distinct logging levels (DEBUG, INFO, WARNING, ERROR, CRITICAL) with clear usage guidelines for each.
8 |
9 | 2. FORMAT CONSISTENCY: Define a consistent log entry format including:
10 | - Timestamp (ISO 8601 format: YYYY-MM-DD HH:MM:SS.mmm)
11 | - Log level
12 | - Module/component name
13 | - Thread ID (where applicable)
14 | - Message content
15 |
16 | 3. CONFIGURATION: Provide a configuration system that allows:
17 | - Setting global minimum log level
18 | - Per-module logging levels
19 | - Multiple output destinations (console, file, external service)
20 | - Log rotation settings for file outputs
21 |
22 | 4. CODE EXAMPLES: Include example implementations showing:
23 | - Proper logger initialization
24 | - Correct usage of each log level
25 | - Error/exception logging with stack traces
26 | - Context-enriched logging
27 |
28 | 5. PERFORMANCE CONSIDERATIONS: Address how to optimize logging for production environments.
29 |
30 | The solution should be maintainable, follow industry best practices, and minimize performance impact.
31 |
--------------------------------------------------------------------------------
/scripts/start-app.ps1:
--------------------------------------------------------------------------------
1 | # Define color codes for PowerShell
2 | $Green = [System.ConsoleColor]::Green
3 | $DefaultColor = [System.ConsoleColor]::White
4 |
5 | # Store initial directory
6 | $InitialDir = Get-Location
7 |
8 | # Check if we're in scripts directory and navigate accordingly
9 | if ((Split-Path -Path (Get-Location) -Leaf) -eq "scripts") {
10 | Set-Location ..
11 | }
12 |
13 | Write-Host "Starting API (Flask) server..."
14 |
15 | # Create and activate virtual environment
16 | if (-not (Test-Path venv)) {
17 | python -m venv venv
18 | }
19 | if ($IsWindows) {
20 | & ./venv/Scripts/Activate.ps1
21 | } else {
22 | & bash -c "source ./venv/bin/activate"
23 | }
24 |
25 | Set-Location server -ErrorAction Stop
26 | pip install -r requirements.txt
27 | Set-Location ..
28 | $env:FLASK_DEBUG = 1
29 | $env:FLASK_PORT = 5100
30 |
31 |
32 | # Start Python server
33 | $pythonProcess = Start-Process python `
34 | -WorkingDirectory (Join-Path $PSScriptRoot "..\server") `
35 | -ArgumentList "app.py" `
36 | -PassThru `
37 | -NoNewWindow
38 |
39 | Write-Host "Starting client (Astro)..."
40 | Set-Location client -ErrorAction Stop
41 | npm install
42 | cd ..
43 | if ($IsWindows) {
44 | $npcCmd = "npm.cmd"
45 | } else {
46 | $npcCmd = "npm"
47 | }
48 |
49 | $clientProcess = Start-Process "$npcCmd" `
50 | -WorkingDirectory (Join-Path $PSScriptRoot "..\client") `
51 | -ArgumentList "run", "dev", "--", "--no-clearScreen" `
52 | -PassThru `
53 | -NoNewWindow
54 |
55 | # Sleep for 5 seconds
56 | Start-Sleep -Seconds 5
57 |
58 | # Display the server URLs
59 | Write-Host "`nServer (Flask) running at: http://localhost:5100" -ForegroundColor $Green
60 | Write-Host "Client (Astro) server running at: http://localhost:4321`n" -ForegroundColor $Green
61 | Write-Host "Ctrl+C to stop the servers"
62 |
63 | # Function to handle cleanup
64 | function Cleanup {
65 | Write-Host "Shutting down servers..."
66 |
67 | # Kill processes and their child processes
68 | if ($pythonProcess) { Stop-Process -Id $pythonProcess.Id -Force -ErrorAction SilentlyContinue }
69 | if ($clientProcess) { Stop-Process -Id $clientProcess.Id -Force -ErrorAction SilentlyContinue }
70 |
71 | # Deactivate virtual environment if it exists
72 | if (Test-Path Function:\deactivate) {
73 | deactivate
74 | }
75 |
76 | # Return to initial directory
77 | Set-Location $InitialDir
78 | exit
79 | }
80 |
81 | # Register cleanup for script termination
82 | $null = Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { Cleanup }
83 |
84 | try {
85 | # Keep the script running until Ctrl+C
86 | Wait-Process -Id $pythonProcess.Id
87 | } finally {
88 | Cleanup
89 | }
90 |
--------------------------------------------------------------------------------
/scripts/start-app.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Define color codes
4 | GREEN='\033[0;32m'
5 | NC='\033[0m' # No Color
6 |
7 | # Store initial directory
8 | INITIAL_DIR=$(pwd)
9 |
10 | # Check if we're in scripts directory and navigate accordingly
11 | if [[ $(basename $(pwd)) == "scripts" ]]; then
12 | cd ..
13 | fi
14 |
15 | echo "Starting API (Flask) server..."
16 |
17 | # Check OS and use appropriate Python command
18 | if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
19 | # Windows
20 | py -m venv venv
21 | source venv/Scripts/activate || . venv/Scripts/activate
22 | else
23 | # macOS/Linux
24 | python3 -m venv venv
25 | source venv/bin/activate || . venv/bin/activate
26 | fi
27 |
28 | pip install -r server/requirements.txt
29 | cd server || {
30 | echo "Error: server directory not found"
31 | cd "$INITIAL_DIR"
32 | exit 1
33 | }
34 | export FLASK_DEBUG=1
35 | export FLASK_PORT=5100
36 |
37 | # Use appropriate Python command based on OS
38 | if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
39 | py app.py &
40 | else
41 | python3 app.py &
42 | fi
43 |
44 | # Store the Python server process ID
45 | SERVER_PID=$!
46 |
47 | echo "Starting client (Astro)..."
48 | cd ../client || {
49 | echo "Error: client directory not found"
50 | cd "$INITIAL_DIR"
51 | exit 1
52 | }
53 | npm install
54 | npm run dev -- --no-clearScreen &
55 |
56 | # Store the SvelteKit server process ID
57 | CLIENT_PID=$!
58 |
59 | # Sleep for 3 seconds
60 | sleep 5
61 |
62 | # Display the server URLs
63 | echo -e "\n${GREEN}Server (Flask) running at: http://localhost:5100${NC}"
64 | echo -e "${GREEN}Client (Astro) server running at: http://localhost:4321${NC}\n"
65 |
66 | echo "Ctl-C to stop the servers"
67 |
68 | # Function to handle script termination
69 | cleanup() {
70 | echo "Shutting down servers..."
71 |
72 | # Kill processes and their child processes
73 | if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
74 | taskkill //F //T //PID $SERVER_PID 2>/dev/null
75 | taskkill //F //T //PID $CLIENT_PID 2>/dev/null
76 | else
77 | # Send SIGTERM first to allow graceful shutdown
78 | kill -TERM $SERVER_PID 2>/dev/null
79 | kill -TERM $CLIENT_PID 2>/dev/null
80 |
81 | # Wait briefly for graceful shutdown
82 | sleep 2
83 |
84 | # Then force kill if still running
85 | if ps -p $SERVER_PID > /dev/null 2>&1; then
86 | pkill -P $SERVER_PID 2>/dev/null
87 | kill -9 $SERVER_PID 2>/dev/null
88 | fi
89 |
90 | if ps -p $CLIENT_PID > /dev/null 2>&1; then
91 | pkill -P $CLIENT_PID 2>/dev/null
92 | kill -9 $CLIENT_PID 2>/dev/null
93 | fi
94 | fi
95 |
96 | # Deactivate virtual environment if active
97 | if [[ -n "${VIRTUAL_ENV}" ]]; then
98 | deactivate
99 | fi
100 |
101 | # Return to initial directory
102 | cd "$INITIAL_DIR"
103 | exit 0
104 | }
105 |
106 | # Trap multiple signals
107 | trap cleanup SIGINT SIGTERM SIGQUIT EXIT
108 |
109 | # Keep the script running
110 | wait
--------------------------------------------------------------------------------
/server/app.py:
--------------------------------------------------------------------------------
1 | import os
2 | from typing import Dict, List, Any, Optional
3 | from flask import Flask, jsonify, Response
4 | from models import init_db, db, Dog, Breed
5 |
6 | # Get the server directory path
7 | base_dir: str = os.path.abspath(os.path.dirname(__file__))
8 |
9 | app: Flask = Flask(__name__)
10 | app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{os.path.join(base_dir, "dogshelter.db")}'
11 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
12 |
13 | # Initialize the database with the app
14 | init_db(app)
15 |
16 | @app.route('/api/dogs', methods=['GET'])
17 | def get_dogs() -> Response:
18 | query = db.session.query(
19 | Dog.id,
20 | Dog.name,
21 | Breed.name.label('breed')
22 | ).join(Breed, Dog.breed_id == Breed.id)
23 |
24 | dogs_query = query.all()
25 |
26 | # Convert the result to a list of dictionaries
27 | dogs_list: List[Dict[str, Any]] = [
28 | {
29 | 'id': dog.id,
30 | 'name': dog.name,
31 | 'breed': dog.breed
32 | }
33 | for dog in dogs_query
34 | ]
35 |
36 | return jsonify(dogs_list)
37 |
38 | @app.route('/api/dogs/', methods=['GET'])
39 | def get_dog(id: int) -> tuple[Response, int] | Response:
40 | # Query the specific dog by ID and join with breed to get breed name
41 | dog_query = db.session.query(
42 | Dog.id,
43 | Dog.name,
44 | Breed.name.label('breed'),
45 | Dog.age,
46 | Dog.description,
47 | Dog.gender,
48 | Dog.status
49 | ).join(Breed, Dog.breed_id == Breed.id).filter(Dog.id == id).first()
50 |
51 | # Return 404 if dog not found
52 | if not dog_query:
53 | return jsonify({"error": "Dog not found"}), 404
54 |
55 | # Convert the result to a dictionary
56 | dog: Dict[str, Any] = {
57 | 'id': dog_query.id,
58 | 'name': dog_query.name,
59 | 'breed': dog_query.breed,
60 | 'age': dog_query.age,
61 | 'description': dog_query.description,
62 | 'gender': dog_query.gender,
63 | 'status': dog_query.status.name
64 | }
65 |
66 | return jsonify(dog)
67 |
68 | ## HERE
69 |
70 | if __name__ == '__main__':
71 | app.run(debug=True, port=5100) # Port 5100 to avoid macOS conflicts
--------------------------------------------------------------------------------
/server/dogshelter.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/github-samples/pets-workshop/06e4b8bd06dbe8f4aa5c01d934cc90dd496e89f2/server/dogshelter.db
--------------------------------------------------------------------------------
/server/models/__init__.py:
--------------------------------------------------------------------------------
1 | from flask_sqlalchemy import SQLAlchemy
2 |
3 | db = SQLAlchemy()
4 |
5 | # Import models after db is defined to avoid circular imports
6 | from .breed import Breed
7 | from .dog import Dog
8 |
9 | # Initialize function to be called from app.py
10 | def init_db(app):
11 | db.init_app(app)
12 |
13 | # Create tables when initializing
14 | with app.app_context():
15 | db.create_all()
--------------------------------------------------------------------------------
/server/models/base.py:
--------------------------------------------------------------------------------
1 | # filepath: server/models/base.py
2 | from . import db
3 |
4 | class BaseModel(db.Model):
5 | __abstract__ = True
6 |
7 | @staticmethod
8 | def validate_string_length(field_name, value, min_length=2, allow_none=False):
9 | if value is None:
10 | if allow_none:
11 | return value
12 | else:
13 | raise ValueError(f"{field_name} cannot be empty")
14 |
15 | if not isinstance(value, str):
16 | raise ValueError(f"{field_name} must be a string")
17 |
18 | if len(value.strip()) < min_length:
19 | raise ValueError(f"{field_name} must be at least {min_length} characters")
20 |
21 | return value
--------------------------------------------------------------------------------
/server/models/breed.py:
--------------------------------------------------------------------------------
1 | # filepath: server/models/breed.py
2 | from . import db
3 | from .base import BaseModel
4 | from sqlalchemy.orm import validates, relationship
5 |
6 | class Breed(BaseModel):
7 | __tablename__ = 'breeds'
8 |
9 | id = db.Column(db.Integer, primary_key=True)
10 | name = db.Column(db.String(100), nullable=False, unique=True)
11 | description = db.Column(db.Text)
12 |
13 | # Relationship with Dog model
14 | dogs = relationship('Dog', backref='breed_info', lazy=True)
15 |
16 | @validates('name')
17 | def validate_name(self, key, name):
18 | return self.validate_string_length('Breed name', name, min_length=2)
19 |
20 | @validates('description')
21 | def validate_description(self, key, description):
22 | return self.validate_string_length('Description', description, min_length=10, allow_none=True)
23 |
24 | def __repr__(self):
25 | return f''
--------------------------------------------------------------------------------
/server/models/breeds.csv:
--------------------------------------------------------------------------------
1 | Breed,Description
2 | Labrador Retriever,"America's favorite family dog, friendly and easy-going."
3 | French Bulldog,"Small, adaptable, and great for urban living."
4 | Golden Retriever,"Family-friendly, smart, and easy to train."
5 | German Shepherd,"Intelligent, loyal, used in police/military work, but also great pets."
6 | Bulldog (English Bulldog),"Laid-back, gentle, and great for apartments."
7 | Poodle,"Smart, hypoallergenic, comes in multiple sizes."
8 | Beagle,"Compact, friendly, and good with kids — but need exercise!"
9 | Rottweiler,"Strong, loyal, great family protector."
10 | Yorkshire Terrier (Yorkie),"Tiny but confident, popular in cities."
11 | Dachshund,"Small, bold, and fun — often called 'wiener dogs.'"
12 | Pembroke Welsh Corgi,"Small herding dog, smart and full of personality."
13 | Boxer,"Playful, protective, and great with kids."
14 | Shih Tzu,"Small, affectionate lap dogs."
15 | Chihuahua,"Tiny and portable, popular with city dwellers."
16 | Siberian Husky,"Beautiful and energetic, but needs lots of exercise — growing in popularity."
17 | Australian Shepherd,"Super smart, active, great for outdoor-loving families."
18 | Doberman Pinscher,"Protective, loyal, and surprisingly gentle family dogs when trained."
19 | Miniature Schnauzer,"Small, smart, hypoallergenic, with a spunky attitude."
20 | American Staffordshire Terrier,"Strong, muscular, and affectionate — often misunderstood but great companions."
21 | Pit Bull,"Loyal, strong, and loving; needs responsible ownership and training."
22 |
--------------------------------------------------------------------------------
/server/models/dog.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from enum import Enum
3 | from . import db
4 | from .base import BaseModel
5 | from sqlalchemy.orm import validates, relationship
6 |
7 | # Define an Enum for dog status
8 | class AdoptionStatus(Enum):
9 | AVAILABLE = 'Available'
10 | ADOPTED = 'Adopted'
11 | PENDING = 'Pending'
12 |
13 | class Dog(BaseModel):
14 | __tablename__ = 'dogs'
15 |
16 | id = db.Column(db.Integer, primary_key=True)
17 | name = db.Column(db.String(100), nullable=False)
18 | breed_id = db.Column(db.Integer, db.ForeignKey('breeds.id'))
19 | age = db.Column(db.Integer)
20 | gender = db.Column(db.String(10))
21 | description = db.Column(db.Text)
22 |
23 | # Adoption status
24 | status = db.Column(db.Enum(AdoptionStatus), default=AdoptionStatus.AVAILABLE)
25 | intake_date = db.Column(db.DateTime, default=datetime.now)
26 | adoption_date = db.Column(db.DateTime, nullable=True)
27 |
28 | @validates('name')
29 | def validate_name(self, key, name):
30 | return self.validate_string_length('Dog name', name, min_length=2)
31 |
32 | @validates('gender')
33 | def validate_gender(self, key, gender):
34 | if gender not in ['Male', 'Female', 'Unknown']:
35 | raise ValueError("Gender must be 'Male', 'Female', or 'Unknown'")
36 | return gender
37 |
38 | @validates('description')
39 | def validate_description(self, key, description):
40 | if description is not None:
41 | return self.validate_string_length('Description', description, min_length=10, allow_none=True)
42 | return description
43 |
44 | def __repr__(self):
45 | return f''
46 |
47 | def to_dict(self):
48 | return {
49 | 'id': self.id,
50 | 'name': self.name,
51 | 'breed': self.breed.name if self.breed else None,
52 | 'age': self.age,
53 | 'gender': self.gender,
54 | 'description': self.description,
55 | 'status': self.status.name if self.status else 'UNKNOWN'
56 | }
--------------------------------------------------------------------------------
/server/models/dogs.csv:
--------------------------------------------------------------------------------
1 | Name,Description,Age,Gender
2 | Max,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",1,Male
3 | Bella,"Energetic and curious, always exploring and eager to meet new friends. Loves outdoor adventures and keeps you on your toes.",9,Male
4 | Charlie,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",15,Male
5 | Lucy,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",5,Male
6 | Cooper,A friendly and playful dog who loves spending time with people and other animals. Always ready for a game of fetch and enjoys long walks.,8,Male
7 | Daisy,"Calm and loving, this dog prefers lounging by your side but still enjoys occasional playtime. Very affectionate and great with families.",15,Female
8 | Buddy,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",2,Male
9 | Luna,"Shy but loving, may take time to warm up but becomes deeply attached once comfortable. A loyal and sweet companion.",5,Male
10 | Rocky,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",4,Male
11 | Sadie,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",12,Male
12 | Milo,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",4,Female
13 | Molly,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",9,Female
14 | Bear,"Energetic and curious, always exploring and eager to meet new friends. Loves outdoor adventures and keeps you on your toes.",13,Male
15 | Bailey,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",7,Male
16 | Duke,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",13,Male
17 | Maggie,"Shy but loving, may take time to warm up but becomes deeply attached once comfortable. A loyal and sweet companion.",10,Female
18 | Tucker,"Energetic and curious, always exploring and eager to meet new friends. Loves outdoor adventures and keeps you on your toes.",2,Male
19 | Chloe,A friendly and playful dog who loves spending time with people and other animals. Always ready for a game of fetch and enjoys long walks.,9,Female
20 | Jack,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",8,Female
21 | Sophie,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",14,Male
22 | Oliver,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",10,Male
23 | Zoey,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",13,Male
24 | Bentley,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",13,Male
25 | Lily,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",6,Female
26 | Jake,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",8,Male
27 | Stella,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",6,Male
28 | Toby,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",9,Male
29 | Penny,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",15,Male
30 | Zeus,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",12,Female
31 | Gracie,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",14,Female
32 | Harley,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",3,Female
33 | Roxy,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",4,Female
34 | Leo,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",15,Male
35 | Abby,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",5,Male
36 | Jax,"Energetic and curious, always exploring and eager to meet new friends. Loves outdoor adventures and keeps you on your toes.",4,Male
37 | Rosie,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",2,Male
38 | Finn,"Calm and loving, this dog prefers lounging by your side but still enjoys occasional playtime. Very affectionate and great with families.",9,Male
39 | Ruby,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",10,Male
40 | Winston,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",3,Male
41 | Ellie,"Shy but loving, may take time to warm up but becomes deeply attached once comfortable. A loyal and sweet companion.",9,Female
42 | Murphy,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",2,Male
43 | Lola,"Calm and loving, this dog prefers lounging by your side but still enjoys occasional playtime. Very affectionate and great with families.",7,Female
44 | Louie,"Shy but loving, may take time to warm up but becomes deeply attached once comfortable. A loyal and sweet companion.",2,Female
45 | Mia,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",4,Female
46 | Henry,"Calm and loving, this dog prefers lounging by your side but still enjoys occasional playtime. Very affectionate and great with families.",8,Female
47 | Nala,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",7,Male
48 | Oscar,"Shy but loving, may take time to warm up but becomes deeply attached once comfortable. A loyal and sweet companion.",7,Male
49 | Pepper,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",9,Female
50 | Sam,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",1,Female
51 | Ginger,A friendly and playful dog who loves spending time with people and other animals. Always ready for a game of fetch and enjoys long walks.,2,Male
52 | Scout,"Calm and loving, this dog prefers lounging by your side but still enjoys occasional playtime. Very affectionate and great with families.",1,Female
53 | Olive,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",10,Male
54 | Dexter,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",3,Male
55 | Harper,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",8,Male
56 | Blue,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",5,Female
57 | Emma,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",6,Female
58 | Buster,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",1,Male
59 | Annie,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",3,Male
60 | Lucky,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",1,Female
61 | Coco,"Energetic and curious, always exploring and eager to meet new friends. Loves outdoor adventures and keeps you on your toes.",5,Female
62 | Moose,A friendly and playful dog who loves spending time with people and other animals. Always ready for a game of fetch and enjoys long walks.,3,Female
63 | Belle,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",8,Female
64 | Thor,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",10,Male
65 | Sasha,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",1,Male
66 | Gus,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",10,Female
67 | Izzy,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",5,Female
68 | George,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",2,Male
69 | Remi,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",9,Female
70 | Boomer,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",5,Female
71 | Ella,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",7,Female
72 | Sammy,"Shy but loving, may take time to warm up but becomes deeply attached once comfortable. A loyal and sweet companion.",8,Male
73 | Willow,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",15,Female
74 | Bruno,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",6,Female
75 | Piper,A friendly and playful dog who loves spending time with people and other animals. Always ready for a game of fetch and enjoys long walks.,6,Male
76 | Shadow,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",10,Female
77 | Riley,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",3,Male
78 | Chance,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",5,Male
79 | Nova,A friendly and playful dog who loves spending time with people and other animals. Always ready for a game of fetch and enjoys long walks.,5,Female
80 | Tank,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",7,Male
81 | Minnie,A friendly and playful dog who loves spending time with people and other animals. Always ready for a game of fetch and enjoys long walks.,9,Female
82 | Rusty,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",3,Male
83 | Millie,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",13,Female
84 | Frankie,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",14,Male
85 | Hazel,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",5,Male
86 | Apollo,"Calm and loving, this dog prefers lounging by your side but still enjoys occasional playtime. Very affectionate and great with families.",14,Male
87 | Holly,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",9,Male
88 | Otis,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",8,Female
89 | Marley,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",13,Male
90 | Ace,"Alert and brave, always ready to protect their home and loved ones. Despite their bravery, they have a soft side for cuddles.",8,Female
91 | Honey,"Gentle and affectionate, always seeking cuddles and attention. Loves to relax but will never say no to a good walk.",10,Female
92 | Chester,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",7,Female
93 | Zoe,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",15,Female
94 | Hunter,"Calm and loving, this dog prefers lounging by your side but still enjoys occasional playtime. Very affectionate and great with families.",8,Male
95 | Callie,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",14,Male
96 | Prince,"Active and fun-loving, always ready to chase a ball or go for a run. Great for owners with an active lifestyle.",1,Male
97 | Missy,"Mischievous but sweet, often found getting into funny trouble around the house. Full of personality and love.",7,Female
98 | Koda,"Loyal and protective, always watching over their loved ones. A perfect companion for someone looking for a devoted friend.",5,Female
99 | Delilah,A friendly and playful dog who loves spending time with people and other animals. Always ready for a game of fetch and enjoys long walks.,8,Female
100 | Ollie,"Calm and loving, this dog prefers lounging by your side but still enjoys occasional playtime. Very affectionate and great with families.",2,Male
101 | Layla,"Smart and attentive, always ready to learn new tricks and please their owner. A quick learner who thrives on mental stimulation.",7,Male
102 |
--------------------------------------------------------------------------------
/server/requirements.txt:
--------------------------------------------------------------------------------
1 | flask
2 | sqlalchemy
3 | flask_sqlalchemy
4 | flask-cors
--------------------------------------------------------------------------------
/server/test_app.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from unittest.mock import patch, MagicMock
3 | import json
4 | from app import app # Changed from relative import to absolute import
5 |
6 | # filepath: server/test_app.py
7 | class TestApp(unittest.TestCase):
8 | def setUp(self):
9 | # Create a test client using Flask's test client
10 | self.app = app.test_client()
11 | self.app.testing = True
12 | # Turn off database initialization for tests
13 | app.config['TESTING'] = True
14 |
15 | def _create_mock_dog(self, dog_id, name, breed):
16 | """Helper method to create a mock dog with standard attributes"""
17 | dog = MagicMock(spec=['to_dict', 'id', 'name', 'breed'])
18 | dog.id = dog_id
19 | dog.name = name
20 | dog.breed = breed
21 | dog.to_dict.return_value = {'id': dog_id, 'name': name, 'breed': breed}
22 | return dog
23 |
24 | def _setup_query_mock(self, mock_query, dogs):
25 | """Helper method to configure the query mock"""
26 | mock_query_instance = MagicMock()
27 | mock_query.return_value = mock_query_instance
28 | mock_query_instance.join.return_value = mock_query_instance
29 | mock_query_instance.all.return_value = dogs
30 | return mock_query_instance
31 |
32 | @patch('app.db.session.query')
33 | def test_get_dogs_success(self, mock_query):
34 | """Test successful retrieval of multiple dogs"""
35 | # Arrange
36 | dog1 = self._create_mock_dog(1, "Buddy", "Labrador")
37 | dog2 = self._create_mock_dog(2, "Max", "German Shepherd")
38 | mock_dogs = [dog1, dog2]
39 |
40 | self._setup_query_mock(mock_query, mock_dogs)
41 |
42 | # Act
43 | response = self.app.get('/api/dogs')
44 |
45 | # Assert
46 | self.assertEqual(response.status_code, 200)
47 |
48 | data = json.loads(response.data)
49 | self.assertEqual(len(data), 2)
50 |
51 | # Verify first dog
52 | self.assertEqual(data[0]['id'], 1)
53 | self.assertEqual(data[0]['name'], "Buddy")
54 | self.assertEqual(data[0]['breed'], "Labrador")
55 |
56 | # Verify second dog
57 | self.assertEqual(data[1]['id'], 2)
58 | self.assertEqual(data[1]['name'], "Max")
59 | self.assertEqual(data[1]['breed'], "German Shepherd")
60 |
61 | # Verify query was called
62 | mock_query.assert_called_once()
63 |
64 | @patch('app.db.session.query')
65 | def test_get_dogs_empty(self, mock_query):
66 | """Test retrieval when no dogs are available"""
67 | # Arrange
68 | self._setup_query_mock(mock_query, [])
69 |
70 | # Act
71 | response = self.app.get('/api/dogs')
72 |
73 | # Assert
74 | self.assertEqual(response.status_code, 200)
75 | data = json.loads(response.data)
76 | self.assertEqual(data, [])
77 |
78 | @patch('app.db.session.query')
79 | def test_get_dogs_structure(self, mock_query):
80 | """Test the response structure for a single dog"""
81 | # Arrange
82 | dog = self._create_mock_dog(1, "Buddy", "Labrador")
83 | self._setup_query_mock(mock_query, [dog])
84 |
85 | # Act
86 | response = self.app.get('/api/dogs')
87 |
88 | # Assert
89 | data = json.loads(response.data)
90 | self.assertTrue(isinstance(data, list))
91 | self.assertEqual(len(data), 1)
92 | self.assertEqual(set(data[0].keys()), {'id', 'name', 'breed'})
93 |
94 |
95 | if __name__ == '__main__':
96 | unittest.main()
--------------------------------------------------------------------------------
/server/utils/seed_database.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import os
3 | import sys
4 | import random
5 | from datetime import datetime, timedelta
6 | from collections import defaultdict
7 |
8 | # Add the parent directory to sys.path to allow importing from models
9 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
10 |
11 | from flask import Flask
12 | from models import init_db, db, Breed, Dog
13 | from models.dog import AdoptionStatus
14 |
15 | def create_app():
16 | """Create and configure Flask app for database operations"""
17 | app = Flask(__name__)
18 |
19 | # Get the server directory path (one level up from utils)
20 | server_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
21 |
22 | app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{os.path.join(server_dir, "dogshelter.db")}'
23 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
24 |
25 | # Initialize the database with the app
26 | init_db(app)
27 |
28 | return app
29 |
30 | def create_breeds():
31 | """Seed the database with breeds from the CSV file"""
32 | app = create_app()
33 |
34 | # Path to the CSV file
35 | csv_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
36 | 'models', 'breeds.csv')
37 |
38 | with app.app_context():
39 | # Check if breeds already exist
40 | existing_breeds = Breed.query.count()
41 | if existing_breeds > 0:
42 | print(f"Database already contains {existing_breeds} breeds. Skipping seed.")
43 | return
44 |
45 | # Read the CSV file and add breeds to the database
46 | with open(csv_path, 'r') as file:
47 | csv_reader = csv.DictReader(file)
48 | for row in csv_reader:
49 | breed = Breed(name=row['Breed'], description=row['Description'])
50 | db.session.add(breed)
51 |
52 | # Commit the changes
53 | db.session.commit()
54 |
55 | # Verify the seeding
56 | breed_count = Breed.query.count()
57 | print(f"Successfully seeded {breed_count} breeds to the database.")
58 |
59 | def create_dogs():
60 | """Seed the database with dogs from the CSV file, ensuring at least 3 dogs per breed"""
61 | app = create_app()
62 |
63 | # Path to the CSV file
64 | csv_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
65 | 'models', 'dogs.csv')
66 |
67 | with app.app_context():
68 | # Check if dogs already exist
69 | existing_dogs = Dog.query.count()
70 | if existing_dogs > 0:
71 | print(f"Database already contains {existing_dogs} dogs. Skipping seed.")
72 | return
73 |
74 | # Get all breeds from the database
75 | breeds = Breed.query.all()
76 | if not breeds:
77 | print("No breeds found in database. Please seed breeds first.")
78 | return
79 |
80 | # Track how many dogs are assigned to each breed
81 | breed_counts = defaultdict(int)
82 |
83 | # Read the CSV file
84 | dogs_data = []
85 | with open(csv_path, 'r') as file:
86 | csv_reader = csv.DictReader(file)
87 | for row in csv_reader:
88 | dogs_data.append(row)
89 |
90 | def create_dog(dog_info, breed_id):
91 | """Helper function to create a dog with consistent attributes"""
92 | dog = Dog(
93 | name=dog_info['Name'],
94 | description=dog_info['Description'],
95 | breed_id=breed_id,
96 | age=int(dog_info['Age']),
97 | gender=dog_info['Gender'],
98 | status=random.choice(list(AdoptionStatus)),
99 | intake_date=datetime.now() - timedelta(days=random.randint(1, 365))
100 | )
101 | db.session.add(dog)
102 | breed_counts[breed_id] += 1
103 | return dog
104 |
105 | # First pass: assign at least 3 dogs to each breed
106 | for breed in breeds:
107 | # Get 3 random dogs that haven't been assigned yet
108 | for _ in range(3):
109 | if not dogs_data:
110 | break
111 |
112 | dog_info = random.choice(dogs_data)
113 | dogs_data.remove(dog_info)
114 |
115 | create_dog(dog_info, breed.id)
116 |
117 | # Second pass: assign remaining dogs randomly
118 | for dog_info in dogs_data:
119 | breed = random.choice(breeds)
120 | create_dog(dog_info, breed.id)
121 |
122 | # Commit all the changes
123 | db.session.commit()
124 |
125 | # Verify the seeding
126 | dog_count = Dog.query.count()
127 | print(f"Successfully seeded {dog_count} dogs to the database.")
128 |
129 | # Print distribution of dogs across breeds
130 | for breed in breeds:
131 | count = breed_counts[breed.id]
132 | print(f"Breed '{breed.name}': {count} dogs")
133 |
134 | def seed_database():
135 | """Run all seeding functions in the correct order"""
136 | create_breeds()
137 | create_dogs()
138 |
139 | if __name__ == '__main__':
140 | seed_database()
--------------------------------------------------------------------------------