├── .devcontainer └── devcontainer.json ├── .github ├── steps │ ├── 1-preparing.md │ ├── 2-first-introduction.md │ ├── 3-copilot-edits.md │ ├── 3b-copilot-agent-mode.md │ ├── 4-copilot-on-github.md │ └── x-review.md └── workflows │ ├── 0-start-exercise.yml │ ├── 1-preparing.yml │ ├── 2-first-introduction.yml │ ├── 3-copilot-edits.yml │ ├── 3b-copilot-agent-mode.yml │ ├── 4-copilot-on-github.yml │ └── 4b-copilot-on-github.yml ├── .gitignore ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── requirements.txt └── src ├── README.md ├── app.py └── static ├── app.js ├── index.html └── styles.css /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Python 3", 3 | "image": "mcr.microsoft.com/vscode/devcontainers/python:3.13", 4 | "forwardPorts": [8000], 5 | "postCreateCommand": "pip install -r requirements.txt", 6 | "customizations": { 7 | "vscode": { 8 | "extensions": [ 9 | "GitHub.copilot", 10 | "ms-python.python", 11 | "ms-python.debugpy" 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/steps/1-preparing.md: -------------------------------------------------------------------------------- 1 | ## Step 1: Hello Copilot 2 | 3 | Welcome to your **"Getting Started with GitHub Copilot"** exercise! :robot: 4 | 5 | In this exercise, you will be using different GitHub Copilot features to work on a website that allows students of Mergington High School to sign up for extracurricular activities. 🎻 ⚽️ ♟️ 6 | 7 | screenshot of Mergington High School WebApp 8 | 9 | ### What is GitHub Copilot? 10 | 11 | copilot logo 12 | 13 | GitHub Copilot is an AI coding assistant that helps you write code faster and with less effort, allowing you to focus more energy on problem solving and collaboration. 14 | 15 | GitHub Copilot has been proven to increase developer productivity and accelerate the pace of software development. For more information, see [Research: quantifying GitHub Copilot’s impact on developer productivity and happiness in the GitHub blog.](https://github.blog/news-insights/research/research-quantifying-github-copilots-impact-on-developer-productivity-and-happiness/) 16 | 17 | Your most common interactions will likely be: 18 | 19 | - **Inline suggestions**: As you type, Copilot uses the nearby context to suggest code directly in your editor. This will be a familiar interaction if you have used code completion tools like [Intellisense](https://code.visualstudio.com/docs/editor/intellisense), except that the completions may be entire functions. 20 | - **Copilot - Ask Mode**: A dedicated chat panel that lets you ask coding related questions. This will feel familiar if you have used online AI assistant chats. The big difference however, is that your project files will provide automatic context to provide tailored responses. 21 | - **Copilot - Edit Mode**: Similar to Ask mode, but less conversational. Copilot will make changes to your selected files to implement your request. 22 | - **Copilot - Agent Mode**: Copilot will run iteratively until it achieves your request. It will select context, make code changes, run terminal commands, run tools, and most importantly review its work to make adjustments. 23 | 24 | > [!TIP] 25 | > You can learn more about current and upcoming features in the [GitHub Copilot Features](https://docs.github.com/en/copilot/about-github-copilot/github-copilot-features) documentation. You can also select different [models](https://docs.github.com/en/github-models) and make your own [extensions](https://github.com/features/copilot/extensions), but that's for a different lesson! 26 | 27 | ### How can I use GitHub Copilot? 28 | 29 | As you work, you'll find GitHub Copilot can help out in several places across the website and in your favorite coding environments such as VS Code, Jet Brains, and Xcode! For today's coding though, we will practice with VS Code in a pre-configured development environment known as [Codespace](https://github.com/features/codespaces). 30 | 31 | ### :keyboard: Activity: Get a project intro from Copilot Chat 32 | 33 | Let's start up our development environment, use copilot to learn a bit about the project, and then give it a test run. 34 | 35 | 1. Left-click the below button to open the **Create Codespace** page in a new tab. Use the default configuration. 36 | 37 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/{{full_repo_name}}?quickstart=1) 38 | 39 | 1. Confirm the **Repository** field is your copy of the exercise, not the original, then click the green **Create Codespace** button. 40 | 41 | - ✅ Your copy: `/{{{full_repo_name}}}` 42 | - ❌ Original: `/skills/getting-started-with-github-copilot` 43 | 44 | 1. Wait a moment for Visual Studio Code to load in your browser. 45 | 46 | 1. In the left sidebar, click the extensions tab and verify that the `GitHub Copilot` and `Python` extensions are installed and enabled. 47 | 48 | copilot extension for VS Code 49 | 50 | python extension for VS Code 51 | 52 | 1. At the top of VS Code, locate and click the **Copilot icon** to open a Copilot Chat panel. 53 | 54 | image 55 | 56 | 1. If this is your first time using GitHub Copilot, you will need to accept the usage terms to continue. 57 | 58 | 1. Enter the below prompt to ask Copilot to introduce you to the project. 59 | 60 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 61 | > 62 | > ```prompt 63 | > @workspace Please briefly explain the structure of this project. 64 | > What should I do to run it? 65 | > ``` 66 | 67 | > **Note**: It is not necessary to follow Copilot's recommended instructions. We have already prepared the environment for you. 68 | 69 |
70 | What is @workspace? 71 | Nice job noticing the details, but let's just use it for now. 🤓 We promise to explain in the next step. 72 |
73 | 74 | 1. Now that we know a bit more about the project, let's actually try running it! In the left sidebar, select the `Run and Debug` tab and then press the **Start Debugging** icon. 75 | 76 | image 77 | 78 | 1. We want to see our webpage running in a browser, so let's find the url and port. If it isn't visible, expand the lower panel and select the **Ports** tab. 79 | 80 | 1. In the list, find port `8000` and the related link. Hover over the link and select the **Open in browser** icon. 81 | 82 | ![image](https://github.com/user-attachments/assets/92d5642e-ce99-4a66-850c-2d311a673596) 83 | 84 | ### :keyboard: Activity: Use Copilot to help remember a terminal command 🙋 85 | 86 | Great work! Now that we are familiar with the app and we know it works, let's ask copilot for help starting a branch so we can do some customizing. 87 | 88 | 1. If not already there, return to VS Code. 89 | 90 | 1. In the bottom panel, select the **Terminal** tab. On the right side, click the plus `+` sign to create a new terminal window. 91 | 92 | > **Note:** This will avoid stopping the existing debug session that is hosting our web application service. 93 | 94 | 1. Within the new terminal window use the keyboard shortcut `Ctrl + I` (windows) or `Cmd + I` (mac) to bring up **Copilot's Terminal Inline Chat**. 95 | 96 | 1. Let's ask Copilot to help us remember a command we have forgotten: creating a branch and publishing it. 97 | 98 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 99 | > 100 | > ```prompt 101 | > Hey copilot, how can I create and publish a new Git branch? 102 | > ``` 103 | 104 | > **Tip:** This is a simple example, but Copilot is great at providing more tailored commands that might involve loops, pattern matching, file modification, and more! Don't be afraid to ask Copilot for a suggestion. Just remember it is a suggestion and you should always verify it first to be safe. 105 | 106 | 1. Copilot probably gave us a command like the following. Rather than manually modify it, let's respond back to tell Copilot to use a particular name. 107 | 108 | ```bash 109 | git checkout -b {new_branch_name} 110 | git push -u origin {new_branch_name} 111 | ``` 112 | 113 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 114 | > 115 | > ```prompt 116 | > Awesome! Thanks, Copilot! Let's use the 117 | > branch name "accelerate-with-copilot". 118 | > ``` 119 | 120 | > **Tip:** If Copilot doesn't give you quite what you want, you can always continue explaining what you need. Copilot will remember the conversation history for follow-up responses. 121 | 122 | 1. Now that we are happy with the command, press the `Run` button to let Copilot run it for us. No need to copy and paste! 123 | 124 | 1. After a moment, look in the VS Code lower status bar, on the left, to see the active branch. It should now say `accelerate-with-copilot`. If so, you are all done with this step! 125 | 126 | 1. Now that your branch is pushed to GitHub, Mona should already be busy checking your work. Give her a moment and keep watch in the comments. You will see her respond with progress info and the next lesson. 127 | 128 |
129 | Having trouble? 🤷
130 | 131 | If you don't get feedback, here are some things to check: 132 | 133 | - Make sure your created the branch with the exact name `accelerate-with-copilot`. No prefixes or suffixes. 134 | - Make sure the branch was indeed published to your repository. 135 | 136 |
137 | -------------------------------------------------------------------------------- /.github/steps/2-first-introduction.md: -------------------------------------------------------------------------------- 1 | ## Step 2: Getting work done with Copilot 2 | 3 | In the previous step, GitHub Copilot was able to help us onboard to the project. That alone is a huge time saver, but now let's get some work done! 4 | 5 | We recently learned there is a bug where students are registering for the same activities twice. That simply isn't acceptable, so let's get it fixed! 6 | 7 | Unfortunately, we were given little information to solve this problem. So, let's enlist Copilot to help find the problem area and get a potential solution made. 8 | 9 | But before we do that, let's learn a bit more about Copilot! 🧑‍🚀 10 | 11 | ### How does Copilot work? 12 | 13 | In short, you can think of Copilot like a very specialized coworker. To be effective with them, you need to provide them background (context) and clear direction (prompts). Additionally, different people are better at different things because of their unique experiences (models). 14 | 15 | - **How do we provide context?:** In our coding environment, Copilot will automatically consider nearby code and open tabs. If you are using chat, you can also explicitly refer to files. 16 | 17 | - **What model should we pick?:** For our exercise, it shouldn't matter too much. Experimenting with different models is part of the fun! That's another lesson! 🤖 18 | 19 | - **How do I make prompts?:** Being explicit and clear helps Copilot do the best job. But unlike some traditional systems, you can always clarify your direction with followup prompts. 20 | 21 | > [!TIP] 22 | > There several other ways to supplement Copilot's knowledge and capabilities like [chat participants](https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/github-copilot-chat-cheat-sheet?tool=vscode#chat-participants), [chat variables](https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/github-copilot-chat-cheat-sheet?tool=vscode#chat-variables), [slash commands](https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/github-copilot-chat-cheat-sheet?tool=vscode#slash-commands-1), and [MCP tools](https://code.visualstudio.com/docs/copilot/chat/mcp-servers). 23 | 24 | ### :keyboard: Activity: Use Copilot to fix our registration bug :bug: 25 | 26 | 1. Let's ask Copilot to suggest where our bug might be coming from. Open the **Copilot Chat** panel in **Ask mode** and ask the following. 27 | 28 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 29 | > 30 | > ```prompt 31 | > @workspace Students are able to register twice for an activity. 32 | > Where could this bug be coming from? 33 | > ``` 34 | 35 |
36 | What is @workspace? 37 | 38 | Great question! This is a specialized [chat participant](https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/github-copilot-chat-cheat-sheet?tool=vscode#chat-participants) that will explore the project repository and try to include relevant additional context. 39 | 40 |
41 | 42 | 1. Now that we know the issue is in the `src/app.py` file and the `signup_for_activity` method, let's follow Copilot's recommendation and go fix it (semi-manually). We'll start with a comment and let Copilot finish the correction. 43 | 44 | 1. In VS Code, select the file **Explorer tab** to show the project files and open the `src/app.py` file. 45 | 46 | 1. Scroll near the bottom of the file and find the `signup_for_activity` method. 47 | 48 | 1. Find the comment line that describes adding a student. Above this is where it seems logical to do our registration check. 49 | 50 | 1. Enter the below comment and press enter to go to the next line. After a moment, temporary shadow text will appear with a suggestion from Copilot! Nice! :tada: 51 | 52 | ```python 53 | # Validate student is not already signed up 54 | ``` 55 | 56 | 1. Press `Tab` to accept Copilot's suggestion and convert the shadow text to code. 57 | 58 | > **Tip:** If you would like to see other suggestions, instead of pressing `Tab`, hover over the shadow text suggestion and a toolbar will appear. Use the arrows to select other suggestions or the three dots `...` and `Open Completions Panel` option to show all suggestions in a dedicated panel. 59 | 60 |
61 | Example Results
62 | 63 | Copilot is growing every day and may not always produce the same results. If you are unhappy with the suggestions, here is an example of a valid suggestion result we produced during the making of this exercise. You can use it to continue forward. 64 | 65 | ```python 66 | @app.post("/activities/{activity_name}/signup") 67 | def signup_for_activity(activity_name: str, email: str): 68 | """Sign up a student for an activity""" 69 | # Validate activity exists 70 | if activity_name not in activities: 71 | raise HTTPException(status_code=404, detail="Activity not found") 72 | 73 | # Get the activity 74 | activity = activities[activity_name] 75 | 76 | # Validate student is not already signed up 77 | if email in activity["participants"]: 78 | raise HTTPException(status_code=400, detail="Student is already signed up") 79 | 80 | # Add student 81 | activity["participants"].append(email) 82 | return {"message": f"Signed up {email} for {activity_name}"} 83 | ``` 84 | 85 |
86 | 87 | ### :keyboard: Activity: Let Copilot generate sample data 📋 88 | 89 | In new project developments, it's often helpful to have some realistic looking fake data for testing. Copilot is excellent at this task, so let's add some more sample activities and introduce another way to interact with Copilot using **Inline Chat** 90 | 91 | **Inline Chat** and the **Copilot Chat** panel are very similar tools, but with slightly different automatic context. As such, while Copilot Chat is good at explaining about the project, inline chat might feel more natural for asking about a particular line or function. 92 | 93 | 1. If not already open, open the `src/app.py` file. 94 | 95 | 1. Near the top (about line 23), find the `activities` variable, where our example extracurricular activities are configured. 96 | 97 | 1. Click on any of the related lines and bring up Copilot inline chat by using the keyboard command `Ctrl + I` (windows) or `Cmd + I` (mac). 98 | 99 | > **Tip:** Another way to bring up Copilot inline chat is: `right click` on any of the selected lines -> `Copilot` -> `Editor Inline Chat`. 100 | 101 | 1. Enter the following prompt text and press enter or the **Send and Dispatch** button. 102 | 103 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 104 | > 105 | > ```prompt 106 | > Add 2 more sports related activities, 2 more artistic 107 | > activities, and 2 more intellectual activities. 108 | > ``` 109 | 110 | 1. After a moment, Copilot will directly start making changes to the code. The changes will be stylized differently to make any additions and removals easy to identify. Take a moment to inspect and then press the **Accept** button. 111 | 112 |
113 | Example Results
114 | 115 | Copilot is growing every day and may not always produce the same results. If you are unhappy with the suggestions, here is an example result we produced during the making of this exercise. You can use it to continue forward, if having trouble. 116 | 117 | ```python 118 | # In-memory activity database 119 | activities = { 120 | "Chess Club": { 121 | "description": "Learn strategies and compete in chess tournaments", 122 | "schedule": "Fridays, 3:30 PM - 5:00 PM", 123 | "max_participants": 12, 124 | "participants": ["michael@mergington.edu", "daniel@mergington.edu"] 125 | }, 126 | "Programming Class": { 127 | "description": "Learn programming fundamentals and build software projects", 128 | "schedule": "Tuesdays and Thursdays, 3:30 PM - 4:30 PM", 129 | "max_participants": 20, 130 | "participants": ["emma@mergington.edu", "sophia@mergington.edu"] 131 | }, 132 | "Gym Class": { 133 | "description": "Physical education and sports activities", 134 | "schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM", 135 | "max_participants": 30, 136 | "participants": ["john@mergington.edu", "olivia@mergington.edu"] 137 | }, 138 | "Basketball Team": { 139 | "description": "Competitive basketball training and games", 140 | "schedule": "Tuesdays and Thursdays, 4:00 PM - 6:00 PM", 141 | "max_participants": 15, 142 | "participants": [] 143 | }, 144 | "Swimming Club": { 145 | "description": "Swimming training and water sports", 146 | "schedule": "Mondays and Wednesdays, 3:30 PM - 5:00 PM", 147 | "max_participants": 20, 148 | "participants": [] 149 | }, 150 | "Art Studio": { 151 | "description": "Express creativity through painting and drawing", 152 | "schedule": "Wednesdays, 3:30 PM - 5:00 PM", 153 | "max_participants": 15, 154 | "participants": [] 155 | }, 156 | "Drama Club": { 157 | "description": "Theater arts and performance training", 158 | "schedule": "Tuesdays, 4:00 PM - 6:00 PM", 159 | "max_participants": 25, 160 | "participants": [] 161 | }, 162 | "Debate Team": { 163 | "description": "Learn public speaking and argumentation skills", 164 | "schedule": "Thursdays, 3:30 PM - 5:00 PM", 165 | "max_participants": 16, 166 | "participants": [] 167 | }, 168 | "Science Club": { 169 | "description": "Hands-on experiments and scientific exploration", 170 | "schedule": "Fridays, 3:30 PM - 5:00 PM", 171 | "max_participants": 20, 172 | "participants": [] 173 | } 174 | } 175 | ``` 176 | 177 |
178 | 179 | ### :keyboard: Activity: Use Copilot to describe our work 💬 180 | 181 | Nice work fixing that bug and expanding the example activities! Now let's get our work committed and pushed to GitHub, again with the help of Copilot! 182 | 183 | 1. In the left sidebar, select the `Source Control` tab. 184 | 185 | > **Tip:** Opening a file from the source control area will show the differences to the original rather than simply opening it. 186 | 187 | 1. Find the `app.py` file and press the `+` sign to collect your changes together in the staging area. 188 | 189 | ![image](https://github.com/user-attachments/assets/7d3daf4e-4125-4775-88a7-33251cd7293e) 190 | 191 | 1. Above the list of staged changes, find the **Message** text box, but **don't enter anything** for now. 192 | 193 | - Typically, you would write a short description of the changes here, but now we have Copilot to help out! 194 | 195 | 1. To the right of the **Message** text box, find and click the **Generate Commit Message with Copilot** button (sparkles icon). 196 | 197 | 1. Press the **Commit** button and **Sync Changes** button to push your changes to GitHub. 198 | 199 | 1. Wait a moment for Mona to check your work, provide feedback, and share the next lesson. 200 | 201 |
202 | Having trouble? 🤷
203 | 204 | If you don't get feedback, here are some things to check: 205 | 206 | - Make sure your pushed the `src/app.py` file changes to the branch `accelerate-with-copilot`. 207 | 208 |
209 | -------------------------------------------------------------------------------- /.github/steps/3-copilot-edits.md: -------------------------------------------------------------------------------- 1 | ## Step 3: Getting work done even _faster_ with Copilot Edits 2 | 3 | In our previous steps, we used features of Copilot that require more hands-on guidance and they produced mostly localized results. Now, we will explore Copilot Edits, a feature that allows working more holistically on our repo. 4 | 5 | [Copilot - Edit Mode](https://code.visualstudio.com/docs/copilot/copilot-edits) is an AI-powered code editing session to make changes across **multiple files** using **natural language**, and applies the edits directly in the editor, where you can review them in-place, with the full context of the surrounding code. 6 | 7 | #### Key features 8 | 9 | - **Multi-file Editing**: Copilot Edits can make changes across multiple files in your workspace. 10 | - **Iterative Workflow**: Designed for fast iteration, allowing you to review, accept, or discard AI-generated code. 11 | - **In-place Edits**: Shows generated code directly in your editor, providing a code review-like flow. 12 | - **Working Set**: Allows you to define which files the edits should be applied to. 13 | 14 | #### How it works 15 | 16 | 1. **Set Context**: Select files to be in the working set. 17 | 1. **Provide Instructions**: Use natural language to describe the required changes. 18 | 1. **Review Changes**: See proposed changes in-place in your code. 19 | 1. **Accept or Discard**: Review each suggested edit and choose which to keep. 20 | 1. **Iterate**: If needed, provide follow-up instructions to refine the changes. 21 | 22 | ### :keyboard: Activity: Use Copilot to add a new feature! :rocket: 23 | 24 | 1. If the Copilot Chat panel is not visible, please reopen it. 25 | 26 | 1. At the bottom of Copilot Chat window, use the dropdown to switch to **Edit** mode. 27 | 28 | image 29 | 30 | 1. Open the files related to our webpage then drag each editor window (or file) to the chat panel, informing Copilot to use them as context. 31 | 32 | - `src/static/app.js` 33 | - `src/static/index.html` 34 | - `src/static/styles.css` 35 | 36 | > **Tip:** You can also use the **Add Context...** button to provide other sources of context items, like a GitHub issue, the entire codebase, or the results of a terminal window. 37 | 38 | 1. Ask Copilot to update our project to display the current participants of activities. Wait a moment for the edit suggestions to arrive and be applied. 39 | 40 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 41 | > 42 | > ```prompt 43 | > Hey Copilot, can you please edit the activity cards to add a participants section. 44 | > It will show what participants that are already signed up for that activity as a bulleted list. 45 | > Remember to make it pretty! 46 | > ``` 47 | 48 | - An extra icon has appeared next to the file names and open editor windows indicating they have suggested edits. 49 | - A suggested edits panel has appeared in the bottom right of the editor window providing controls to jump to the recommended changes. 50 | 51 | files with icons indicating they have been edited 52 | 53 | edit navigation panel 54 | 55 |
56 | Need help? 🤷
57 | 58 | Remember, to add the relevant files to the working set. 59 | 60 | ![screenshot of working set](https://github.com/user-attachments/assets/d3eadc8e-583e-4a28-9e82-be128eab843b) 61 | 62 |
63 | 64 | 1. Before we simply accept the changes, please check our website again and verify everything is updated as expected. Here is an example of an updated activity card. You may need to restart the app or refresh the page. 65 | 66 | Activity card with participant info 67 | 68 | > **Note:** Your activity card may look different. Copilot won't always produce the same results. 69 | 70 |
71 | Need help? 🤷
72 | If the website is not loading, here are some things to check. 73 | 74 | - Restart the VS Code Debugger to make sure the latest version of the website is served. 75 | - If you forgot the url, or closed the window, please review step 1. 76 | - Try hard refreshing the webpage or opening in a private window so it downloads a fresh copy. 77 | 78 |
79 | 80 | 1. Now that we have confirmed our changes are good, use the panel to cycle through each suggested edit and press **Keep** to apply the change. 81 | 82 | > **Tip:** You can accept the changes directly, modify them, or provide additional instruction to refine them using the chat interface. 83 | 84 | 1. With our new feature complete, please **commit** and **push** the changes to GitHub. 85 | 86 | 1. Wait a moment for Mona to check your work, provide feedback, and share the final lesson. Almost done! 87 | 88 | 1. (optional) If you would like an ungraded bonus step to briefly introduce Agent mode, **add an issue comment** asking **@professortocat** about Copilot Agent mode. 🚀 89 | 90 | ```txt 91 | Hey @professortocat, Agent mode sounds pretty cool. Can you please tell me more about it? 92 | ``` 93 | 94 |
95 | Having trouble? 🤷
96 | 97 | If you don't get feedback, here are some things to check: 98 | 99 | - Make sure your commit the changes in the `src/static/` directory to the branch `accelerate-with-copilot` and pushed/synchronized to GitHub. 100 | - If Mona found a mistake, simply make a correction and push your changes again. Mona will check your work as many times as needed. 101 | 102 |
103 | -------------------------------------------------------------------------------- /.github/steps/3b-copilot-agent-mode.md: -------------------------------------------------------------------------------- 1 | ### :keyboard: Bonus Activity - GitHub Copilot Agent Mode 2 | 3 | > [!NOTE] 4 | > This activity is optional and not graded. 5 | 6 | ### What is "Agent" Mode? 7 | 8 | **Agent** mode enhances Copilot by automatically providing it feedback, typically the types of feedback you would provide after reviewing Copilot's suggested edits. 9 | 10 | **Agent** mode gives Copilot a feedback loop, enabling it to inspect its own results for issues, bugs, inconsistency, etc. in the code and even the terminal! This allows it to automatically revise its work in many situations. Similarly this means **Agent** mode can 11 | typically handle more complex and multi-step tasks. 12 | 13 | That's just a brief intro and there is much more to learn, but that's for a dedicated future exercise. (hint) 14 | 15 | Now, let's give **Agent** mode a try! 👩‍🚀 16 | 17 | ### :keyboard: Activity: Use Agent mode to add functional "unregister" buttons 18 | 19 | Let's experiment with some more open-ended requests that will add more functionality to our web application. Remember, AI assistants often produce different results, even if the same prompt is provided. If you don't get the desired results, you can try other models or provided followup feedback to refine the results. 20 | 21 | 1. Open the **Copilot** chat panel and use the dropdown menu to switch to **Agent** mode. 22 | 23 | image 24 | 25 | 1. Time for our test! Let's ask Copilot to add functionality for removing participants. 26 | 27 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 28 | > 29 | > ```prompt 30 | > #codebase Please add a delete icon next to each participant and hide the bullet points. 31 | > When clicked, it will unregister that participant from the activity. 32 | > ``` 33 | 34 | - If you try this prompt in **Edit** mode, you will probably find that the changes to the frontend and backend were made in a theoretical way. Although no syntax or runtime errors occurred, the changes were not compatible and didn't achieve the goal. 35 | - In **Agent** mode, Copilot reviewed its own work and refined it to ensure all changes were error free and coordinated together. 36 | 37 | 1. When Copilot is finished, restart the debugger and inspect the results. If you like the results, press the **Keep** button. If not, try providing Copilot some feedback to refined the results. 38 | 39 | 1. Ask Copilot to fix a registration bug. 40 | 41 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 42 | > 43 | > ```prompt 44 | > #codebase I've noticed there seems to be a bug. 45 | > When a participant is registered, the page must be refreshed to see the change on the activity. 46 | > ``` 47 | 48 | - If you try this prompt in **Edit** mode, it may or may not work. 49 | 50 | 1. When Copilot is finished, inspect the results. If you like the results, press the **Keep** button. If not, try providing Copilot some feedback. 51 | 52 | ### :keyboard: Activity: Use Agent mode to change the database! 🧑‍🚀 53 | 54 | Just for fun, let's try something even more difficult and open-ended to see what happens! 55 | 56 | > [!TIP] 57 | > In our experiments, we got working results most of the time, but not every time. 58 | > You might try other models or pausing to provide Copilot feedback. 59 | 60 | 1. (optional) If it is available for you, you might try another model such as `Claude 3.5 Sonnet`. 61 | 62 | image 63 | 64 | 1. Ask Copilot to install a local database service. 65 | 66 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 67 | > 68 | > ```prompt 69 | > Please install a local mongodb server for development reasons. 70 | > Afterward, run a command that lists the collections to verify the service is active and working. 71 | > Do not modify our program yet. 72 | > ``` 73 | 74 | - We purposely made the default development environment not ready for installing a local MongoDB server. 75 | - You will see Copilot make mistakes, analyze the error messages, and ask to run various extra commands to make the environment suitable. Nice! 76 | 77 | 1. Ask Copilot to change our app to use the database service. 🤯 78 | 79 | > ![Static Badge](https://img.shields.io/badge/-Prompt-text?style=social&logo=github%20copilot) 80 | > 81 | > ```prompt 82 | > #codebase I don't like that we are storing the data in memory. 83 | > Let's switch to using mongodb. 84 | > For now use the local development instance. 85 | > Please pre-populate the database with the existing hardcoded json activities, keeping the activity name as the key. 86 | > ``` 87 | 88 | 1. That's your preview for now. We hope it was fun and please check back soon on the [Skills page](https://skills.github.com) for a dedicated exercise to explore even more of Agent Mode! 🧑‍🚀 🚀 89 | -------------------------------------------------------------------------------- /.github/steps/4-copilot-on-github.md: -------------------------------------------------------------------------------- 1 | ## Step 4: Using GitHub Copilot within a pull request 2 | 3 | Congratulations! You are finished with coding for this exercise (and VS Code). Now it's time to merge our work. :tada: To wrap up, let's learn about two limited-access Copilot features that can speed up our pull requests! 4 | 5 | #### Copilot pull request summaries 6 | 7 | Typically, you would review your notes and commit messages then summarize them for your pull request description. This may take some time, especially if commit messages are inconsistent or code is not documented well. Fortunately, Copilot can consider all changes in the pull request and provide the important highlights, and with references too! 8 | 9 | > [!NOTE] 10 | > This feature is not available in **GitHub Copilot Free**. [[docs]](https://docs.github.com/en/enterprise-cloud@latest/copilot/using-github-copilot/using-github-copilot-for-pull-requests/creating-a-pull-request-summary-with-github-copilot) 11 | 12 | #### Copilot code review 13 | 14 | More eyes on our work is always useful so let's ask Copilot to do a first pass before we do a normal peer review process. Copilot is great at catching common mistakes that are fixed by simple adjustments, but please remember to use it responsibly. 15 | 16 | > [!NOTE] 17 | > This feature is not available in **GitHub Copilot Free**. [[docs]](https://docs.github.com/en/copilot/using-github-copilot/code-review/using-copilot-code-review) 18 | 19 | ### :keyboard: Activity: Summarize and review a PR with Copilot 20 | 21 | Both **Copilot pull request summaries** and **Copilot code review** have limited access, so this activity is mostly optional. If you have access, Mona will gladly check your work though! If not, you can skip the optional steps. 22 | 23 | 1. In a web browser, open another tab and navigate to your exercise repository. 24 | 25 | 1. You might notice a **notification banner** suggesting to create a new pull request. Click that or use the **Pull Requests** tab at the top to create a new pull request. Please use the following details: 26 | 27 | - **base:** `main` 28 | - **compare:** `accelerate-with-copilot` 29 | - **title:** `Add registration validation and more activities` 30 | 31 | 1. (Optional) In the **Add a description** area, enter edit mode if needed, then click the **Copilot actions** icon and **Summary** action. After a moment, Copilot will add a description. :memo: 32 | 33 | Copilot summarize button 34 | 35 | 1. (Optional) In the right side information panel at the top, locate the **Reviewers** section and click the **Request** button next to a **Copilot icon**. Wait a moment for Copilot to add a review comment to your pull request! 36 | 37 | Copilot review button 38 | 39 | > **Tip:** Notice a log entry that Copilot was requested for a review. 40 | 41 | 1. At the bottom, press the **Merge pull request** button. Nice work! You are all done! :tada: 42 | 43 | 1. Wait a moment for Mona to check your work, provide feedback, and post a final review of this lesson! 44 | -------------------------------------------------------------------------------- /.github/steps/x-review.md: -------------------------------------------------------------------------------- 1 | ## Review 2 | 3 | _Congratulations, you've completed this exercise and learned a lot about GitHub Copilot!_ 4 | 5 | celebrate 6 | 7 | Here's a recap of your accomplishments: 8 | 9 | - Set up your GitHub Codespace and environment. 10 | - Learned how to use Copilot inline suggestions, Chat, and Edits. 11 | - Used Copilot to generate commit messages and pull request summaries. 12 | - Learned how to request Copilot to review your code. 13 | 14 | ### What's next? 15 | 16 | - Continue working on the project 17 | - Use Copilot to add a function for students to unregister from an activity. 18 | - Use Copilot to fix issues found during a pull request review. 19 | - Use Copilot to generate tests and documentation. 20 | - Use Copilot with different models. 21 | - Check out the other [GitHub Skills exercises](https://skills.github.com). 22 | - Learn how to [Integrate MCP with Copilot](https://github.com/skills/integrate-mcp-with-copilot) 23 | - Try building your first [GitHub Copilot Extension](https://github.com/skills/your-first-extension-for-github-copilot) 24 | 25 | Check out these resources to learn more about GitHub Copilot : 26 | 27 | - Are you not getting the responses you want from Copilot? [Learn prompt engineering](https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/prompt-engineering-for-copilot-chat) 28 | - Explore GitHub Copilot [Slash Commands](https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/github-copilot-chat-cheat-sheet?tool=vscode). 29 | - See what other features are available [GitHub Copilot Features](https://docs.github.com/en/copilot/about-github-copilot/github-copilot-features). 30 | - Take a look at the [GitHub Copilot Documentation](https://docs.github.com/en/copilot). 31 | -------------------------------------------------------------------------------- /.github/workflows/0-start-exercise.yml: -------------------------------------------------------------------------------- 1 | name: Step 0 # Start Exercise 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: write 10 | actions: write 11 | issues: write 12 | 13 | env: 14 | STEP_1_FILE: ".github/steps/1-preparing.md" 15 | 16 | jobs: 17 | start_exercise: 18 | if: | 19 | !github.event.repository.is_template 20 | name: Start Exercise 21 | uses: skills/exercise-toolkit/.github/workflows/start-exercise.yml@v0.4.0 22 | with: 23 | exercise-title: "Getting Started with GitHub Copilot" 24 | intro-message: "Welcome to the exciting world of GitHub Copilot! 🚀 In this exercise, you'll unlock the potential of this AI-powered coding assistant to accelerate your development process. Let's dive in and have some fun exploring the future of coding together! 💻✨" 25 | 26 | 27 | post_next_step_content: 28 | name: Post next step content 29 | runs-on: ubuntu-latest 30 | needs: [start_exercise] 31 | env: 32 | ISSUE_URL: ${{ needs.start_exercise.outputs.issue-url }} 33 | 34 | steps: 35 | - name: Checkout 36 | uses: actions/checkout@v4 37 | 38 | - name: Get response templates 39 | uses: actions/checkout@v4 40 | with: 41 | repository: skills/exercise-toolkit 42 | path: exercise-toolkit 43 | ref: v0.4.0 44 | 45 | - name: Build comment - add step content 46 | id: build-comment 47 | uses: skills/action-text-variables@v2 48 | with: 49 | template-file: ${{ env.STEP_1_FILE }} 50 | template-vars: | 51 | login: ${{ github.actor }} 52 | full_repo_name: ${{ github.repository }} 53 | 54 | - name: Create comment - add step content 55 | run: | 56 | gh issue comment "$ISSUE_URL" \ 57 | --body "$ISSUE_BODY" 58 | env: 59 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 60 | ISSUE_BODY: ${{ steps.build-comment.outputs.updated-text }} 61 | 62 | - name: Create comment - watching for progress 63 | run: | 64 | gh issue comment "$ISSUE_URL" \ 65 | --body-file "exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md" 66 | env: 67 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 68 | 69 | - name: Disable current workflow and enable next one 70 | run: | 71 | gh workflow enable "Step 1" 72 | env: 73 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 74 | -------------------------------------------------------------------------------- /.github/workflows/1-preparing.yml: -------------------------------------------------------------------------------- 1 | name: Step 1 # Preparing to make your extension 2 | 3 | on: 4 | push: 5 | branches: 6 | - "accelerate-with-copilot" 7 | 8 | permissions: 9 | contents: read 10 | actions: write 11 | issues: write 12 | 13 | env: 14 | STEP_2_FILE: ".github/steps/2-first-introduction.md" 15 | 16 | jobs: 17 | find_exercise: 18 | name: Find Exercise Issue 19 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.4.0 20 | 21 | check_step_work: 22 | name: Check step work 23 | runs-on: ubuntu-latest 24 | needs: [find_exercise] 25 | env: 26 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 27 | 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | 32 | - name: Get response templates 33 | uses: actions/checkout@v4 34 | with: 35 | repository: skills/exercise-toolkit 36 | path: exercise-toolkit 37 | ref: v0.4.0 38 | 39 | - name: Update comment - checking work 40 | run: | 41 | gh issue comment "$ISSUE_URL" \ 42 | --body-file exercise-toolkit/markdown-templates/step-feedback/checking-work.md \ 43 | --edit-last 44 | env: 45 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | 47 | # START: Check practical exercise 48 | 49 | # Nothing to verify. Creating the branch is enough for now. 50 | # In a future update, we will check that the codepsace is running and that the website is visible. 51 | 52 | # END: Check practical exercise 53 | 54 | - name: Build message - step finished 55 | id: build-message-step-finish 56 | uses: skills/action-text-variables@v2 57 | with: 58 | template-file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md 59 | template-vars: | 60 | next_step_number: 2 61 | 62 | - name: Update comment - step finished 63 | run: | 64 | gh issue comment "$ISSUE_URL" \ 65 | --body "$ISSUE_BODY" \ 66 | --edit-last 67 | env: 68 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | ISSUE_BODY: ${{ steps.build-message-step-finish.outputs.updated-text }} 70 | 71 | post_next_step_content: 72 | name: Post next step content 73 | needs: [find_exercise, check_step_work] 74 | runs-on: ubuntu-latest 75 | env: 76 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 77 | 78 | steps: 79 | - name: Checkout 80 | uses: actions/checkout@v4 81 | 82 | - name: Get response templates 83 | uses: actions/checkout@v4 84 | with: 85 | repository: skills/exercise-toolkit 86 | path: exercise-toolkit 87 | ref: v0.4.0 88 | 89 | - name: Create comment - add step content 90 | run: | 91 | gh issue comment "$ISSUE_URL" \ 92 | --body-file "$STEP_2_FILE" 93 | env: 94 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 95 | 96 | - name: Create comment - watching for progress 97 | run: | 98 | gh issue comment "$ISSUE_URL" \ 99 | --body-file exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md 100 | env: 101 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 102 | 103 | - name: Disable current workflow and enable next one 104 | run: | 105 | gh workflow disable "Step 1" 106 | gh workflow enable "Step 2" 107 | env: 108 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 109 | -------------------------------------------------------------------------------- /.github/workflows/2-first-introduction.yml: -------------------------------------------------------------------------------- 1 | name: Step 2 # Copilot chat 2 | 3 | on: 4 | push: 5 | branches: 6 | - "accelerate-with-copilot" 7 | paths: 8 | - "src/app.py" 9 | 10 | permissions: 11 | contents: read 12 | actions: write 13 | issues: write 14 | 15 | env: 16 | STEP_3_FILE: ".github/steps/3-copilot-edits.md" 17 | 18 | jobs: 19 | find_exercise: 20 | name: Find Exercise Issue 21 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.4.0 22 | 23 | check_step_work: 24 | name: Check step work 25 | runs-on: ubuntu-latest 26 | needs: [find_exercise] 27 | env: 28 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 29 | 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v4 33 | 34 | - name: Get response templates 35 | uses: actions/checkout@v4 36 | with: 37 | repository: skills/exercise-toolkit 38 | path: exercise-toolkit 39 | ref: v0.4.0 40 | 41 | - name: Update comment - checking work 42 | run: | 43 | gh issue comment "$ISSUE_URL" \ 44 | --body-file exercise-toolkit/markdown-templates/step-feedback/checking-work.md \ 45 | --edit-last 46 | env: 47 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | 49 | # START: Check practical exercise 50 | 51 | - name: Check for additional student activities 52 | id: check-additional-activities 53 | continue-on-error: true 54 | uses: skills/action-keyphrase-checker@v1 55 | with: 56 | text-file: src/app.py 57 | keyphrase: '"description"' 58 | minimum-occurrences: 4 59 | case-sensitive: false 60 | 61 | - name: Build message - step results 62 | id: build-message-step-results 63 | uses: skills/action-text-variables@v2 64 | with: 65 | template-file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md 66 | template-vars: | 67 | step_number: 2 68 | passed: ${{ !contains(steps.*.outcome, 'failure') }} 69 | results_table: 70 | - description: "New activities added to src/app.py. We found ${{ steps.check-additional-activities.outputs.occurrences }} activities (minimum 4 required)" 71 | passed: ${{ steps.check-additional-activities.outcome == 'success' }} 72 | 73 | - name: Create comment - step results 74 | run: | 75 | gh issue comment "$ISSUE_URL" \ 76 | --body "$COMMENT_BODY" \ 77 | --edit-last 78 | env: 79 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 80 | COMMENT_BODY: ${{ steps.build-message-step-results.outputs.updated-text }} 81 | 82 | - name: Fail job if not all checks passed 83 | if: contains(steps.*.outcome, 'failure') 84 | run: exit 1 85 | 86 | - name: Build message - step finished 87 | id: build-message-step-finish 88 | uses: skills/action-text-variables@v2 89 | with: 90 | template-file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md 91 | template-vars: | 92 | next_step_number: 3 93 | 94 | - name: Update comment - step finished 95 | run: | 96 | gh issue comment "$ISSUE_URL" \ 97 | --body "$ISSUE_BODY" 98 | env: 99 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 100 | ISSUE_BODY: ${{ steps.build-message-step-finish.outputs.updated-text }} 101 | 102 | post_next_step_content: 103 | name: Post next step content 104 | needs: [find_exercise, check_step_work] 105 | runs-on: ubuntu-latest 106 | env: 107 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 108 | 109 | steps: 110 | - name: Checkout 111 | uses: actions/checkout@v4 112 | 113 | - name: Get response templates 114 | uses: actions/checkout@v4 115 | with: 116 | repository: skills/exercise-toolkit 117 | path: exercise-toolkit 118 | ref: v0.4.0 119 | 120 | - name: Create comment - add step content 121 | run: | 122 | gh issue comment "$ISSUE_URL" \ 123 | --body-file "$STEP_3_FILE" 124 | env: 125 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 126 | 127 | - name: Create comment - watching for progress 128 | run: | 129 | gh issue comment "$ISSUE_URL" \ 130 | --body-file exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md 131 | env: 132 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 133 | 134 | - name: Disable current workflow and enable next one 135 | run: | 136 | gh workflow disable "Step 2" 137 | gh workflow enable "Step 3" 138 | gh workflow enable "Step 3b" 139 | env: 140 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 141 | -------------------------------------------------------------------------------- /.github/workflows/3-copilot-edits.yml: -------------------------------------------------------------------------------- 1 | name: Step 3 # Copilot edits 2 | 3 | on: 4 | push: 5 | branches: 6 | - "accelerate-with-copilot" 7 | paths: 8 | - "src/static/**" 9 | 10 | permissions: 11 | contents: read 12 | actions: write 13 | issues: write 14 | 15 | env: 16 | STEP_4_FILE: ".github/steps/4-copilot-on-github.md" 17 | 18 | jobs: 19 | find_exercise: 20 | name: Find Exercise Issue 21 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.4.0 22 | 23 | check_step_work: 24 | name: Check step work 25 | runs-on: ubuntu-latest 26 | needs: [find_exercise] 27 | env: 28 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 29 | 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v4 33 | 34 | - name: Get response templates 35 | uses: actions/checkout@v4 36 | with: 37 | repository: skills/exercise-toolkit 38 | path: exercise-toolkit 39 | ref: v0.4.0 40 | 41 | - name: Update comment - checking work 42 | run: | 43 | gh issue comment "$ISSUE_URL" \ 44 | --body-file exercise-toolkit/markdown-templates/step-feedback/checking-work.md \ 45 | --edit-last 46 | env: 47 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | 49 | - name: Check for participant info in app.js 50 | id: check-app-js 51 | continue-on-error: true 52 | uses: skills/action-keyphrase-checker@v1 53 | with: 54 | text-file: src/static/app.js 55 | keyphrase: participant 56 | minimum-occurrences: 3 57 | case-sensitive: false 58 | 59 | - name: Check for participant info in styles.css 60 | id: check-styles 61 | continue-on-error: true 62 | uses: skills/action-keyphrase-checker@v1 63 | with: 64 | text-file: src/static/styles.css 65 | keyphrase: participant 66 | case-sensitive: false 67 | 68 | - name: Build message - step results 69 | id: build-message-step-results 70 | uses: skills/action-text-variables@v2 71 | with: 72 | template-file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md 73 | template-vars: | 74 | step_number: 3 75 | passed: ${{ !contains(steps.*.outcome, 'failure') }} 76 | results_table: 77 | - description: "Check app.js for participant info" 78 | passed: ${{ steps.check-app-js.outcome == 'success' }} 79 | - description: "Participant styling updated in styles.css" 80 | passed: ${{ steps.check-styles.outcome == 'success' }} 81 | 82 | - name: Create comment - step results 83 | run: | 84 | gh issue comment "$ISSUE_URL" \ 85 | --body "$COMMENT_BODY" \ 86 | --edit-last 87 | env: 88 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 89 | COMMENT_BODY: ${{ steps.build-message-step-results.outputs.updated-text }} 90 | 91 | - name: Fail job if not all checks passed 92 | if: contains(steps.*.outcome, 'failure') 93 | run: exit 1 94 | 95 | - name: Build message - step finished 96 | id: build-message-step-finish 97 | uses: skills/action-text-variables@v2 98 | with: 99 | template-file: exercise-toolkit/markdown-templates/step-feedback/step-finished-prepare-next-step.md 100 | template-vars: | 101 | next_step_number: 4 102 | 103 | - name: Update comment - step finished 104 | run: | 105 | gh issue comment "$ISSUE_URL" \ 106 | --body "$ISSUE_BODY" 107 | env: 108 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 109 | ISSUE_BODY: ${{ steps.build-message-step-finish.outputs.updated-text }} 110 | 111 | post_next_step_content: 112 | name: Post next step content 113 | needs: [find_exercise, check_step_work] 114 | runs-on: ubuntu-latest 115 | env: 116 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 117 | 118 | steps: 119 | - name: Checkout 120 | uses: actions/checkout@v4 121 | 122 | - name: Get response templates 123 | uses: actions/checkout@v4 124 | with: 125 | repository: skills/exercise-toolkit 126 | path: exercise-toolkit 127 | ref: v0.4.0 128 | 129 | - name: Create comment - add step content 130 | run: | 131 | gh issue comment "$ISSUE_URL" \ 132 | --body-file "$STEP_4_FILE" 133 | env: 134 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 135 | 136 | - name: Create comment - watching for progress 137 | run: | 138 | gh issue comment "$ISSUE_URL" \ 139 | --body-file exercise-toolkit/markdown-templates/step-feedback/watching-for-progress.md 140 | env: 141 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 142 | 143 | - name: Disable current workflow and enable next one 144 | run: | 145 | gh workflow disable "Step 3" 146 | gh workflow enable "Step 4" 147 | gh workflow enable "Step 4b" 148 | env: 149 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 150 | -------------------------------------------------------------------------------- /.github/workflows/3b-copilot-agent-mode.yml: -------------------------------------------------------------------------------- 1 | name: Step 3b # Copilot Agent Mode 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | permissions: 8 | contents: read 9 | actions: write 10 | issues: write 11 | 12 | env: 13 | # Keywords required in the issue comment to allow this workflow to run 14 | REQUIRED_ISSUE_COMMENT_KEYWORDS: "@professortocat,Agent" 15 | STEP_3B_FILE: ".github/steps/3b-copilot-agent-mode.md" 16 | 17 | jobs: 18 | required_issue_comment_keywords: 19 | name: Check issue comment text for required keywords 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - name: Stop early if missing the expected keywords, case insensitive 24 | shell: bash 25 | run: | 26 | required_keywords=(${REQUIRED_ISSUE_COMMENT_KEYWORDS//,/ }) 27 | comment_body_lower=$(echo "$COMMENT_BODY" | tr '[:upper:]' '[:lower:]') 28 | for keyword in "${required_keywords[@]}"; do 29 | keyword_lower=$(echo "$keyword" | tr '[:upper:]' '[:lower:]') 30 | if [[ ! "$comment_body_lower" =~ $keyword_lower ]]; then 31 | exit 1 32 | fi 33 | done 34 | env: 35 | COMMENT_BODY: ${{ github.event.comment.body }} 36 | 37 | find_exercise: 38 | name: Find Exercise Issue 39 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.4.0 40 | 41 | post_step_3b_content: 42 | name: Post step 3b content 43 | needs: [find_exercise, required_issue_comment_keywords] 44 | runs-on: ubuntu-latest 45 | env: 46 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 47 | 48 | steps: 49 | - name: Checkout 50 | uses: actions/checkout@v4 51 | 52 | - name: Create comment - add step content 53 | run: | 54 | gh issue comment "$ISSUE_URL" \ 55 | --body-file "$STEP_3B_FILE" 56 | env: 57 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | 59 | - name: Disable current workflow 60 | run: | 61 | gh workflow disable "Step 3b" 62 | env: 63 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | -------------------------------------------------------------------------------- /.github/workflows/4-copilot-on-github.yml: -------------------------------------------------------------------------------- 1 | name: Step 4 # Copilot on GitHub 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | types: 8 | - closed 9 | 10 | permissions: 11 | contents: write 12 | actions: write 13 | issues: write 14 | 15 | env: 16 | REVIEW_FILE: ".github/steps/x-review.md" 17 | 18 | jobs: 19 | find_exercise: 20 | name: Find Exercise Issue 21 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.4.0 22 | 23 | check_step_work: 24 | name: Check step work 25 | runs-on: ubuntu-latest 26 | needs: [find_exercise] 27 | env: 28 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 29 | 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v4 33 | 34 | 35 | - name: Get response templates 36 | uses: actions/checkout@v4 37 | with: 38 | repository: skills/exercise-toolkit 39 | path: exercise-toolkit 40 | ref: v0.4.0 41 | 42 | # START: Check practical exercise 43 | 44 | # Nothing to check. Merging the pull request is enough. 45 | 46 | # END: Check practical exercise 47 | 48 | - name: Create comment - step finished - final review next 49 | run: | 50 | gh issue comment "$ISSUE_URL" \ 51 | --body-file exercise-toolkit/markdown-templates/step-feedback/lesson-review.md 52 | env: 53 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 54 | 55 | post_review_content: 56 | name: Post review content 57 | needs: [find_exercise, check_step_work] 58 | runs-on: ubuntu-latest 59 | env: 60 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 61 | 62 | steps: 63 | - name: Checkout 64 | uses: actions/checkout@v4 65 | 66 | 67 | - name: Get response templates 68 | uses: actions/checkout@v4 69 | with: 70 | repository: skills/exercise-toolkit 71 | path: exercise-toolkit 72 | ref: v0.4.0 73 | 74 | - name: Create comment - add step content 75 | run: | 76 | gh issue comment "$ISSUE_URL" \ 77 | --body-file "$REVIEW_FILE" 78 | env: 79 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 80 | 81 | finish_exercise: 82 | name: Finish Exercise 83 | needs: [find_exercise, post_review_content] 84 | uses: skills/exercise-toolkit/.github/workflows/finish-exercise.yml@v0.4.0 85 | with: 86 | issue-url: ${{ needs.find_exercise.outputs.issue-url }} 87 | 88 | disable_workflow: 89 | name: Disable this workflow 90 | needs: [find_exercise, post_review_content] 91 | runs-on: ubuntu-latest 92 | 93 | steps: 94 | - name: Checkout 95 | uses: actions/checkout@v4 96 | - name: Disable current workflow 97 | run: gh workflow disable "${{github.workflow}}" 98 | env: 99 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 100 | -------------------------------------------------------------------------------- /.github/workflows/4b-copilot-on-github.yml: -------------------------------------------------------------------------------- 1 | name: Step 4b # Copilot on GitHub 2 | 3 | on: 4 | # Trigger if PR Description is edited 5 | # Disabled because PR summaries are not available for free accounts 6 | # pull_request: 7 | # branches: 8 | # - main 9 | # types: 10 | # - edited 11 | 12 | # Trigger if Copilot adds a review comment 13 | pull_request_review: 14 | 15 | permissions: 16 | contents: write 17 | actions: write 18 | issues: write 19 | pull-requests: read 20 | repository-projects: read 21 | 22 | jobs: 23 | find_exercise: 24 | name: Find Exercise Issue 25 | uses: skills/exercise-toolkit/.github/workflows/find-exercise-issue.yml@v0.4.0 26 | 27 | check_step_work: 28 | name: Check step work 29 | runs-on: ubuntu-latest 30 | needs: [find_exercise] 31 | env: 32 | ISSUE_URL: ${{ needs.find_exercise.outputs.issue-url }} 33 | 34 | steps: 35 | - name: Checkout 36 | uses: actions/checkout@v4 37 | 38 | - name: Get response templates 39 | uses: actions/checkout@v4 40 | with: 41 | repository: skills/exercise-toolkit 42 | path: exercise-toolkit 43 | ref: v0.4.0 44 | 45 | # START: Check practical exercise 46 | 47 | - name: Check for PR description 48 | continue-on-error: true 49 | id: check-pr-description 50 | run: | 51 | # Check if PR has a description and minimum length 52 | min_length=15 53 | body_length=$(echo "$PR_Body" | wc -c) 54 | echo "PR description length: $body_length" 55 | 56 | if [ "$body_length" -lt $min_length ]; then 57 | echo "::error::PR description is too short or missing" 58 | exit 1 59 | fi 60 | env: 61 | PR_Body: ${{ github.event.pull_request.body }} 62 | 63 | - name: Check for Copilot review 64 | id: check-copilot-review 65 | run: | 66 | # Check for a PR Review from Copilot 67 | reviews=$(gh pr view --repo $REPO $PR_NUMBER --json reviews) 68 | authors=$(echo "$reviews" | jq '.reviews[].author.login') 69 | 70 | if echo "$authors" | grep -q "copilot-pull-request-reviewer"; then 71 | echo "Copilot has reviewed this PR." 72 | else 73 | echo "Copilot has NOT reviewed this PR." 74 | echo "::error::No review from Copilot found" 75 | exit 1 76 | fi 77 | env: 78 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 79 | REPO: ${{ github.repository }} 80 | PR_NUMBER: ${{ github.event.pull_request.number }} 81 | continue-on-error: true 82 | 83 | - name: Build message - step results 84 | id: build-message-step-results 85 | uses: skills/action-text-variables@v2 86 | with: 87 | template-file: exercise-toolkit/markdown-templates/step-feedback/step-results-table.md 88 | template-vars: | 89 | step_number: 4 90 | passed: ${{ !contains(steps.*.outcome, 'failure') }} 91 | results_table: 92 | - description: "Pull request contains a descriptive overview" 93 | passed: ${{ steps.check-pr-description.outcome == 'success' }} 94 | - description: "Pull request received a review from GitHub Copilot" 95 | passed: ${{ steps.check-copilot-review.outcome == 'success' }} 96 | tips: 97 | - "If you already requested Copilot review and this check did not pass, go to your repository [actions](https://github.com/${{github.repository}}/actions) tab to check if a workflow run is awaiting your manual approval." 98 | - "You can use repository rulesets to automatically require a review from Copilot." 99 | 100 | - name: Create comment - step results 101 | run: | 102 | gh issue comment "$ISSUE_URL" \ 103 | --body "$COMMENT_BODY" 104 | env: 105 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 106 | COMMENT_BODY: ${{ steps.build-message-step-results.outputs.updated-text }} 107 | 108 | - name: Fail job if not all checks passed 109 | if: contains(steps.*.outcome, 'failure') 110 | run: exit 1 111 | 112 | # END: Check practical exercise 113 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.temp* 2 | 3 | # Compiled source # 4 | ################### 5 | *.com 6 | *.class 7 | *.dll 8 | *.exe 9 | *.o 10 | *.so 11 | 12 | # Packages # 13 | ############ 14 | # it's better to unpack these files and commit the raw source 15 | # git has its own built in compression methods 16 | *.7z 17 | *.dmg 18 | *.gz 19 | *.iso 20 | *.jar 21 | *.rar 22 | *.tar 23 | *.zip 24 | 25 | # Logs and databases # 26 | ###################### 27 | *.log 28 | *.sql 29 | *.sqlite 30 | 31 | # OS generated files # 32 | ###################### 33 | .DS_Store 34 | .DS_Store? 35 | ._* 36 | .Spotlight-V100 37 | .Trashes 38 | ehthumbs.db 39 | Thumbs.db 40 | .actrc* 41 | 42 | __pycache__/ -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Mergington WebApp", 9 | "type": "debugpy", 10 | "request": "launch", 11 | "module": "uvicorn", 12 | "args": [ 13 | "src.app:app", 14 | "--reload" 15 | ], 16 | "jinja": true 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) GitHub and others 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with GitHub Copilot 2 | 3 | _Get started using GitHub Copilot in less than an hour._ 4 | 5 | ## Welcome 6 | 7 | - **Who is this for**: Developers at any experience level looking to accelerate their code workflow. 8 | - **What you'll learn**: The different ways to interact with Copilot to explain, write, debug, and develop code. 9 | - **What you'll build**: You will guide Copilot to update Mergington High School's extracurricular activities website. 10 | - **Prerequisites**: 11 | - Skills exercise: [Introduction to GitHub](https://github.com/skills/introduction-to-github) 12 | - Familiarity with [VS Code](https://code.visualstudio.com/) 13 | - Basic coding principles 14 | - **How long**: This exercise takes less than one hour to complete. 15 | 16 | In this exercise, you will: 17 | 18 | 1. Use a preconfigured Codespace to run VS Code in your browser. 19 | 1. Learn different interaction options to develop with GitHub Copilot. 20 | 1. Use Copilot to summarize and review your pull request. 21 | 22 | ### How to start this exercise 23 | 24 | Simply copy the exercise to your account, then give your favorite Octocat (Mona) **about 20 seconds** to prepare the first lesson, then **refresh the page**. 25 | 26 | [![](https://img.shields.io/badge/Copy%20Exercise-%E2%86%92-1f883d?style=for-the-badge&logo=github&labelColor=197935)](https://github.com/new?template_owner=skills&template_name=getting-started-with-github-copilot&owner=%40me&name=skills-getting-started-with-github-copilot&description=Exercise:+Get+started+using+GitHub+Copilot&visibility=public) 27 | 28 |
29 | Having trouble? 🤷
30 | 31 | When copying the exercise, we recommend the following settings: 32 | 33 | - For owner, choose your personal account or an organization to host the repository. 34 | 35 | - We recommend creating a public repository, since private repositories will use Actions minutes. 36 | 37 | If the exercise isn't ready in 20 seconds, please check the [Actions](../../actions) tab. 38 | 39 | - Check to see if a job is running. Sometimes it simply takes a bit longer. 40 | 41 | - If the page shows a failed job, please submit an issue. Nice, you found a bug! 🐛 42 | 43 |
44 | 45 | --- 46 | 47 | © 2025 GitHub • [Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md) • [MIT License](https://gh.io/mit) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn 3 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Mergington High School Activities API 2 | 3 | A super simple FastAPI application that allows students to view and sign up for extracurricular activities. 4 | 5 | ## Features 6 | 7 | - View all available extracurricular activities 8 | - Sign up for activities 9 | 10 | ## Getting Started 11 | 12 | 1. Install the dependencies: 13 | 14 | ``` 15 | pip install fastapi uvicorn 16 | ``` 17 | 18 | 2. Run the application: 19 | 20 | ``` 21 | python app.py 22 | ``` 23 | 24 | 3. Open your browser and go to: 25 | - API documentation: http://localhost:8000/docs 26 | - Alternative documentation: http://localhost:8000/redoc 27 | 28 | ## API Endpoints 29 | 30 | | Method | Endpoint | Description | 31 | | ------ | ----------------------------------------------------------------- | ------------------------------------------------------------------- | 32 | | GET | `/activities` | Get all activities with their details and current participant count | 33 | | POST | `/activities/{activity_name}/signup?email=student@mergington.edu` | Sign up for an activity | 34 | 35 | ## Data Model 36 | 37 | The application uses a simple data model with meaningful identifiers: 38 | 39 | 1. **Activities** - Uses activity name as identifier: 40 | 41 | - Description 42 | - Schedule 43 | - Maximum number of participants allowed 44 | - List of student emails who are signed up 45 | 46 | 2. **Students** - Uses email as identifier: 47 | - Name 48 | - Grade level 49 | 50 | All data is stored in memory, which means data will be reset when the server restarts. 51 | -------------------------------------------------------------------------------- /src/app.py: -------------------------------------------------------------------------------- 1 | """ 2 | High School Management System API 3 | 4 | A super simple FastAPI application that allows students to view and sign up 5 | for extracurricular activities at Mergington High School. 6 | """ 7 | 8 | from fastapi import FastAPI, HTTPException 9 | from fastapi.staticfiles import StaticFiles 10 | from fastapi.responses import RedirectResponse 11 | import os 12 | from pathlib import Path 13 | 14 | app = FastAPI(title="Mergington High School API", 15 | description="API for viewing and signing up for extracurricular activities") 16 | 17 | # Mount the static files directory 18 | current_dir = Path(__file__).parent 19 | app.mount("/static", StaticFiles(directory=os.path.join(Path(__file__).parent, 20 | "static")), name="static") 21 | 22 | # In-memory activity database 23 | activities = { 24 | "Chess Club": { 25 | "description": "Learn strategies and compete in chess tournaments", 26 | "schedule": "Fridays, 3:30 PM - 5:00 PM", 27 | "max_participants": 12, 28 | "participants": ["michael@mergington.edu", "daniel@mergington.edu"] 29 | }, 30 | "Programming Class": { 31 | "description": "Learn programming fundamentals and build software projects", 32 | "schedule": "Tuesdays and Thursdays, 3:30 PM - 4:30 PM", 33 | "max_participants": 20, 34 | "participants": ["emma@mergington.edu", "sophia@mergington.edu"] 35 | }, 36 | "Gym Class": { 37 | "description": "Physical education and sports activities", 38 | "schedule": "Mondays, Wednesdays, Fridays, 2:00 PM - 3:00 PM", 39 | "max_participants": 30, 40 | "participants": ["john@mergington.edu", "olivia@mergington.edu"] 41 | } 42 | } 43 | 44 | 45 | @app.get("/") 46 | def root(): 47 | return RedirectResponse(url="/static/index.html") 48 | 49 | 50 | @app.get("/activities") 51 | def get_activities(): 52 | return activities 53 | 54 | 55 | @app.post("/activities/{activity_name}/signup") 56 | def signup_for_activity(activity_name: str, email: str): 57 | """Sign up a student for an activity""" 58 | # Validate activity exists 59 | if activity_name not in activities: 60 | raise HTTPException(status_code=404, detail="Activity not found") 61 | 62 | # Get the specific activity 63 | activity = activities[activity_name] 64 | 65 | # Add student 66 | activity["participants"].append(email) 67 | return {"message": f"Signed up {email} for {activity_name}"} 68 | -------------------------------------------------------------------------------- /src/static/app.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | const activitiesList = document.getElementById("activities-list"); 3 | const activitySelect = document.getElementById("activity"); 4 | const signupForm = document.getElementById("signup-form"); 5 | const messageDiv = document.getElementById("message"); 6 | 7 | // Function to fetch activities from API 8 | async function fetchActivities() { 9 | try { 10 | const response = await fetch("/activities"); 11 | const activities = await response.json(); 12 | 13 | // Clear loading message 14 | activitiesList.innerHTML = ""; 15 | 16 | // Populate activities list 17 | Object.entries(activities).forEach(([name, details]) => { 18 | const activityCard = document.createElement("div"); 19 | activityCard.className = "activity-card"; 20 | 21 | const spotsLeft = details.max_participants - details.participants.length; 22 | 23 | activityCard.innerHTML = ` 24 |

${name}

25 |

${details.description}

26 |

Schedule: ${details.schedule}

27 |

Availability: ${spotsLeft} spots left

28 | `; 29 | 30 | activitiesList.appendChild(activityCard); 31 | 32 | // Add option to select dropdown 33 | const option = document.createElement("option"); 34 | option.value = name; 35 | option.textContent = name; 36 | activitySelect.appendChild(option); 37 | }); 38 | } catch (error) { 39 | activitiesList.innerHTML = "

Failed to load activities. Please try again later.

"; 40 | console.error("Error fetching activities:", error); 41 | } 42 | } 43 | 44 | // Handle form submission 45 | signupForm.addEventListener("submit", async (event) => { 46 | event.preventDefault(); 47 | 48 | const email = document.getElementById("email").value; 49 | const activity = document.getElementById("activity").value; 50 | 51 | try { 52 | const response = await fetch( 53 | `/activities/${encodeURIComponent(activity)}/signup?email=${encodeURIComponent(email)}`, 54 | { 55 | method: "POST", 56 | } 57 | ); 58 | 59 | const result = await response.json(); 60 | 61 | if (response.ok) { 62 | messageDiv.textContent = result.message; 63 | messageDiv.className = "success"; 64 | signupForm.reset(); 65 | } else { 66 | messageDiv.textContent = result.detail || "An error occurred"; 67 | messageDiv.className = "error"; 68 | } 69 | 70 | messageDiv.classList.remove("hidden"); 71 | 72 | // Hide message after 5 seconds 73 | setTimeout(() => { 74 | messageDiv.classList.add("hidden"); 75 | }, 5000); 76 | } catch (error) { 77 | messageDiv.textContent = "Failed to sign up. Please try again."; 78 | messageDiv.className = "error"; 79 | messageDiv.classList.remove("hidden"); 80 | console.error("Error signing up:", error); 81 | } 82 | }); 83 | 84 | // Initialize app 85 | fetchActivities(); 86 | }); 87 | -------------------------------------------------------------------------------- /src/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mergington High School Activities 7 | 8 | 9 | 10 |
11 |

Mergington High School

12 |

Extracurricular Activities

13 |
14 | 15 |
16 |
17 |

Available Activities

18 |
19 | 20 |

Loading activities...

21 |
22 |
23 | 24 |
25 |

Sign Up for an Activity

26 |
27 |
28 | 29 | 30 |
31 |
32 | 33 | 37 |
38 | 39 |
40 | 41 |
42 |
43 | 44 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/static/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | font-family: Arial, sans-serif; 6 | } 7 | 8 | body { 9 | font-family: Arial, sans-serif; 10 | line-height: 1.6; 11 | color: #333; 12 | max-width: 1200px; 13 | margin: 0 auto; 14 | padding: 20px; 15 | background-color: #f5f5f5; 16 | } 17 | 18 | header { 19 | text-align: center; 20 | padding: 20px 0; 21 | margin-bottom: 30px; 22 | background-color: #1a237e; 23 | color: white; 24 | border-radius: 5px; 25 | } 26 | 27 | header h1 { 28 | margin-bottom: 10px; 29 | } 30 | 31 | main { 32 | display: flex; 33 | flex-wrap: wrap; 34 | gap: 30px; 35 | justify-content: center; 36 | } 37 | 38 | @media (min-width: 768px) { 39 | main { 40 | grid-template-columns: 2fr 1fr; 41 | } 42 | } 43 | 44 | section { 45 | background-color: white; 46 | padding: 20px; 47 | border-radius: 5px; 48 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); 49 | width: 100%; 50 | max-width: 500px; 51 | } 52 | 53 | section h3 { 54 | margin-bottom: 20px; 55 | padding-bottom: 10px; 56 | border-bottom: 1px solid #ddd; 57 | color: #1a237e; 58 | } 59 | 60 | .activity-card { 61 | margin-bottom: 15px; 62 | padding: 15px; 63 | border: 1px solid #ddd; 64 | border-radius: 5px; 65 | background-color: #f9f9f9; 66 | } 67 | 68 | .activity-card h4 { 69 | margin-bottom: 10px; 70 | color: #0066cc; 71 | } 72 | 73 | .activity-card p { 74 | margin-bottom: 8px; 75 | } 76 | 77 | .form-group { 78 | margin-bottom: 15px; 79 | } 80 | 81 | .form-group label { 82 | display: block; 83 | margin-bottom: 5px; 84 | font-weight: bold; 85 | } 86 | 87 | .form-group input, 88 | .form-group select { 89 | width: 100%; 90 | padding: 10px; 91 | border: 1px solid #ddd; 92 | border-radius: 4px; 93 | font-size: 16px; 94 | } 95 | 96 | button { 97 | background-color: #1a237e; 98 | color: white; 99 | border: none; 100 | padding: 10px 15px; 101 | font-size: 16px; 102 | border-radius: 5px; 103 | cursor: pointer; 104 | transition: background-color 0.2s; 105 | } 106 | 107 | button:hover { 108 | background-color: #3949ab; 109 | } 110 | 111 | .message { 112 | margin-top: 20px; 113 | padding: 10px; 114 | border-radius: 4px; 115 | } 116 | 117 | .success { 118 | background-color: #e8f5e9; 119 | color: #2e7d32; 120 | border: 1px solid #a5d6a7; 121 | } 122 | 123 | .error { 124 | background-color: #ffebee; 125 | color: #c62828; 126 | border: 1px solid #ef9a9a; 127 | } 128 | 129 | .info { 130 | background-color: #d1ecf1; 131 | color: #0c5460; 132 | border: 1px solid #bee5eb; 133 | } 134 | 135 | .hidden { 136 | display: none; 137 | } 138 | 139 | footer { 140 | text-align: center; 141 | margin-top: 30px; 142 | padding: 20px; 143 | color: #666; 144 | } 145 | --------------------------------------------------------------------------------