Project 2 — Git and GitHub

CS-340: Software Engineering

Spring 2026

For project 2, you will gain experience with using the git distributed version control system and associated collaboration tools on GitHub. Your task will be to correct a bug in a repository of basic Python programs.

Often as a software engineer, you will be tasked with addressing issues that are reported by other users and developers. Depending on the nature of the project (e.g., you are contributing to an open-source project in your spare time), you might not have write permissions to the repository. In this case, you will need to use the tools discussed in class to construct a Pull Request to contribute your changes to the project. This project gives you an opportunity to practice using these tools in a low-stakes environment.

Requirements

As part of this project, you must:

  • Select one of the existing issues on the GitHub repository to fix.
  • Comment on the issue you select to indicate that you are working on it. An issue will be assigned to the first student to comment on it.
  • Update the issue with a description of what you identify as the problem and your plan for addressing it. You can also use this issue to ask questions about the problem and your proposed solution.
  • Submit a pull request to address the issue you select and provides updated testing code revealing the bug. Ensure that this PR is cross-linked with the issue you are addressing. Your pull request must come from a branch in your forked repository that is not the main branch
  • Provide high-quality commit messages, pull request descriptions, and issue comments.
  • Successfully have your contribution merged into the main project repository by following all the requirements above and feedback you receive on GitHub.
  • Review a peer's pull request and provide feedback on the quality of the contribution and the organization of commits.

Outside Resources

You may use outside resources to assist you on this assignment, but you may not use a resource that already (or nearly) solves the problem. This also means that your use of AI is restricted to assisting you with problem-solving, understanding git actions, and proofreading your commit messages. You should not be asking AI to write your commits for you. When reviewing a peer's work, your feedback should be based on your own analysis. While AI can help you understand a teammate's logic, the final evaluation of their commit organization and fix correctness must be your own.

Instead, you may use AI to give you hints about the quality of tests you write, correctness of your solution, or what an error message might mean. You are encouraged to include instructions in your AI prompts that strictly forbid it from giving you code samples but rather focuses on high-level examples and suggestions. You can also use AI to help you find typos in your commit messages and report, but you should do this to refine writing that you have already constructed yourself.

Main Project Repository

The main repository for this project is located at https://github.com/kevinaangstadt/CS340-S26-Repo. Be sure that you are looking at the main branch and not one that we might have used for class exercises.

This repository contains a number of python files that contain bugs. For each python file, there is a corresponding test_ file that contains some testing functions. These tests are not high quality. Indeed, they miss the bugs in the python files.

Note that you do not have write access to this repository, nor will you be granted write access to this repository. This means that you cannot push to this repository. Instead, you will need to make contributions following the techniques we discussed in class.

Getting Started

To get started, begin looking through the issues in the main project repository. Select one that you think you can address and comment on it to indicate that you are working on it. Your instructor will then officially "assign" you to that issue using the built-in GitHub tools. If you try to work on an issue without commenting on it first, your contributions will be rejected. You don't need to wait for the official assignment as long as you verify that you are first to comment on an issue.

Make a fork of the main project repository and clone your fork to your cloud vm. Try running all of the existing test cases to ensure things are working:

              
              python3 -m unittest discover --verbose
              (out)
              (out)test_negative_input (test_absolute_flipper.TestAbsoluteFlipper.test_negative_input) ... ok
              (out)test_zero_input (test_absolute_flipper.TestAbsoluteFlipper.test_zero_input) ... ok
              (out)test_adult (test_age_classifier.TestAgeClassifier.test_adult) ... ok
              (out)test_child (test_age_classifier.TestAgeClassifier.test_child) ... ok
              (out)test_mid_teen (test_age_classifier.TestAgeClassifier.test_mid_teen) ... ok
              (out)test_average_basic (test_average_calculator.TestAverageCalculator.test_average_basic) ... ok
              (out)test_average_floats (test_average_calculator.TestAverageCalculator.test_average_floats) ... ok
              (out)test_insufficient_funds (test_bank_transaction.TestBankTransaction.test_insufficient_funds) ... ok
              (out)test_valid_withdrawal (test_bank_transaction.TestBankTransaction.test_valid_withdrawal) ... ok
              (out)test_unit_dimensions (test_bmi_calculator.TestBMICalculator.test_unit_dimensions) ... ok
              (out)test_freezing_point (test_celsius_converter.TestCelsiusConverter.test_freezing_point) ... ok
              (out)test_radius_two (test_circle_area.TestCircleArea.test_radius_two) ... ok
              (out)test_black (test_color_converter.TestColorConverter.test_black) ... ok
              (out)test_white (test_color_converter.TestColorConverter.test_white) ... ok
              (out)test_start_one (test_countdown_generator.TestCountdownGenerator.test_start_one) ... ok
              (out)test_basic_split (test_csv_stripper.TestCSVStripper.test_basic_split) ... ok
              (out)test_fifty_percent_discount (test_discount_applier.TestDiscountApplier.test_fifty_percent_discount) ... ok
              (out)test_no_t (test_dna_transcriber.TestDNATranscriber.test_no_t) ... ok
              (out)test_uppercase_transcription (test_dna_transcriber.TestDNATranscriber.test_uppercase_transcription) ... ok
              (out)test_valid_email (test_email_extractor.TestEmailExtractor.test_valid_email) ... ok
              (out)test_empty_list (test_even_filter.TestEvenFilter.test_empty_list) ... ok
              (out)test_factorial_zero_one (test_factorial_calculator.TestFactorialCalculator.test_factorial_zero_one) ... ok
              (out)test_path_with_slash (test_file_path_builder.TestFilePathBuilder.test_path_with_slash) ... ok
              (out)test_buzz (test_fizzbuzz_utils.TestFizzBuzz.test_buzz) ... ok
              (out)test_fizz (test_fizzbuzz_utils.TestFizzBuzz.test_fizz) ... ok
              (out)test_number (test_fizzbuzz_utils.TestFizzBuzz.test_number) ... ok
              (out)test_failing_score (test_grade_passer.TestGradePasser.test_failing_score) ... ok
              (out)test_high_score (test_grade_passer.TestGradePasser.test_high_score) ... ok
              (out)test_find_middle_item (test_inventory_lookup.TestInventoryLookup.test_find_middle_item) ... ok
              (out)test_item_not_found (test_inventory_lookup.TestInventoryLookup.test_item_not_found) ... ok
              (out)test_non_leap_year (test_leap_year_check.TestLeapYear.test_non_leap_year) ... ok
              (out)test_simple_leap_year (test_leap_year_check.TestLeapYear.test_simple_leap_year) ... ok
              (out)test_zero_element (test_list_doubler.TestListDoubler.test_zero_element) ... ok
              (out)test_mixed_numbers (test_list_max_finder.TestListMaxFinder.test_mixed_numbers) ... ok
              (out)test_positive_numbers (test_list_max_finder.TestListMaxFinder.test_positive_numbers) ... ok
              (out)test_remove_separated_occurrences (test_list_modifier.TestListModifier.test_remove_separated_occurrences) ... ok
              (out)test_remove_single_occurrence (test_list_modifier.TestListModifier.test_remove_single_occurrence) ... ok
              (out)test_longer_sorted_list (test_median_finder.TestMedianFinder.test_longer_sorted_list) ... ok
              (out)test_sorted_list (test_median_finder.TestMedianFinder.test_sorted_list) ... ok
              (out)test_empty_names (test_name_combiner.TestNameCombiner.test_empty_names) ... ok
              (out)test_single_name (test_name_combiner.TestNameCombiner.test_single_name) ... ok
              (out)test_non_palindrome (test_palindrome_checker.TestPalindromeChecker.test_non_palindrome) ... ok
              (out)test_simple_palindrome (test_palindrome_checker.TestPalindromeChecker.test_simple_palindrome) ... ok
              (out)test_strong_password (test_password_validator.TestPasswordValidator.test_strong_password) ... ok
              (out)test_weak_password (test_password_validator.TestPasswordValidator.test_weak_password) ... ok
              (out)test_power_of_one (test_power_calculator.TestPowerCalculator.test_power_of_one) ... ok
              (out)test_two_squared (test_power_calculator.TestPowerCalculator.test_two_squared) ... ok
              (out)test_composite_four (test_prime_checker.TestPrimeChecker.test_composite_four) ... ok
              (out)test_prime_seven (test_prime_checker.TestPrimeChecker.test_prime_seven) ... ok
              (out)test_zero_dimensions (test_rectangle_geometry.TestRectangleGeometry.test_zero_dimensions) ... ok
              (out)test_admin_access (test_role_checker.TestRoleChecker.test_admin_access) ... ok
              (out)test_identical_sets (test_set_merger.TestSetMerger.test_identical_sets) ... ok
              (out)test_free_shipping (test_shipping_calculator.TestShippingCalculator.test_free_shipping) ... ok
              (out)test_standard_shipping (test_shipping_calculator.TestShippingCalculator.test_standard_shipping) ... ok
              (out)test_empty_cart (test_shopping_cart.TestShoppingCart.test_empty_cart) ... ok
              (out)test_single_item (test_shopping_cart.TestShoppingCart.test_single_item) ... ok
              (out)test_repeat_positive (test_string_repeater.TestStringRepeater.test_repeat_positive) ... ok
              (out)test_repeat_zero (test_string_repeater.TestStringRepeater.test_repeat_zero) ... ok
              (out)test_long_string (test_string_truncator.TestStringTruncator.test_long_string) ... ok
              (out)test_zero_rate (test_tax_adder.TestTaxAdder.test_zero_rate) ... ok
              (out)test_zero_celsius (test_temperature_converter.TestTemperatureConverter.test_zero_celsius) ... ok
              (out)test_returns_number (test_temperature_utils.TestTemperatureUtils.test_returns_number) ... ok
              (out)test_too_short (test_username_validator.TestUsernameValidator.test_too_short) ... ok
              (out)test_valid_username (test_username_validator.TestUsernameValidator.test_valid_username) ... ok
              (out)test_lowercase_vowels (test_vowel_counter.TestVowelCounter.test_lowercase_vowels) ... ok
              (out)test_no_vowels (test_vowel_counter.TestVowelCounter.test_no_vowels) ... ok
              (out)test_simple_sentence (test_word_counter.TestWordCounter.test_simple_sentence) ... ok
              (out)test_single_word (test_word_counter.TestWordCounter.test_single_word) ... ok
              (out)
              (out)----------------------------------------------------------------------
              (out)Ran 68 tests in 0.001s
              (out)
              (out)OK

              
            

This just ran all the unit tests that Python could find in the project repository. You can also run a single test file (e.g., for when you are developing your own test cases):

              
              python3 -m unittest test_age_classifier.py --verbose
              (out)
              (out)test_adult (test_age_classifier.TestAgeClassifier.test_adult) ... ok
              (out)test_child (test_age_classifier.TestAgeClassifier.test_child) ... ok
              (out)test_mid_teen (test_age_classifier.TestAgeClassifier.test_mid_teen) ... ok
              (out)
              (out)----------------------------------------------------------------------
              (out)Ran 3 tests in 0.001s
              (out)
              (out)OK

              
            

Now, it's time to get started on your fix. Be sure to create and checkout a new branch for your fix. PRs submitted from the main branch of your repository will be rejected. Begin by adding a new test (or tests) to the test file associated with your issue. Confirm that the code now fails the test (thereby demonstrating the reported bug). We call this approach test-driven development. Then, work on a fix to the code that resolves the bug (passes the test) while also passing all the existing tests.

As you proceed, be sure to commit your changes and follow best practices for your commit messages!

Contributions

You will be contributing to the main project repository through both issues and pull requests.

Issues

When responding to issues, please be sure to provide descriptive prose of the issue you are discussing.

Pull Requests (PRs)

You do not have write access to the main project repository. Therefore, you must make a fork of the repository and submit your contributions as pull requests. Recall our discussion of pull requests from class: you will want to provide a meaningful message with your pull request and also follow best practices for organizing your commits. Please refer to the High-Quality Commit Messages section for more details.

Create your pull requests from non-main branches. That is, create a new branch with a descriptive name before committing your contributions to your fork. Failure to open a pull request from a separate branch will result in your pull request being rejected. Note that in real projects, this isn't always necessary, but this project is giving you a chance to practice with using git.

Similarly, your pull request will be rejected if there are merge conflicts with the main project repository. This means you might need to update your PR to address other changes that are contributed to the repository.

Reviewing

As part of this project, you will be assigned one pull request from a peer to review. Your job in reviewing this PR is to:

  • Verify the correctness of the contribution
  • Review the commit organization and make sure that it follows the best practices we discussed.
  • Ask for changes if needed.
  • Write a comment explaining your reasons for approving the PR once you are satisfied that everything is in order.

Note that you may lose points if you approve a contribution that does not meet our guidelines or fail to adequately justify your decision.

High-Quality Commit Messages

As part of this project, you will be graded on the quality of your commit messages. Further, the quality of your commits will also be judged.

In general, we will be following the guidelines laid out here (and inlined below).

Further, look through Open Stack's Git Commit Practices for tips on how to break up commits in reasonable ways. This guide also provides some examples of high- and low-quality commit messages.

Commentary

This assignment is perhaps different from any of your other CS assignments. In some sense, we're less interested in the content you create and more interested in the process you follow. Further, git can be frustrating to use, so this project gives you a fairly low-stakes venue to practice. We are using very basic python programs so that your focus can be on the git workflows rather than very complicated code.

You might note that your score does not actually reflect directly the quality of code that you are contributing. Instead, our focus is on the quality of the commits, issue comments, and pull request that you create. It is still in your best interest to create high-quality bug fixes, otherwise your pull request is likely to be denied. This more closely mimics the reality of a job (or grad school) where producing high-quality work is an iterative process.

While you are working on this project, keep some notes about things you learn or struggle with. This information will help you as you are writing your final reflection.

Recall that you can reorganize your commits by using git rebase and git cherry-pick.

unittest Assertions

When writing tests with the unittest, we must use assertion methods to trigger tests for correctness. Depending on the nature of the bug you are addressing, you might need to use a different assertion method than those already in the test files. You can find a list of assertion methods in the Python documentation. For example, the following example makes sure that someFunction() produces a value that is less than 10:

              
              self.assertLess(someFunction(), 10)
              
            

Floating Point Numbers

Working with floating point numbers can be challenging (take CS-220 to understand why). Essentially, there will frequently be rounding error. unittest allows us to handle this with "fuzzy" matching using self.assertAlmostEqual(a, b, places=c). For example, to check that someFloatFunction() is approximately equal to b within 2 decimal places, we would write:

              
              self.assertAlmostEqual(someFloatFunction(), b, places=2)
              
            

Return Types

Note that it is also reasonable to validate the return type of a function. For example, if we want to check that someFunction() returns a string, we could write:

              
              self.assertIsInstance(someFunction(), str)
              
            

Exceptions

If you need to check that a piece of code raises an exception, you can use the assertRaises method (see here for more details).

Using this method is different from using the assertEqual method. We use it as part of a context manager, which is a special type of block in Python that allows us to set up some context for the code we are testing. The syntax looks like this:

              
              with self.assertRaises(SomeException):
                  # code that should raise SomeException goes here
                  doTheBadThing()
              
            

In this example, we are asserting that the code inside the with block raises an exception of type SomeException. If the code does not raise an exception, or if it raises a different type of exception, then the test will fail.

Automated Feedback on GitHub

In addition to peer feedback (part of Checkpoint 2) and instructor feedback, the main project repository is configured to provide automated feedback on your pull request. When you create a pull request (and for any subsequent push), GitHub will run some basic checks on your contribution. You can see the results of these checks in the feed for your PR. If any of these checks fail, you will need to address the issues before your PR can be merged. You can click on the details for any failed check to get more information about what went wrong.

This automation will check for:

  • All unit tests are passing (no failing tests allowed)
  • The number of passing tests in your PR is strictly greater than the number of tests currently in the main branch

Note that just because your code passes these automated checks does not necessarily mean that your contribution is correct. You should still be sure to review your code and test cases carefully before submitting your pull request.

Written Report (README)

You must also write a short two-paragraph report reflecting on your experience contributing to a git repository. In addition to these two paragraphs, your report should also contain references for any resources you used to help complete this assignment.

The first paragraph should contain an overview of the issue you selected, the nature of the bug you repaired, and the additional tests you developed to reveal the bug.

The second paragraph should address the challenges you faced and concepts you learned. Rather than write this as a chronological narrative, organize your prose around key themes. If a particular task took you a while or took you multiple tries to get correct, focus some of your description here.

Finally, your written report should contain your list of references used for completing this assignment.

Submit this report as a PDF on Gradescope. Any other format may cause you to lose points on this asignment.

What to Submit for P2

Checkpoint 1

By the checkpoint deadline:

  • Select an issue from the main project repository and add discussion
  • Submit a PR with your updated code and test case(s)

You do not need to submit any files to Gradescope for the checkpoint. You will be graded based on your contributions to the main project repository.

Checkpoint 2

By the checkpoint deadline:

  • Review your assigned PR and provide feedback on the quality of the contribution and the organization of commits.

You do not need to submit any files to Gradescope for the checkpoint. You will be graded based on your contributions to the main project repository.

Final Submission

For the final project submission, you should submit your written report on Gradescope.

Grading Rubric

P2 Grading (out of 45 points):

  • 15 points: Checkpoint 1
    • 5 points — create pull request before the deadline
    • 5 points — issue selected and commented on before the deadline
    • 5 points — quality of prose and organization of commits
  • 15 points: Checkpoint 2 — Review of assigned PR
    • 15 — Review is thorough, ensures that the contribution are correct (both in content and format), and the comment approving the PR is descriptive.
    • 10 — Review is good, but might have allowed some mistakes in the contribution. The comment approving the PR, however, is descriptive.
    • 7 — Review is adequate, but might have allowed some mistakes in the contribution. The comment approving the PR, lacks sufficient description.
    • 5 — Review fails to catch many errors in the contributed PR or the approving comment is extremely terse, without much detail.
    • 2 — Review is completed, but lacks nearly all required level of detail.
    • 0 — Assigned review is not completed.
  • 8 points: PR Merged into Repository
    • To receive full credit, nearly all of your contributed commits, issues, and PRs must have proper formatting, including descriptive message bodies.
    • Failure to adhere to our course guidelines for high-quality messages will result in a reduction on this score.
    • Use feedback you receive from the checkpoint to improve your PR before the deadline. You may continue to update your PR in an effort to have it merged, but you will not receive credit for a PR that is not merged by the deadline.
  • 5 points: Written report
    • 5 — a two-paragraph report reflecting on your activities using git. One paragraph the challenges faced and concepts you learned. The second paragraph reflects on the challenges you faced and the concepts you learned.
    • 4 — a reasonable report, but lacking a solid description of one or more aspects or significantly exceeding the length limit.
    • 3 — a brief report, detailing only half of the required information, but mentioning both required topics.
    • 2 — a brief report, detailing only half of the required information.
    • 1 — a terse or uninformative report.
    • 0 — No README file provided.
  • 2 points: References
    • 2 — References are provided as part of the final report and contain a list of resources used for this assignment. This includes course materials.
    • 1 — References file exists, but does not adequately identify resources used for this assignment.
    • 0 — No references file provided.