Skip to content

Lab 010: GitHub Copilot β€” First StepsΒΆ

Level: L100 Path: πŸ€– GitHub Copilot Time: ~45 min πŸ’° Cost: GitHub Free β€” Free tier (2,000 completions + 50 chat/month)

What You'll LearnΒΆ

  • Use inline code completion to write code from comments
  • Use Copilot Chat /fix to find and understand real bugs
  • Use Copilot Edits to refactor an entire file with natural language
  • Use inline chat to extend code without leaving the editor
  • Write prompts that get better results

This lab uses hands-on exercises β€” you'll open files with real bugs and incomplete code, then use Copilot to fix and extend them.


PrerequisitesΒΆ

1. Enable GitHub Copilot FreeΒΆ

  1. Go to github.com/features/copilot β†’ "Start for free"
  2. Sign in and follow the setup wizard

Students get Copilot Pro for free

β†’ GitHub Student Developer Pack

2. Install VS Code + Copilot extensionΒΆ

  1. Install VS Code
  2. Extensions (Ctrl+Shift+X) β†’ search "GitHub Copilot" β†’ Install both:
  3. GitHub Copilot (completions)
  4. GitHub Copilot Chat (chat panel)
  5. Sign in when prompted β€” you'll see the Copilot icon in the status bar

3. Download the exercise filesΒΆ

Clone or download the exercise files for this lab:

git clone https://github.com/lcarli/AI-LearningHub.git
cd AI-LearningHub/docs/docs/en/labs/lab-010

Or copy each file directly from the sections below.


Quick Start with GitHub Codespaces

Open in GitHub Codespaces

All dependencies are pre-installed in the devcontainer.

πŸ“¦ Supporting FilesΒΆ

Download these files before starting the lab

Save all files to a lab-010/ folder in your working directory.

File Description Download
exercise1_fibonacci.py Interactive exercise script πŸ“₯ Download
exercise2_shopping_cart.py Interactive exercise script πŸ“₯ Download
exercise3_product_search.py Interactive exercise script πŸ“₯ Download
exercise4_refactor_me.py Interactive exercise script πŸ“₯ Download

Exercise 1 β€” Inline Completion: Write Code from CommentsΒΆ

Goal: Learn how Copilot completes code as you type.

Create a new file practice.py and type each comment below. After each comment, stop typing and wait for Copilot's suggestion. Press Tab to accept, you can keep pressing tab until copilot stops suggesting more completions.

We will not execute this code, so don't worry about syntax errors or missing imports β€” just focus on the suggestions Copilot gives you based on the comments.

# Function that takes a list of prices and returns the average:

# Function that reads a CSV file and returns rows as a list of dicts:

# Async function that fetches JSON from a URL using httpx:

# Class OutdoorProduct with name, price, category attributes and a discount() method:

Keyboard shortcuts

Key Action
Tab Accept suggestion
Esc Dismiss
Alt+] / Alt+[ Next / previous suggestion
Ctrl+Enter Open all suggestions panel

Try better and worse prompts:

❌ Vague βœ… Specific
# sort this # Sort list of dicts by 'price' descending, then 'name' ascending
# connect to db # Connect to PostgreSQL using asyncpg, return a connection pool
# handle error # Retry 3 times with exponential backoff if requests.Timeout is raised

Exercise 2 β€” Copilot /fix: Bug Hunt πŸ›ΒΆ

Goal: Use Copilot Chat to find, understand, and fix real bugs.

File: πŸ“₯ exercise1_fibonacci.pyΒΆ

exercise1_fibonacci.py β€” 3 bugs hidden inside
# exercise1_fibonacci.py
# πŸ› BUG HUNT β€” This file has 3 bugs. Can you find them all using Copilot /fix?
#
# TASK: The fibonacci() function should return a list of the first n
#       Fibonacci numbers: [0, 1, 1, 2, 3, 5, 8, 13, ...]
#
# EXPECTED OUTPUT (for n=8):
#   fibonacci(8)  β†’ [0, 1, 1, 2, 3, 5, 8, 13]
#   fibonacci(1)  β†’ [0]
#   fibonacci(0)  β†’ []
#
# HOW TO USE THIS EXERCISE:
#   1. Open this file in VS Code
#   2. Select ALL the code (Ctrl+A)
#   3. Open Copilot Chat β†’ type: /fix
#   4. Read Copilot's explanation of each bug
#   5. Accept the fix and run the tests below to verify

def fibonacci(n):
    """Return a list of the first n Fibonacci numbers."""
    if n = 0:           # BUG 1: syntax error
        return []

    sequence = [0, 1]

    for i in range(2, n):
        next_val = sequence[i-1] + sequence[i-2]
        sequence.append(next_val)

    return sequence[n]  # BUG 2: should return a slice, not a single element
                        # BUG 3: what happens when n=1? sequence has 2 elements but we only want 1


# --- Tests (run after fixing) ---
if __name__ == "__main__":
    assert fibonacci(0) == [], f"Expected [], got {fibonacci(0)}"
    assert fibonacci(1) == [0], f"Expected [0], got {fibonacci(1)}"
    assert fibonacci(8) == [0, 1, 1, 2, 3, 5, 8, 13], f"Got {fibonacci(8)}"
    print("βœ… All tests passed!")

Steps:

  1. Copy the code above into a new file (or open it from the downloaded exercises)
  2. Open Copilot Chat (Ctrl+Shift+I)
  3. Select all the code (Ctrl+A)
  4. Type: /fix

Copilot should identify all 3 bugs and explain each one. Before accepting, read the explanation β€” understanding why the code was wrong is the point.

Expected output after fixing:

fibonacci(0)  # β†’ []
fibonacci(1)  # β†’ [0]
fibonacci(8)  # β†’ [0, 1, 1, 2, 3, 5, 8, 13]

Run python exercise1_fibonacci.py β€” you should see: βœ… All tests passed!


File: πŸ“₯ exercise2_shopping_cart.pyΒΆ

exercise2_shopping_cart.py β€” 4 bugs hidden inside
# exercise2_shopping_cart.py
# πŸ› BUG HUNT β€” This file has 4 bugs. Use Copilot Chat to find and fix them.
#
# SCENARIO: OutdoorGear Inc. shopping cart logic.
# The cart should:
#   - Add items with a quantity
#   - Calculate total price (sum of price Γ— quantity)
#   - Apply a 10% discount on orders over $200
#   - Count unique items (not total quantity)
#
# EXPECTED OUTPUT:
#   Cart with 2x TrailBlazer ($189.99) + 1x Summit Tent ($349):
#   total before discount = $728.98
#   total after 10% discount = $656.08
#   unique_items = 2
#
# HOW TO USE:
#   1. Copy this file into VS Code
#   2. Try to run it: python exercise2_shopping_cart.py
#   3. Read the errors β€” but DON'T fix manually yet!
#   4. Select all code β†’ Copilot Chat β†’ /fix
#   5. Ask Copilot to explain EACH bug before fixing
#   6. Verify with the tests at the bottom

class ShoppingCart:
    def __init__(self):
        self.items = {}  # {product_name: {"price": float, "quantity": int}}

    def add_item(self, name: str, price: float, quantity: int = 1):
        if name in self.items:
            self.items[name]["quantity"] += quantity
        else:
            self.items[name] = {"price": price, "quantity": quantity}

    def get_total(self) -> float:
        """Calculate total price, applying 10% discount if over $200."""
        total = 0
        for item in self.items:            # BUG 1: iterating over keys only, not values
            total += item["price"] * item["quantity"]

        if total > 200:
            total = total * 0.90           # BUG 2: discount calculation correct, but...
                                           # should return rounded to 2 decimal places
        return total

    def count_unique_items(self) -> int:
        """Return the number of unique products (not total quantity)."""
        return sum(self.items.values())    # BUG 3: wrong β€” should be len(), not sum()

    def get_receipt(self) -> str:
        lines = []
        for name, details in self.items.items():
            subtotal = details["price"] + details["quantity"]  # BUG 4: + instead of *
            lines.append(f"  {name} x{details['quantity']} @ ${details['price']:.2f} = ${subtotal:.2f}")
        total = self.get_total()
        lines.append(f"\nTotal: ${total:.2f}")
        return "\n".join(lines)


# --- Tests ---
if __name__ == "__main__":
    cart = ShoppingCart()
    cart.add_item("TrailBlazer X200", 189.99, 2)
    cart.add_item("Summit Pro Tent", 349.00, 1)

    total = cart.get_total()
    unique = cart.count_unique_items()

    print(cart.get_receipt())
    print(f"\nUnique items: {unique}")

    assert unique == 2, f"Expected 2 unique items, got {unique}"
    assert abs(total - 656.08) < 0.01, f"Expected $656.08, got ${total}"
    print("\nβœ… All tests passed!")

This file has 4 bugs in the ShoppingCart class. This time, before using /fix:

  1. Try to spot the bugs yourself first β€” spend 2 minutes reading the code
  2. Then use Copilot Chat: select all β†’ /fix
  3. Did Copilot find bugs you missed?

Ask Copilot to explain one bug in depth:

Why is iterating with "for item in self.items" wrong here? What does it actually iterate over?

Expected output after fixing:

TrailBlazer X200 x2 @ $189.99 = $379.98
Summit Pro Tent x1 @ $349.00 = $349.00

Total: $656.08
Unique items: 2
βœ… All tests passed!


Exercise 3 β€” Inline Chat: Fix + ExtendΒΆ

Goal: Fix bugs AND add a new feature using inline chat (Ctrl+I).

File: πŸ“₯ exercise3_product_search.pyΒΆ

exercise3_product_search.py β€” 2 bugs + 1 missing feature
# exercise3_product_search.py
# πŸ› BUG HUNT + EXTEND β€” This file has 2 bugs AND is missing a feature.
#
# SCENARIO: OutdoorGear product search with filtering.
#
# TASK A (Fix): Find and fix the 2 bugs using Copilot /fix
# TASK B (Extend): Ask Copilot to add a sort_by_price() function
#   Prompt to use: "Add a sort_by_price(products, ascending=True) function
#                   that sorts the search results by price"
#
# EXPECTED OUTPUT after fixing:
#   search("boot")   β†’ [{"name": "TrailBlazer X200", "price": 189.99, "category": "footwear"}]
#   search("tent")   β†’ [{"name": "Summit Pro Tent",  "price": 349.00, "category": "camping"}]
#   search("xyz")    β†’ []
#   search("")       β†’ all 5 products
#
# HOW TO USE:
#   Step 1 β€” Fix bugs:  Select all β†’ Copilot Chat β†’ /fix
#   Step 2 β€” Extend:    Ctrl+I (inline chat) β†’ type the prompt above
#   Step 3 β€” Test:      Run the tests at the bottom

CATALOG = [
    {"name": "TrailBlazer X200",      "price": 189.99, "category": "footwear"},
    {"name": "Summit Pro Tent",        "price": 349.00, "category": "camping"},
    {"name": "ClimbTech Pro Harness", "price": 129.99, "category": "climbing"},
    {"name": "OmniPack 45L",          "price": 279.99, "category": "packs"},
    {"name": "StormShell Jacket",      "price": 349.00, "category": "clothing"},
]

def search_products(query: str) -> list[dict]:
    """Return products matching query in name or category (case-insensitive)."""
    if not query:
        return CATALOG

    query_lower = query.lower()
    results = []
    for product in CATALOG:
        if query_lower in product["name"].lower or \   # BUG 1: missing () on .lower
           query_lower in product["category"].lower():
            result.append(product)                      # BUG 2: wrong variable name (result vs results)
    return results


def format_results(products: list[dict]) -> str:
    """Format search results for display."""
    if not products:
        return "No products found."
    lines = [f"Found {len(products)} product(s):"]
    for p in products:
        lines.append(f"  β€’ {p['name']} β€” ${p['price']:.2f} ({p['category']})")
    return "\n".join(lines)


# --- Tests ---
if __name__ == "__main__":
    print("Test 1: search for 'boot'")
    r1 = search_products("boot")
    print(format_results(r1))
    assert len(r1) == 1 and r1[0]["name"] == "TrailBlazer X200"

    print("\nTest 2: search for 'tent'")
    r2 = search_products("tent")
    print(format_results(r2))
    assert len(r2) == 1 and r2[0]["name"] == "Summit Pro Tent"

    print("\nTest 3: empty search returns all")
    r3 = search_products("")
    assert len(r3) == 5

    print("\nTest 4: search 'xyz' returns empty")
    r4 = search_products("xyz")
    assert r4 == []

    # Test the sort function Copilot should have added:
    print("\nTest 5: sort by price ascending")
    sorted_asc = sort_by_price(CATALOG, ascending=True)
    assert sorted_asc[0]["name"] == "ClimbTech Pro Harness"  # cheapest first
    assert sorted_asc[-1]["price"] == 349.00

    print("\nβœ… All tests passed!")

Part A β€” Fix (2 bugs):

  1. Open the file in VS Code
  2. Select all (Ctrl+A) β†’ Copilot Chat β†’ /fix
  3. Verify: python exercise3_product_search.py β€” tests 1–4 should pass

Part B β€” Extend (1 missing feature):

The file mentions a sort_by_price() function that doesn't exist yet.

  1. Place your cursor at the end of the file (before the tests section)
  2. Press Ctrl+I (inline chat)
  3. Type exactly:
    Add a sort_by_price(products, ascending=True) function that returns
    the products list sorted by price
    
  4. Review the suggestion and press Accept (Ctrl+Enter)
  5. Run the tests again β€” all 5 should pass now

Exercise 4 β€” Copilot Edits: Refactor an Entire FileΒΆ

Goal: Use Copilot Edits to improve code quality with natural language instructions β€” without changing behavior.

File: πŸ“₯ exercise4_refactor_me.pyΒΆ

exercise4_refactor_me.py β€” works, but needs improvement
# exercise4_refactor_me.py
# ✏️  REFACTORING CHALLENGE β€” No bugs here, but the code is terrible.
#
# TASK: Use Copilot Edits to improve this code WITHOUT changing its behavior.
#
# TRY THESE COPILOT EDITS PROMPTS (one at a time):
#   1. "Add type hints to all function parameters and return values"
#   2. "Add docstrings following Google style to every function"  
#   3. "Replace the magic numbers with named constants at the top of the file"
#   4. "Refactor calculate_shipping to use early return instead of nested ifs"
#   5. "Add input validation: raise ValueError for negative prices or quantities"
#
# After each prompt, review what Copilot changed. Accept or reject with Ctrl+Enter / Ctrl+Backspace.
#
# GOAL: By the end, this code should be production-ready.

STANDARD_SHIPPING = 5.99
EXPRESS_SHIPPING = 14.99
FREE_SHIPPING_THRESHOLD = 75.0
DISCOUNT_THRESHOLD = 200.0
DISCOUNT_RATE = 0.10

def calculate_price(p, q):
    return p * q

def calculate_shipping(t):
    if t >= 75:
        return 0
    else:
        if t > 50:
            return 5.99
        else:
            return 14.99

def apply_discount(t):
    if t > 200:
        d = t * 0.10
        t = t - d
    return round(t, 2)

def order_summary(items):
    t = 0
    for i in items:
        t = t + calculate_price(i[0], i[1])
    s = calculate_shipping(t)
    t_with_shipping = t + s
    final = apply_discount(t_with_shipping)
    return {"subtotal": round(t, 2), "shipping": s, "discount_applied": t > 200, "total": final}


# Test β€” this should still pass after all refactoring
if __name__ == "__main__":
    items = [(189.99, 1), (349.00, 1)]   # (price, quantity)
    result = order_summary(items)
    print(result)
    assert result["total"] == 489.59, f"Got {result['total']}"
    print("βœ… Refactoring complete β€” behavior unchanged!")

This code works correctly but is hard to read and maintain. Use Copilot Edits to improve it step by step:

  1. Open the Copilot Edits panel: Ctrl+Shift+I β†’ click "Open Copilot Edits" (pencil icon)
  2. Click "Add Files" and add exercise4_refactor_me.py
  3. Run each of these prompts one at a time, reviewing changes before moving on:

Prompt 1:

Add type hints to all function parameters and return values

Prompt 2:

Add docstrings following Google style to every function

Prompt 3:

Refactor calculate_shipping to use early return instead of nested if/else

Prompt 4:

Add input validation: raise ValueError if price or quantity is negative

After each prompt, check that the test at the bottom still passes:

python exercise4_refactor_me.py
# Should still print: βœ… Refactoring complete β€” behavior unchanged!

Don't accept everything blindly

Sometimes Copilot adds extra complexity. If a suggestion makes the code harder to read, press Discard (Ctrl+Backspace) and rephrase.


Bonus: Ask Copilot to explain, not just fixΒΆ

Use these prompts on any of the exercise files to deepen your understanding:

/explain
What tests should I write for this function? Generate them.
What edge cases does this code not handle?
Is there a more Pythonic way to write this?


What You PracticedΒΆ

Copilot feature Exercise Use case
Inline completion Exercise 1 Write new code from comments
Chat /fix Exercise 2 Understand and fix bugs
Inline chat Ctrl+I Exercise 3 Fix + extend in-place
Copilot Edits Exercise 4 Refactor entire files

Next StepsΒΆ