From 9f02043b795d17772c9cb2f964c98fdf6ae5c765 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Fri, 28 Nov 2025 23:29:31 -0500 Subject: [PATCH 01/25] Experimenting with new actions --- .github/workflows/test.yml | 25 +++++++++++++++++++ .../autotag.yaml | 0 .../autotest.yml | 0 .../triage_issues.yml | 0 4 files changed, 25 insertions(+) create mode 100644 .github/workflows/test.yml rename {.github/workflows => workflows-archive}/autotag.yaml (100%) rename {.github/workflows => workflows-archive}/autotest.yml (100%) rename {.github/workflows => workflows-archive}/triage_issues.yml (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..7992fa2 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,25 @@ +name: Python CI Pipeline + +on: + push: + branches: ["development"] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install Dependencies + run: + pip install -r requirements.txt + + - name: Run tests + run: pytest -q \ No newline at end of file diff --git a/.github/workflows/autotag.yaml b/workflows-archive/autotag.yaml similarity index 100% rename from .github/workflows/autotag.yaml rename to workflows-archive/autotag.yaml diff --git a/.github/workflows/autotest.yml b/workflows-archive/autotest.yml similarity index 100% rename from .github/workflows/autotest.yml rename to workflows-archive/autotest.yml diff --git a/.github/workflows/triage_issues.yml b/workflows-archive/triage_issues.yml similarity index 100% rename from .github/workflows/triage_issues.yml rename to workflows-archive/triage_issues.yml From 4ca38560a90aa0ad0c39ef7c86f3dddde05b2d6e Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Fri, 28 Nov 2025 23:30:46 -0500 Subject: [PATCH 02/25] Experimenting with new actions --- tests/test_substring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_substring.py b/tests/test_substring.py index 70d2b40..a080210 100644 --- a/tests/test_substring.py +++ b/tests/test_substring.py @@ -15,7 +15,7 @@ def test_equal_substrings(self): def test_partial_substrings(self): score:float = string_utils.calculate_match_degree("software engineering","building engineering") - self.assertEqual(score, 0.9) + self.assertEqual(score, 0.6) if __name__ == "__main__": unittest.main() \ No newline at end of file From a529c6174e1790018e62415ab84531b239839a66 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Fri, 28 Nov 2025 23:55:11 -0500 Subject: [PATCH 03/25] Changed test application and added additional checks --- .github/workflows/test.yml | 9 +++- app/delivery.py | 69 +++++++++++++++++++++++++++ app/string_utils.py | 25 ---------- requirements.txt | 3 +- tests/test_delivery.py | 88 +++++++++++++++++++++++++++++++++++ tests/test_string_distance.py | 23 --------- tests/test_substring.py | 21 --------- 7 files changed, 166 insertions(+), 72 deletions(-) create mode 100644 app/delivery.py delete mode 100644 app/string_utils.py create mode 100644 tests/test_delivery.py delete mode 100644 tests/test_string_distance.py delete mode 100644 tests/test_substring.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7992fa2..e307c66 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,10 +16,17 @@ jobs: uses: actions/setup-python@v5 with: python-version: "3.11" + + - name: Run linter + run: ruff check . + - name: Check formatting + run: black --check . + - name: Install Dependencies run: pip install -r requirements.txt - name: Run tests - run: pytest -q \ No newline at end of file + run: pytest -q + diff --git a/app/delivery.py b/app/delivery.py new file mode 100644 index 0000000..07394dd --- /dev/null +++ b/app/delivery.py @@ -0,0 +1,69 @@ +import math +from typing import Callable + + +class DeliveryMode: + NORMAL = 1 + TURBO = 2 + HYPERJUMP = 3 + + +MODE_SPEED = { + DeliveryMode.NORMAL: 10, # light-minutes per hour + DeliveryMode.TURBO: 25, + DeliveryMode.HYPERJUMP: 100, +} + +# Planet distances from “Galactic Pizza Hub” in light-minutes +PLANET_DISTANCE = { + "Mercury": 3, + "Venus": 2, + "Earth": 0.5, + "Mars": 4, + "Jupiter": 25, + "Saturn": 50, + "Neptune": 200, +} + + +def estimate_delivery_time( + planet: str, + mode: int = DeliveryMode.NORMAL, + surge_load: float = 1.0, + weather_delay_fn: Callable[[], float] = lambda: 0.0, +) -> float: + """ + Estimate total delivery time in hours. + + - `planet`: destination planet name + - `mode`: delivery mode speed multiplier + - `surge_load`: factor (>=1); simulates high-order load + - `weather_delay_fn`: returns number of hours to add (stochastic) + """ + + if planet not in PLANET_DISTANCE: + raise ValueError(f"Unknown destination: {planet}") + + if surge_load < 1: + raise ValueError("surge_load must be >= 1") + + if mode not in MODE_SPEED: + raise ValueError("Invalid delivery mode") + + distance = PLANET_DISTANCE[planet] # light-minutes + + # Base time + speed = MODE_SPEED[mode] + travel_time = distance / speed + + # If distance is extremely large, apply nonlinear fatigue penalty + if distance > 100: + travel_time *= 1.2 # 20% fatigue penalty + + # Weather delay (provided by injected function) + weather_delay = weather_delay_fn() + if weather_delay < 0: + raise ValueError("weather_delay_fn returned negative delay") + + total_time = (travel_time * surge_load) + weather_delay + return round(total_time, 2) diff --git a/app/string_utils.py b/app/string_utils.py deleted file mode 100644 index 3a57a95..0000000 --- a/app/string_utils.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Utility to perform advanced string comparisons. -""" - -from difflib import SequenceMatcher -import textdistance - - -def calculate_match_degree(txt1:str,txt2:str) -> float: - """ - Given two strings, finds the longest common substring. - Returns the degree of the match based on that longest - substring. - """ - match = SequenceMatcher(None, txt1, txt2).find_longest_match() - return match.size/max(len(txt1),len(txt2)) - -def calcualte_text_distance(txt1:str,txt2:str) -> float: - """ - Uses a text distance metric to calculate the similarity - between two texts. This is not a sub-string match but a - comparison of similar terms occurring in both texts. - """ - algs = textdistance.algorithms - return algs.levenshtein.normalized_similarity(txt1, txt2) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 282786f..f9ddc40 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ -pytest==8.3.3 -textdistance==4.6.3 \ No newline at end of file +pytest==8.3.3 \ No newline at end of file diff --git a/tests/test_delivery.py b/tests/test_delivery.py new file mode 100644 index 0000000..ca954e0 --- /dev/null +++ b/tests/test_delivery.py @@ -0,0 +1,88 @@ + +# Make sure the test finds the application code +import os +import sys +sys.path.insert(0, os.path.abspath('.')) + +import pytest +from app.delivery import estimate_delivery_time, DeliveryMode + + +def no_weather(): + return 0.0 + + +def fixed_weather(): + return 2.5 + + +# ------------------------------ +# Black-box functional tests +# ------------------------------ + +def test_basic_delivery_normal_mode(): + """Earth is 0.5 lm away; NORMAL speed 10 lm/hr → 0.05 hr.""" + assert estimate_delivery_time("Earth", DeliveryMode.NORMAL, 1.0, no_weather) == 0.05 + + +def test_turbo_delivery(): + """Mars (4 lm) at TURBO speed 25 → 0.16.""" + assert estimate_delivery_time("Mars", DeliveryMode.TURBO, 1.0, no_weather) == 0.16 + + +def test_weather_delay_added(): + """Jupiter (25 lm at 10 lm/hr = 2.5 hr) + 2.5 hr weather.""" + assert estimate_delivery_time("Jupiter", DeliveryMode.NORMAL, 1.0, fixed_weather) == 5.0 + + +# ------------------------------ +# Error-handling tests +# ------------------------------ + +def test_invalid_planet(): + with pytest.raises(ValueError): + estimate_delivery_time("Pluto", DeliveryMode.NORMAL, 1.0, no_weather) + + +def test_invalid_mode(): + with pytest.raises(ValueError): + estimate_delivery_time("Earth", 999, 1.0, no_weather) + + +def test_invalid_surge_load(): + with pytest.raises(ValueError): + estimate_delivery_time("Earth", DeliveryMode.NORMAL, 0.5, no_weather) + + +def test_negative_weather_delay(): + with pytest.raises(ValueError): + estimate_delivery_time("Earth", DeliveryMode.NORMAL, 1.0, lambda: -1) + + +# ------------------------------ +# Boundary value tests +# ------------------------------ + +def test_boundary_no_fatigue_penalty(): + """Distance = 50 → below 100, so no fatigue penalty.""" + assert estimate_delivery_time("Saturn", DeliveryMode.HYPERJUMP, 1.0, no_weather) == 0.5 + + +def test_fatigue_penalty_kicks_in(): + """Neptune = 200 lm → fatigue penalty applied (×1.2).""" + base = 200 / 100 # HYPERJUMP speed + expected = round((base * 1.2), 2) + assert estimate_delivery_time("Neptune", DeliveryMode.HYPERJUMP, 1.0, no_weather) == expected + + +# ------------------------------ +# Category partitioning tests +# ------------------------------ + +@pytest.mark.parametrize("planet", ["Earth", "Mars"]) +@pytest.mark.parametrize("mode", [DeliveryMode.NORMAL, DeliveryMode.TURBO]) +@pytest.mark.parametrize("surge", [1.0, 1.5]) +def test_category_partitioning(planet, mode, surge): + """Planet × mode × surge cartesian test.""" + result = estimate_delivery_time(planet, mode, surge, no_weather) + assert result > 0 diff --git a/tests/test_string_distance.py b/tests/test_string_distance.py deleted file mode 100644 index 61a6bd3..0000000 --- a/tests/test_string_distance.py +++ /dev/null @@ -1,23 +0,0 @@ - -# Make sure the test finds the application code -import os -import sys -sys.path.insert(0, os.path.abspath('.')) - -import unittest -from app import string_utils - -class TestStringDistance(unittest.TestCase): - - def test_similar_text(self): - score:float = string_utils.calcualte_text_distance("Software engineering is the cornerstone of a successful software project.","Building engineering is the cornerstone of a successful building project.") - self.assertGreater(score, 0.7) - self.assertLess(score,0.8) - - def test_non_similar_text(self): - score:float = string_utils.calcualte_text_distance("Requirements are a first level entity in Agile development","Microservices have helped address scalibility issues in today's cloud environments.") - self.assertGreater(score, 0.3) - self.assertLess(score,0.4) - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests/test_substring.py b/tests/test_substring.py deleted file mode 100644 index a080210..0000000 --- a/tests/test_substring.py +++ /dev/null @@ -1,21 +0,0 @@ - -# Make sure the test finds the application code -import os -import sys -sys.path.insert(0, os.path.abspath('.')) - -import unittest -from app import string_utils - -class TestSubstring(unittest.TestCase): - - def test_equal_substrings(self): - score:float = string_utils.calculate_match_degree("software engineering","software engineering") - self.assertEqual(score, 1) - - def test_partial_substrings(self): - score:float = string_utils.calculate_match_degree("software engineering","building engineering") - self.assertEqual(score, 0.6) - -if __name__ == "__main__": - unittest.main() \ No newline at end of file From 06b85ecf9dd8b749021e975187b2368df1fa8251 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Fri, 28 Nov 2025 23:59:21 -0500 Subject: [PATCH 04/25] Fixed build errors --- .github/workflows/test.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e307c66..764e878 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,11 +17,16 @@ jobs: with: python-version: "3.11" - - name: Run linter - run: ruff check . - - - name: Check formatting - run: black --check . + - name: Install lint tools + run: pip install flake8 black + + + - name: Run black (check) + run: python -m black --check . + + + - name: Run flake8 + run: flake8 . - name: Install Dependencies run: From d1b4b99ae24cec78ad4e8784c7a04d6190ba6b5b Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 29 Nov 2025 00:04:59 -0500 Subject: [PATCH 05/25] Fixed build errors --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 764e878..56c35d7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: - name: Run black (check) - run: python -m black --check . + run: python -m black --diff . - name: Run flake8 From 828a15d10b8dd98935f3b16a190b0033e1e8f406 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 29 Nov 2025 00:08:20 -0500 Subject: [PATCH 06/25] Fixed build errors --- .github/workflows/test.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 56c35d7..62db20b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,12 +18,7 @@ jobs: python-version: "3.11" - name: Install lint tools - run: pip install flake8 black - - - - name: Run black (check) - run: python -m black --diff . - + run: pip install flake8 - name: Run flake8 run: flake8 . From d2e879075ab9efbadc8ab4cd959555c88ccbc4df Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 15:36:07 -0500 Subject: [PATCH 07/25] Added new actions --- .github/workflows/deploy.yml | 26 +++++++ .github/workflows/release.yml | 41 +++++++++++ .vscode/settings.json | 32 ++++++++- README.md | 32 +++++++++ __version__.py | 7 ++ deployment/update_release_notes.py | 50 +++++++++++++ deployment/update_version_number.py | 70 +++++++++++++++++++ {app => spacedelivery}/delivery.py | 0 spacedelivery/web/estimator.js | 70 +++++++++++++++++++ spacedelivery/web/index.html | 39 +++++++++++ spacedelivery/web/style.css | 54 ++++++++++++++ tests/test_delivery.py | 2 +- workflows-archive/build_docker.yml | 22 ++++++ .../config}/issue-rules.yml | 0 14 files changed, 443 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/release.yml create mode 100644 __version__.py create mode 100644 deployment/update_release_notes.py create mode 100644 deployment/update_version_number.py rename {app => spacedelivery}/delivery.py (100%) create mode 100644 spacedelivery/web/estimator.js create mode 100644 spacedelivery/web/index.html create mode 100644 spacedelivery/web/style.css create mode 100644 workflows-archive/build_docker.yml rename {config => workflows-archive/config}/issue-rules.yml (100%) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..f4bb467 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,26 @@ +name: Deploy to GitHub Pages + +on: + push: + branches: ["main"] + +permissions: + contents: read + pages: write + id-token: write + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Upload static site + uses: actions/upload-pages-artifact@v2 + with: + path: . + + - name: Deploy to GitHub Pages + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..98bb66f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,41 @@ +name: Add Release Notes to README + +on: + pull_request: + types: [opened] + +jobs: + update_readme: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Increase version number + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + python deployment/update_version_number.py + + - name: Update release notes + env: + PR_TITLE: ${{ github.event.pull_request.title }} + PR_BODY: ${{ github.event.pull_request.body }} + run: | + python deployment/update_release_notes.py + + - name: Commit changes + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add README.md + git commit -m "Add release notes for PR #${{ github.event.pull_request.number }}" || echo "No changes to commit" + git push diff --git a/.vscode/settings.json b/.vscode/settings.json index 8fc7789..37e28eb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,5 +12,35 @@ "coverage-gutters.showLineCoverage": true, "python.testing.pytestArgs": [ "tests" - ] + ], + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/Thumbs.db": true, + "**/*.pyc": { + "when": "$(basename).py" + }, + "**/__pycache__": true, + "**/app.egg-info": true, + "**/env": true, + "**/.env.dist": true, + "**/*.log": true, + "**/.0": true + }, + "workbench.colorCustomizations": { + "tab.activeBorder": "#ff0000", + "tab.unfocusedActiveBorder": "#000000", + "tab.activeBackground": "#045980" + }, + "workbench.editor.wrapTabs": true, + "debug.toolBarLocation": "docked", + "python.formatting.provider": "autopep8", + "editor.formatOnSave": true, + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.REPL.enableREPLSmartSend": false } \ No newline at end of file diff --git a/README.md b/README.md index f283c09..a80ea8f 100644 --- a/README.md +++ b/README.md @@ -125,3 +125,35 @@ After you created the file and copied the action above, push the change to the r * **Task C**: Add a test case to either test file and push your changes to your repository. Check the run of the action to see what status is finishes with. * **Task D**: You will notice that the action shows a red x after it has completed its run. Investigate why that action failed. Resolve the issue and push to the repository to trigger the action again. + + + + +Task 1 + +Automated testing on commit + +a) Create a new branch called `test` and push it to the repository. Then create a PR for that branch. +b) Observe the test results +c) Introduce a bug and push. Observe the test results. + + + +Task 2 + +Add release notes to README + +a) Create a new branch called `release` and push it to the repository. +b) Then create a PR for that branch and add a bulleted list of changes. +b) Check that the release notes are added to the `README.md` file. + + +Task 3 + +Deploy on merge + +a) Create a new branch called `deploy1` and push it to the repository. Then create a PR for that branch. +b) Merge the PR into `main`. +c) Navigate to the deployed app +d) Change the app title and create a new PR. Merge the PR into `main`. Navigate to the deployed app again.Observe the changes. + diff --git a/__version__.py b/__version__.py new file mode 100644 index 0000000..c046acc --- /dev/null +++ b/__version__.py @@ -0,0 +1,7 @@ +# coding: utf-8 + +__title__ = 'enpm611-ghactions' +__version__ = '1.3.8' +__author__ = 'ENPM611' +__url__ = 'https://github.com/enpm611/github-actions' +__description__ = ("Exercise to use GitHub Actions for CI/CD task.") diff --git a/deployment/update_release_notes.py b/deployment/update_release_notes.py new file mode 100644 index 0000000..20e6112 --- /dev/null +++ b/deployment/update_release_notes.py @@ -0,0 +1,50 @@ + + +import os +import re +from datetime import datetime +from pathlib import Path + + +def get_current_version() -> str: + # Read version file + VERSION_FILE = Path("__version__.py") + version_text = VERSION_FILE.read_text() + # Extract current version string + match = re.search(r"__version__\s*=\s*['\"](\d+\.\d+\.\d+)['\"]", version_text) + if not match: + raise ValueError("Could not find __version__ in file.") + return match.group(1) + + +def update_release_notes() -> None: + + # Read the environment variables that were passed in from + # the GitHub Action workflow. + pr_title: str = os.environ.get("PR_TITLE", "").strip() + pr_body: str = os.environ.get("PR_BODY", "").strip() + # Check for missing environment variables + if not pr_title: + raise ValueError("PR_TITLE environment variable is missing.") + + # Get current version from version file + version: str = get_current_version() + + # Create release note entry + date_str: str = datetime.utcnow().strftime("%Y-%m-%d") + entry_lines: list[str] = [ + "", + f"## Release Notes — v{version} — {pr_title} ({date_str})", + "", + pr_body, + "", + ] + + # Append to README + with open("README.md", "a", encoding="utf-8") as f: + f.write("\n".join(entry_lines)) + + print("README updated with release notes.") + +if __name__ == "__main__": + update_release_notes() diff --git a/deployment/update_version_number.py b/deployment/update_version_number.py new file mode 100644 index 0000000..7ad249a --- /dev/null +++ b/deployment/update_version_number.py @@ -0,0 +1,70 @@ + +""" +Bumps the version number in the `__version__.py` file when a Pull +Request is created. +""" + + +import re +import os +from pathlib import Path +from typing import Any, Literal + + +def get_current_version(version_text:str) -> str: + # Extract current version string + match = re.search(r"__version__\s*=\s*['\"](\d+\.\d+\.\d+)['\"]", version_text) + if not match: + raise ValueError("Could not find __version__ in file.") + return match.group(1) + +def get_release_type() -> Literal["patch", "minor", "major"]: + """ Determine the type of release based on the PR title """ + + # Read release title from env + pr_title: str = os.environ.get("PR_TITLE", "").strip() + # Determine release type based on terms in title + if "minor" in pr_title.lower(): + return "minor" + elif "major" in pr_title.lower(): + return "major" + else: + return "patch" + +def bump_version(): + + # Read version file + VERSION_FILE = Path("__version__.py") + version_text = VERSION_FILE.read_text() + + old_version: str = get_current_version(version_text) + major, minor, patch = map(int, old_version.split(".")) + + # Increment based on the requested level + level: Literal['patch', 'minor', 'major'] = get_release_type() + if level == "patch": + patch += 1 + elif level == "minor": + minor += 1 + patch = 0 + elif level == "major": + major += 1 + minor = 0 + patch = 0 + else: + raise ValueError("level must be 'major', 'minor', or 'patch'") + + new_version = f"{major}.{minor}.{patch}" + + # Replace the version string in the file + new_text = version_text.replace(old_version,new_version) + + VERSION_FILE.write_text(new_text) + print(f"Version bumped to {new_version}") + return new_version + + + + +if __name__ == "__main__": + bump_version() diff --git a/app/delivery.py b/spacedelivery/delivery.py similarity index 100% rename from app/delivery.py rename to spacedelivery/delivery.py diff --git a/spacedelivery/web/estimator.js b/spacedelivery/web/estimator.js new file mode 100644 index 0000000..d456db9 --- /dev/null +++ b/spacedelivery/web/estimator.js @@ -0,0 +1,70 @@ +const PLANET_DISTANCE = { + Mercury: 3, + Venus: 2, + Earth: 0.5, + Mars: 4, + Jupiter: 25, + Saturn: 50, + Neptune: 200, +}; + +const MODE_SPEED = { + 1: 10, // NORMAL + 2: 25, // TURBO + 3: 100, // HYPERJUMP +}; + +// Populate planet dropdown +window.onload = () => { + const select = document.getElementById("planet"); + Object.keys(PLANET_DISTANCE).forEach((planet) => { + const option = document.createElement("option"); + option.value = planet; + option.textContent = planet; + select.appendChild(option); + }); +}; + +function estimateDeliveryTime(planet, mode, surgeLoad, weatherDelay) { + if (!(planet in PLANET_DISTANCE)) { + throw new Error("Unknown destination"); + } + if (!(mode in MODE_SPEED)) { + throw new Error("Invalid delivery mode"); + } + if (surgeLoad < 1) { + throw new Error("surgeLoad must be >= 1"); + } + if (weatherDelay < 0) { + throw new Error("weatherDelay must be >= 0"); + } + + const distance = PLANET_DISTANCE[planet]; + const speed = MODE_SPEED[mode]; + + let travelTime = distance / speed; + + // Fatigue penalty for extreme distances + if (distance > 100) { + travelTime *= 1.2; + } + + const total = travelTime * surgeLoad + weatherDelay; + return Math.round(total * 100) / 100; +} + +// Wire UI to estimator +document.getElementById("estimate").onclick = () => { + const planet = document.getElementById("planet").value; + const mode = Number(document.getElementById("mode").value); + const surge = Number(document.getElementById("surge").value); + const weather = Number(document.getElementById("weather").value); + + try { + const time = estimateDeliveryTime(planet, mode, surge, weather); + document.getElementById("result").textContent = + `Estimated delivery time: ${time} hours`; + } catch (err) { + document.getElementById("result").textContent = "Error: " + err.message; + } +}; diff --git a/spacedelivery/web/index.html b/spacedelivery/web/index.html new file mode 100644 index 0000000..df4c568 --- /dev/null +++ b/spacedelivery/web/index.html @@ -0,0 +1,39 @@ + + + + + + Galactic Pizza Delivery Estimator + + + + +
+

🚀 Galactic Pizza Delivery Estimator

+ +
+ + + + + + + + + + + + + +
+ +
+
+ + + + diff --git a/spacedelivery/web/style.css b/spacedelivery/web/style.css new file mode 100644 index 0000000..26363cd --- /dev/null +++ b/spacedelivery/web/style.css @@ -0,0 +1,54 @@ +body { + font-family: Arial, sans-serif; + background: #0f0f22; + color: #fff; + margin: 0; + padding: 0; +} + +.container { + max-width: 500px; + margin: 50px auto; + background: #1c1c3c; + padding: 20px; + border-radius: 10px; +} + +h1 { + text-align: center; + margin-bottom: 20px; +} + +label { + font-weight: bold; + margin-top: 10px; + display: block; +} + +input, select { + width: 100%; + padding: 8px; + margin-top: 4px; + border-radius: 5px; + border: none; +} + +button { + width: 100%; + padding: 10px; + margin-top: 15px; + background: #00b7ff; + border: none; + border-radius: 5px; + font-size: 16px; + cursor: pointer; +} + +button:hover { + background: #0090cc; +} + +.result { + margin-top: 20px; + font-size: 18px; +} diff --git a/tests/test_delivery.py b/tests/test_delivery.py index ca954e0..94ec226 100644 --- a/tests/test_delivery.py +++ b/tests/test_delivery.py @@ -5,7 +5,7 @@ sys.path.insert(0, os.path.abspath('.')) import pytest -from app.delivery import estimate_delivery_time, DeliveryMode +from spacedelivery.delivery import estimate_delivery_time, DeliveryMode def no_weather(): diff --git a/workflows-archive/build_docker.yml b/workflows-archive/build_docker.yml new file mode 100644 index 0000000..a470636 --- /dev/null +++ b/workflows-archive/build_docker.yml @@ -0,0 +1,22 @@ +name: Build and save Docker image artifact + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build the Docker image + run: docker build . --tag spacedelivery:latest + + - name: Save image to a tar file + run: docker save spacedelivery:latest -o ${{ runner.temp }}/spacedelivery.tar + + - name: Upload Docker image artifact + uses: actions/upload-artifact@v4 + with: + name: docker-image-artifact + path: ${{ runner.temp }}/spacedelivery.tar \ No newline at end of file diff --git a/config/issue-rules.yml b/workflows-archive/config/issue-rules.yml similarity index 100% rename from config/issue-rules.yml rename to workflows-archive/config/issue-rules.yml From 6dfa377693c457ac25eec5dbd64cca4c7ef2cccb Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 15:37:15 -0500 Subject: [PATCH 08/25] Removed linting from action --- .github/workflows/test.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 62db20b..fe6ece7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,16 +17,8 @@ jobs: with: python-version: "3.11" - - name: Install lint tools - run: pip install flake8 - - - name: Run flake8 - run: flake8 . - - name: Install Dependencies - run: - pip install -r requirements.txt + run: pip install -r requirements.txt - name: Run tests run: pytest -q - From 46d112a73538c038fbd494484b96b2f2430c9371 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 15:38:30 -0500 Subject: [PATCH 09/25] Added a bug --- tests/test_delivery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_delivery.py b/tests/test_delivery.py index 94ec226..908388d 100644 --- a/tests/test_delivery.py +++ b/tests/test_delivery.py @@ -22,7 +22,7 @@ def fixed_weather(): def test_basic_delivery_normal_mode(): """Earth is 0.5 lm away; NORMAL speed 10 lm/hr → 0.05 hr.""" - assert estimate_delivery_time("Earth", DeliveryMode.NORMAL, 1.0, no_weather) == 0.05 + assert estimate_delivery_time("Earth", DeliveryMode.NORMAL, 1.0, no_weather) == 0.06 def test_turbo_delivery(): From 962222f27d8dab47b276e6403577259a2983cd67 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 15:46:49 -0500 Subject: [PATCH 10/25] Fixed the release action --- .github/workflows/release.yml | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 98bb66f..e23b047 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: - fetch-depth: 0 + ref: ${{ github.head_ref }} - name: Set up Python uses: actions/setup-python@v5 diff --git a/README.md b/README.md index a80ea8f..a785831 100644 --- a/README.md +++ b/README.md @@ -134,8 +134,8 @@ Task 1 Automated testing on commit a) Create a new branch called `test` and push it to the repository. Then create a PR for that branch. -b) Observe the test results -c) Introduce a bug and push. Observe the test results. +b) Observe the test results. If there is a bug, update the test case to match the value that is returned by the function. +c) Push the updated code. Observe the test results. From 581a07d2b0b93f5e00fc8bed0675326d3bbeaf64 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 15:47:38 -0500 Subject: [PATCH 11/25] Removed bug --- tests/test_delivery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_delivery.py b/tests/test_delivery.py index 908388d..94ec226 100644 --- a/tests/test_delivery.py +++ b/tests/test_delivery.py @@ -22,7 +22,7 @@ def fixed_weather(): def test_basic_delivery_normal_mode(): """Earth is 0.5 lm away; NORMAL speed 10 lm/hr → 0.05 hr.""" - assert estimate_delivery_time("Earth", DeliveryMode.NORMAL, 1.0, no_weather) == 0.06 + assert estimate_delivery_time("Earth", DeliveryMode.NORMAL, 1.0, no_weather) == 0.05 def test_turbo_delivery(): From 593ac4d5b563e9d70da99d1885eb07cf4d59158d Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 15:52:06 -0500 Subject: [PATCH 12/25] Added permissions for action --- .github/workflows/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e23b047..02a8452 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,9 @@ on: pull_request: types: [opened] +permissions: + contents: write + pull-requests: write jobs: update_readme: runs-on: ubuntu-latest From 6f70d1d7f15356e170f4bf7375ee24ae4baa6ced Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 6 Dec 2025 20:52:51 +0000 Subject: [PATCH 13/25] Add release notes for PR #12 --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a785831..ada291d 100644 --- a/README.md +++ b/README.md @@ -157,3 +157,8 @@ b) Merge the PR into `main`. c) Navigate to the deployed app d) Change the app title and create a new PR. Merge the PR into `main`. Navigate to the deployed app again.Observe the changes. + +## Release Notes — v2.0.0 — Major changes (2025-12-06) + +- Big deal changes +- Minor bug fixes From b9d5102fca5fdea97c5c9b68bd738987209ab917 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 15:58:28 -0500 Subject: [PATCH 14/25] Fixed pushing version changes --- .github/workflows/release.yml | 1 + README.md | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 02a8452..9a5dd50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,6 +39,7 @@ jobs: run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" + git add __version__.py git add README.md git commit -m "Add release notes for PR #${{ github.event.pull_request.number }}" || echo "No changes to commit" git push diff --git a/README.md b/README.md index ada291d..b491a77 100644 --- a/README.md +++ b/README.md @@ -157,8 +157,5 @@ b) Merge the PR into `main`. c) Navigate to the deployed app d) Change the app title and create a new PR. Merge the PR into `main`. Navigate to the deployed app again.Observe the changes. +# Release Notes -## Release Notes — v2.0.0 — Major changes (2025-12-06) - -- Big deal changes -- Minor bug fixes From 628740805c457dde0e82104176e811128fc0b880 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 6 Dec 2025 20:59:16 +0000 Subject: [PATCH 15/25] Add release notes for PR #13 --- README.md | 6 ++++++ __version__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b491a77..53d2227 100644 --- a/README.md +++ b/README.md @@ -159,3 +159,9 @@ d) Change the app title and create a new PR. Merge the PR into `main`. Navigate # Release Notes + +## Release Notes — v1.4.0 — Minor release with changes to the delivery logic (2025-12-06) + +- Added more pizza varieties +- Now also delivering to Mars! +- Cleanup and bug fixes diff --git a/__version__.py b/__version__.py index c046acc..beadd94 100644 --- a/__version__.py +++ b/__version__.py @@ -1,7 +1,7 @@ # coding: utf-8 __title__ = 'enpm611-ghactions' -__version__ = '1.3.8' +__version__ = '1.4.0' __author__ = 'ENPM611' __url__ = 'https://github.com/enpm611/github-actions' __description__ = ("Exercise to use GitHub Actions for CI/CD task.") From 29948e1f7b2e217bfdddb0275ba25c3a72a66f20 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 16:02:53 -0500 Subject: [PATCH 16/25] Testing deployment --- .github/workflows/deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f4bb467..b9140a0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,7 +2,7 @@ name: Deploy to GitHub Pages on: push: - branches: ["main"] + branches: ["development"] permissions: contents: read @@ -20,7 +20,7 @@ jobs: - name: Upload static site uses: actions/upload-pages-artifact@v2 with: - path: . + path: spacedelivery/web - name: Deploy to GitHub Pages uses: actions/deploy-pages@v4 From 5aafc17284f2db81635563e56fa905c5238cd94f Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 16:08:08 -0500 Subject: [PATCH 17/25] Testing fixing build --- .github/workflows/deploy.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b9140a0..e94587d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,12 +14,10 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout source - uses: actions/checkout@v4 - - - name: Upload static site - uses: actions/upload-pages-artifact@v2 + - name: Download built site + uses: actions/download-artifact@v4 with: + name: site path: spacedelivery/web - name: Deploy to GitHub Pages From 4145ea2c0e97b66fece300d3d29b077b79713c29 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 16:11:20 -0500 Subject: [PATCH 18/25] Testing fixing build --- .github/workflows/deploy.yml | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e94587d..2ae491b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,15 +10,26 @@ permissions: id-token: write jobs: - deploy: + build: runs-on: ubuntu-latest steps: - - name: Download built site - uses: actions/download-artifact@v4 + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Upload site files + uses: actions/upload-pages-artifact@v2 with: - name: site - path: spacedelivery/web + path: ./spacedelivery/web # the folder containing index.html + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deploy-pages.outputs.page_url }} + steps: - name: Deploy to GitHub Pages + id: deploy-pages uses: actions/deploy-pages@v4 From 1973fbfc9058e37c80b5515a317b01eaede670b3 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 16:13:59 -0500 Subject: [PATCH 19/25] Testing fixing build --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2ae491b..69aac52 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Upload site files - uses: actions/upload-pages-artifact@v2 + uses: actions/upload-artifact@v4 with: path: ./spacedelivery/web # the folder containing index.html From 7cd8cea5a94c1c0dfba5325351f8c5c64795645a Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 17:26:36 -0500 Subject: [PATCH 20/25] Testing fixing build --- .github/workflows/deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 69aac52..475a9bd 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -21,6 +21,7 @@ jobs: uses: actions/upload-artifact@v4 with: path: ./spacedelivery/web # the folder containing index.html + name: github-pages deploy: needs: build From 298ad55acc2cc329e9f03b76782d10cbdd9f4686 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 17:32:02 -0500 Subject: [PATCH 21/25] Testing fixing build --- .github/workflows/deploy.yml | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 475a9bd..f588adf 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,14 +23,34 @@ jobs: path: ./spacedelivery/web # the folder containing index.html name: github-pages + # deploy: + # needs: build + # runs-on: ubuntu-latest + # environment: + # name: github-pages + # url: ${{ steps.deploy-pages.outputs.page_url }} + + # steps: + # - name: Deploy to GitHub Pages + # id: deploy-pages + # uses: actions/deploy-pages@v4 + deploy: needs: build - runs-on: ubuntu-latest environment: name: github-pages - url: ${{ steps.deploy-pages.outputs.page_url }} - + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: "./spacedelivery/web" - name: Deploy to GitHub Pages - id: deploy-pages + id: deployment uses: actions/deploy-pages@v4 From 3a06c80eaf662c5b60925085b091542911329b78 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 22:15:49 -0500 Subject: [PATCH 22/25] Testing fixing build --- .github/workflows/deploy.yml | 43 +++++++++++++----------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f588adf..1e307f2 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,42 +1,29 @@ -name: Deploy to GitHub Pages +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages on: + # Runs on pushes targeting the default branch push: branches: ["development"] + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Upload site files - uses: actions/upload-artifact@v4 - with: - path: ./spacedelivery/web # the folder containing index.html - name: github-pages - - # deploy: - # needs: build - # runs-on: ubuntu-latest - # environment: - # name: github-pages - # url: ${{ steps.deploy-pages.outputs.page_url }} - - # steps: - # - name: Deploy to GitHub Pages - # id: deploy-pages - # uses: actions/deploy-pages@v4 +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false +jobs: + # Single deploy job since we're just deploying deploy: - needs: build environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} @@ -50,7 +37,7 @@ jobs: uses: actions/upload-pages-artifact@v3 with: # Upload entire repository - path: "./spacedelivery/web" + path: "." - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 From cb97d42d4cfca504279fc1ee131bd5aa14951288 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sat, 6 Dec 2025 22:18:54 -0500 Subject: [PATCH 23/25] Testing fixing build --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 1e307f2..189bfba 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -37,7 +37,7 @@ jobs: uses: actions/upload-pages-artifact@v3 with: # Upload entire repository - path: "." + path: "./spacedelivery/web" - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 From e3a74cbba90826a20473e8d7435900bbdf84d330 Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sun, 7 Dec 2025 13:28:58 -0500 Subject: [PATCH 24/25] Updated README and prepared exercises --- .github/workflows/deploy.yml | 43 --- .github/workflows/release.yml | 45 --- .github/workflows/test.yml | 24 -- README.md | 290 +++++++++++++----- .../update_release_notes.py | 0 .../update_version_number.py | 0 docs/github_actions_exercises.svg | 3 + tests/test_delivery.py | 2 +- workflows-archive/autotag.yaml | 18 -- workflows-archive/autotest.yml | 22 -- workflows-archive/build_docker.yml | 22 -- workflows-archive/config/issue-rules.yml | 15 - workflows-archive/triage_issues.yml | 46 --- 13 files changed, 220 insertions(+), 310 deletions(-) delete mode 100644 .github/workflows/deploy.yml delete mode 100644 .github/workflows/release.yml delete mode 100644 .github/workflows/test.yml rename {deployment => deployment_scripts}/update_release_notes.py (100%) rename {deployment => deployment_scripts}/update_version_number.py (100%) create mode 100644 docs/github_actions_exercises.svg delete mode 100644 workflows-archive/autotag.yaml delete mode 100644 workflows-archive/autotest.yml delete mode 100644 workflows-archive/build_docker.yml delete mode 100644 workflows-archive/config/issue-rules.yml delete mode 100644 workflows-archive/triage_issues.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 189bfba..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,43 +0,0 @@ -# Simple workflow for deploying static content to GitHub Pages -name: Deploy static content to Pages - -on: - # Runs on pushes targeting the default branch - push: - branches: ["development"] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Single deploy job since we're just deploying - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Pages - uses: actions/configure-pages@v5 - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - # Upload entire repository - path: "./spacedelivery/web" - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 9a5dd50..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Add Release Notes to README - -on: - pull_request: - types: [opened] - -permissions: - contents: write - pull-requests: write -jobs: - update_readme: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ github.head_ref }} - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - - name: Increase version number - env: - PR_TITLE: ${{ github.event.pull_request.title }} - run: | - python deployment/update_version_number.py - - - name: Update release notes - env: - PR_TITLE: ${{ github.event.pull_request.title }} - PR_BODY: ${{ github.event.pull_request.body }} - run: | - python deployment/update_release_notes.py - - - name: Commit changes - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add __version__.py - git add README.md - git commit -m "Add release notes for PR #${{ github.event.pull_request.number }}" || echo "No changes to commit" - git push diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index fe6ece7..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Python CI Pipeline - -on: - push: - branches: ["development"] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install Dependencies - run: pip install -r requirements.txt - - - name: Run tests - run: pytest -q diff --git a/README.md b/README.md index 53d2227..3251436 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ # GitHub Actions Experiments -This repository illustrates how GitHub Actions can be used to automate software development processes. GitHub Actions are scripts that run on a containerized platform hosted on GitHub. A GitHub action is defined by creating a `.yml` file in the `.github/workflows` directory of a repository (as done here). Such an action needs to be follow a specific format as described in the [GitHub documentation](https://docs.github.com/en/actions/about-github-actions/understanding-github-actions). An example is provided in the `triage_issues.yml` action file: +This repository illustrates how GitHub Actions can be used to automate software development processes. + +## Introduction + +### What are GitHub Actions? + +GitHub Actions are scripts that run on a containerized platform hosted on GitHub. A GitHub action is defined by creating a `.yml` file in the `.github/workflows` directory of a repository (as done here). Such an action needs to be follow a specific format as described in the [GitHub documentation](https://docs.github.com/en/actions/about-github-actions/understanding-github-actions). An example is provided in the `triage_issues.yml` action file: ```yaml name: "Label Issues for Triage" @@ -34,134 +40,270 @@ If you are familiar with **containerized applications**, you will notice familia Now that you understand the basic structure of a GitHub Action, we will see on in, well, action. -## Exercise 1 - Issue Action +### 🚀 Galactic Pizza Delivery Time Estimator + +In this exercise, you will work with a small application called the **Galactic Pizza Delivery Time Estimator**. The program calculates how long it takes to deliver a pizza to different planets using several factors: the destination distance, the delivery mode (normal, turbo, or hyperjump), a surge-load multiplier, and a weather-delay component. Some planets involve long-distance fatigue penalties, while incorrect inputs or unexpected weather values trigger errors. + +The application can be found in in the `spacedelivery` folder. There are two versions: + +- `python`: the Python version is a single module (`delivery.py`) and just one function. That module will be used for illustrating **building**, **testing**, and **releasing** an applications using GitHub Actions. +- `web` : the web version is a static web application of essentially the same functionality as the Python version. It also implments a user interface. This version is used to illustrate how to **deploy** a static web application to GitHub Pages via GitHub Actions. + +The application itself is secondary and only used to illustrate CI/CD concepts. + +### Directory structure + +The directory structure is as follows: + +```bash +actions/ +├── .github/ # GitHub-specific configuration +│ └── workflows/ # This is where GitHub will look for `.yml` Action files. +├── deployment_scripts/ # Python scripts that will be called by the *release* Action +├── spacedelivery/ # Main application package +│ ├── delivery.py # Python module for delivery calculations +│ └── web/ # Web version of the application to be deployed by the *deploy* Action +├── tests/ # Tests that will be executed by the *test* Action +├── __version__.py # Version information to be updated by the *release* Action +└── requirements.txt # Python dependencies that will be installed during the *build* Action +``` + +### Getting Started + +Fork the repository and clone it to your local machine. Then create a new branch called `development`: + +```bash +git checkout -b development +``` + +All exercises will be done on the `development` branch that we will merge into the `main` branch occasionally. -In this exercise, we will run our first GitHub Action It is already defined so you don't have to do too much to see it execute and the result of its execution. +## Exercises -Let's assume we have developed an application that is open source and is wildly popular with developers. As developers use your application, they also find bugs and ways to improve the application. When they do, they usually submit a GitHub issue. We need a way of making sure that we triage all the new issues appropriately. In this exercise, we will work with a GitHub Action that automatically tags all new issues that are submitted with the label `triage`. +This lab gradually builds up a CI/CD pipeline using GitHub Actions. As you know, Continuous Integration (CI) and Continuous Deployment (CD) are practices that help teams deliver software quickly and reliably. CI focuses on automatically **building** and **testing** code every time changes are made, ensuring that bugs are caught early and that new work integrates smoothly. CD extends this idea by automatically **releasing** and **deploying** software after it passes tests. GitHub Actions provides an easy way to implement CI/CD directly within a GitHub repository. By defining simple workflow files, you can automate tasks such as running tests, checking code quality, updating version numbers, or deploying applications—all triggered whenever code is pushed or a pull request is opened. -To see the it in action, simply create a new issue with any title. Stay on the page and wait until the label `triage` magically appears. When it does, you know the GitHub Action did it's job. +The diagram below shows the steps of the CI/CD pipeline that we will build in this lab: -You can also view every run of a GitHub Action by clicking on `Actions` in the repository toolbar. The green checkmark indicates that the run was successful. Clicking on the job name, tells you more about that particular run. On the next page, click on the box that indicates the job that was executed as part of that action. Now you see all the details of the run. +![GitHub Actions Exercises](docs/github_actions_exercises.svg "GitHub Actions Exercises") -## Exercise 2 - Smarter Issue Labeling +We will implement GitHub Actions that are automatically triggered by events in GitHub, namely: +- `push` event: runs tests whenever a new commit is pushed to the repository +- `pull_request` event: runs tests whenever a new pull request is opened against the repository +- `merge` event: runs tests whenever the PR is merged into the `main` branch. -We have already seen an example of labeling issues automatically for triage. However, we might want GitHub Actions to perform smarter tagging by recognizing what type of issue the user submitted. We can implement it from scratch or we can use an [existing library](https://github.com/damccorm/tag-ur-it) to do most of the work for us. The repository description for [`tag-ur-it`](https://github.com/damccorm/tag-ur-it) describes how to set up and configure custom labeling. +These events will trigger GitHub Actions to build, test (`test.yml`), release (`release.yml`), and deploy (`deploy.yml`) the application. You will create this Actions as you follow the exercise instructions. -Create a new file `.github/workflows/autotag.yaml` and copy in the following content: +## Exercise 1: **Testing** + +One of the tasks that goes along with making changes to your code is testing. We have learned how to create test cases and even implemented unit tests that can be executed automatically. As part of a CI (Continuous Integration) pipeline, we can run tests automatically whenever a new commit is pushed to the repository. In this exercise, we will integrate that part of the CI pipeline using GitHub Actions. + +In the `.github/workflows` directory, create a new file names `test.yml` and copy the following contents: ```yaml -name: "Auto Tag" -on: - issues: - types: [opened, edited] +name: Build and test -permissions: - issues: write - contents: read +on: + push: + branches: ["development"] # Triggered when a commit is pushed to the development branch jobs: - triage: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - uses: damccorm/tag-ur-it@master - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - configuration-path: "issue-rules.yml" + build: + runs-on: ubuntu-latest # Run this code on a Linux Virtual Machine (VM) + + steps: # Steps that are executed for this Action + + # Checks out the code into the VM + - name: Checkout repository + uses: actions/checkout@v4 + + # Installs Python + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + # Installs the dependencies + - name: Install Dependencies + run: pip install -r requirements.txt + + # Discovers and runs the tests + - name: Run tests + run: pytest -q ``` -The GitHub Action specified above is very simple: it executed when an issue is opened or re-opened. It then checks out your repository code and runs the [`tag-ur-it`](https://github.com/damccorm/tag-ur-it) job. It can do more than just label issues. The behavior is configured in `config/issue-rules.yml`. Note that the file specifies that if the term `enpm611` appears in the issue text, the issue is assigned to the GitHub user `enpm611`: +Save the file and push the changes to the repository: -```yaml -rules: -... -- contains: enpm611 - assign: ['enpm611'] +```bash +git add --all +git commit -m "Added test action" +git push ``` -After you created that file, push your changes to the repository. Then, work on the following tasks: +Now, go to your GitHub repository page in your browser and click on the Actions tab. You should see the test action running. Click on the action to reveal details about each step of the action (as defined in the `steps` section of the workflow file). + +Is your Action failing? That's ok. That's what we expect. Let's fix it. Check the details of the failed test output. It should tell you what test was failing and where in the code that failure occurred. Go to the respective test in `tests/test_delivery.py` and update the test case to match the value that is returned by the function. -* **Task A**: create a new rule that assigns the label `question` if the issue contains the term `maybe`. +Once you update the test case, push your changes to the repository with the same commands as above. Again, navigate to the Actions tab in GitHub to see the output of the test run. -* **Task B**: add a rule that assigns the issue to your user if the issue contains the term `urgent`. +This exercise illustrates one of the most fundamental parts of a CI/DC pipeline: automated quality assurance by executing test cases. That provides developers early warning signs that something is broken and should be fixed immediately. +## Exercise 2: **Release** -## Exercise 3 - Continuous Integration +Imagine you have completed making changes to the *Galactic Pizza Delivery Time Estimator* and are ready to push a new release out to your users. There are a variety of steps that could be entailed in a release process. For this exercise, we will have our GitHub Action automatically update the version of our application and create release notes. -Continuous Integration (CI) relies heavily on automating processes so that we an focus on development and let tools take care of giving us feedback when something goes wrong. Hence, a core part of CI is to automated the running of tests whenever someone pushes code to the repository. The goal is to get immediate feedback telling us that whether what we commited is of acceptable quality. +ℹ️ [**Semantic versioning**](https://semver.org is a standardized way of assigning version numbers so that users can understand the scope and impact of changes in a release. A semantic version has the form `MAJOR.MINOR.PATCH` (e.g., `1.8.16`). The `MAJOR` number increases when changes break backward compatibility, `MINOR` increases when new features are added without breaking existing behavior, and `PATCH` increases for backwards-compatible bug fixes. -Now, you will create a new GitHub Action. First, in the folder `.github/workflows`, create a file named `autotest.yml`. Then, copy and paste the following YAML specification into the file and save it: +Keep up with version can be tedious. So we will let GitHub Action handle the versioning for us. Create a new file in `.github/workflows` and copy the content below: ```yaml -name: "Continuous Integration" +name: Update version and add release notes to README -on: push +on: + pull_request: + types: [opened] # Only executed when a new PR is created +permissions: # Required for the Action to change our version and README files + contents: write + pull-requests: write + jobs: - test: - runs-on: ubuntu-24.04 + + update_readme: + + runs-on: ubuntu-latest + steps: - - name: Checkout Code + + - name: Checkout repository uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} - - name: Setup Python + - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.12.4' - - - name: Install Dependencies - run: - pip install -r requirements.txt + python-version: "3.x" - - name: Run Tests - run: pytest + # Calls a Python script to increase the version number in `__version__.py` + - name: Increase version number + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + python deployment_scripts/update_version_number.py + + # Calls a Python script to update the release notes in `README.md` + - name: Update release notes + env: + PR_TITLE: ${{ github.event.pull_request.title }} + PR_BODY: ${{ github.event.pull_request.body }} + run: | + python deployment_scripts/update_release_notes.py + + # Commits the changes the script made to `__version__.py` and `README.md` + - name: Commit changes + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add __version__.py + git add README.md + git commit -m "Add release notes for PR #${{ github.event.pull_request.number }}" || echo "No changes to commit" + git push ``` -This action is executed whenever someone does a `push`. It will perform several `steps` as part of the `test` job. First, it checks out the source code from your repository. We are using a pre-defined [checkout action](https://github.com/actions/checkout) for this. You can see that we can reuse actions also! Then, we set up a Python environment so that we can run our code using the [setup-python action](https://github.com/actions/setup-python). As you know, we can't execute our Python code if we don't first install our dependencies. So next, we are doing exactly that by running the `pip install` command. Finally, we can run our tests by running `pytest`. This will run all the test defined in this repository and let us know if the tests pass. +The Action itself doesn't do a lot. It just calls Python scripts that reside in our repo (`deployment_scripts`): + +- `update_version_number.py`: reads the version number from `__version__.py` and increments it. +- `update_release_notes.py`: reads the PR title and body and adds them to the `README.md` file. -After you created the file and copied the action above, push the change to the repository. Next, work on the following tasks: +These Python scripts use the information you enter in your PR title and description. To increase the version number, it checks if the PR title contains `major` or `minor`. If so, it will increase the respective part of the semantic version number. The description of the PR will be used as the release notes that are inserted into the README file. -* **Task C**: Add a test case to either test file and push your changes to your repository. Check the run of the action to see what status is finishes with. +### Tasks A -* **Task D**: You will notice that the action shows a red x after it has completed its run. Investigate why that action failed. Resolve the issue and push to the repository to trigger the action again. +Once you created the `release.yml` Action file, push it to the repository as described above. Now, go to the `Pull request` tab of your GitHub repository. Create a new PR with the following info: +- Title: `Emergency fix for cheese crust pizza` +- Body: + ``` + - Patching a bug found when calculating cheese crust pizza delivery cost. + - Slight UI improvements. + ``` +Create the PR and go to the `Actions` tab. You should see the release Action running or already be completed. After the Action is completed, check the `Files changed` section in the PR for the changes made to `__version__.py` and `README.md`. +❓ Can you see what part of the version number was updated (e.g., major, minor, patch)? Do you know why? -Task 1 +We don't really want to merge this PR. Got ahead and click on `Close pull request` at the very bottom of the `Conversation` tab of the PR. -Automated testing on commit +### Tasks B -a) Create a new branch called `test` and push it to the repository. Then create a PR for that branch. -b) Observe the test results. If there is a bug, update the test case to match the value that is returned by the function. -c) Push the updated code. Observe the test results. +Now, let's see if we can make our Action update the `Minor` part of the semantic version number. Create a new PR with the following details: +- Title: `Minor update for delivery to Mars` +- Body: + + ```bash + - Can now calculate delivery to Mars! + - Minor bug fixes + ``` +Create the PR and check again on the Action execution and then the changes it made. Did it work to increase the `minor` part of the version number? -Task 2 +This exercise illustrated how we can use GitHub Actions to automate the release process, letting developers focus on being productive and leaving tedious task up to the CI/CD pipeline. -Add release notes to README +## Exercise 3: Deploy -a) Create a new branch called `release` and push it to the repository. -b) Then create a PR for that branch and add a bulleted list of changes. -b) Check that the release notes are added to the `README.md` file. +To make our application available to users, we need to deploy it to some server. For this exercise, we will use GitHub Pages to host our application. GitHub pages. GitHub Pages is a free hosting service provided by GitHub that allows you to publish static websites directly from a GitHub repository. +Create a file in `.github/wokflows` and name it `deploy.yml`. Then copy the contents below: -Task 3 +```yml +name: Deploy static content to Pages -Deploy on merge +on: + push: + branches: [ main ] # Runs when PR is merged to main branch or code is pushed directly to main + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: -a) Create a new branch called `deploy1` and push it to the repository. Then create a PR for that branch. -b) Merge the PR into `main`. -c) Navigate to the deployed app -d) Change the app title and create a new PR. Merge the PR into `main`. Navigate to the deployed app again.Observe the changes. + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v4 -# Release Notes + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: "./spacedelivery/web" + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 +``` -## Release Notes — v1.4.0 — Minor release with changes to the delivery logic (2025-12-06) +# Release notes -- Added more pizza varieties -- Now also delivering to Mars! -- Cleanup and bug fixes +This section should be populated by the *release* Action. diff --git a/deployment/update_release_notes.py b/deployment_scripts/update_release_notes.py similarity index 100% rename from deployment/update_release_notes.py rename to deployment_scripts/update_release_notes.py diff --git a/deployment/update_version_number.py b/deployment_scripts/update_version_number.py similarity index 100% rename from deployment/update_version_number.py rename to deployment_scripts/update_version_number.py diff --git a/docs/github_actions_exercises.svg b/docs/github_actions_exercises.svg new file mode 100644 index 0000000..2ba03b7 --- /dev/null +++ b/docs/github_actions_exercises.svg @@ -0,0 +1,3 @@ + + +
push
Automatically run unit tests
Coding
Test
Release
create PR
Deploy
merge
CI/CD
Update release version and update README with release notes
Deploy web version to GitHub Pages
GitHub Events
GitHub Actions
test.yml
release.yml
deploy.yml
\ No newline at end of file diff --git a/tests/test_delivery.py b/tests/test_delivery.py index 94ec226..76d00e1 100644 --- a/tests/test_delivery.py +++ b/tests/test_delivery.py @@ -22,7 +22,7 @@ def fixed_weather(): def test_basic_delivery_normal_mode(): """Earth is 0.5 lm away; NORMAL speed 10 lm/hr → 0.05 hr.""" - assert estimate_delivery_time("Earth", DeliveryMode.NORMAL, 1.0, no_weather) == 0.05 + assert estimate_delivery_time("Earth", DeliveryMode.NORMAL, 1.0, no_weather) == 0.06 # Fix this! It should be 0.05 def test_turbo_delivery(): diff --git a/workflows-archive/autotag.yaml b/workflows-archive/autotag.yaml deleted file mode 100644 index 3d7fd71..0000000 --- a/workflows-archive/autotag.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: "Auto Tag" -on: - issues: - types: [opened, edited] - -permissions: - issues: write - contents: read - -jobs: - triage: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - uses: damccorm/tag-ur-it@master - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - configuration-path: "config/issue-rules.yml" \ No newline at end of file diff --git a/workflows-archive/autotest.yml b/workflows-archive/autotest.yml deleted file mode 100644 index 03b2661..0000000 --- a/workflows-archive/autotest.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: "Continuous Integration" - -on: push - -jobs: - test: - runs-on: ubuntu-24.04 - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.12.4' - - - name: Install Dependencies - run: - pip install -r requirements.txt - - - name: Run Tests - run: pytest \ No newline at end of file diff --git a/workflows-archive/build_docker.yml b/workflows-archive/build_docker.yml deleted file mode 100644 index a470636..0000000 --- a/workflows-archive/build_docker.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Build and save Docker image artifact - -on: [push] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Build the Docker image - run: docker build . --tag spacedelivery:latest - - - name: Save image to a tar file - run: docker save spacedelivery:latest -o ${{ runner.temp }}/spacedelivery.tar - - - name: Upload Docker image artifact - uses: actions/upload-artifact@v4 - with: - name: docker-image-artifact - path: ${{ runner.temp }}/spacedelivery.tar \ No newline at end of file diff --git a/workflows-archive/config/issue-rules.yml b/workflows-archive/config/issue-rules.yml deleted file mode 100644 index 19000ce..0000000 --- a/workflows-archive/config/issue-rules.yml +++ /dev/null @@ -1,15 +0,0 @@ -# list of primary rules -rules: -- contains: question - addLabels: ['question'] -- contains: bug - addLabels: ['bug'] -- contains: feature - addLabels: ['enhancement'] -- contains: enpm611 - assign: ['enpm611'] - -# List that always runs after rules and nomatches. Look for missing sets of tags here. -tags: -- noneIn: ['bug', 'enhancement', 'question'] # If no bug, enhancement, or question labels are added, label with 'triage' - addLabels: ['invalid'] diff --git a/workflows-archive/triage_issues.yml b/workflows-archive/triage_issues.yml deleted file mode 100644 index f47dcc7..0000000 --- a/workflows-archive/triage_issues.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: "Label Issues for Triage" -on: - issues: - types: - - reopened - - opened -jobs: - label_issues: - runs-on: ubuntu-latest - permissions: - issues: write - env: - LABELS_JSON: | - [ - {"name": "triage", "color": "ededed", "description": "Triage needed"}, - ] - steps: - - uses: actions/github-script@v7 - with: - script: | - const labels = JSON.parse(process.env.LABELS_JSON); - for (const label of labels) { - try { - await github.rest.issues.createLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - name: label.name, - description: label.description || '', - color: label.color - }); - } catch (error) { - // Check if the error is because the label already exists - if (error.status === 422) { - console.log(`Label '${label.name}' already exists. Skipping.`); - } else { - // Log other errors - console.error(`Error creating label '${label.name}': ${error}`); - } - } - } - - run: gh issue edit "$NUMBER" --add-label "$LABELS" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.issue.number }} - LABELS: question From 39d40b8f7f921613fca4a283e709ef3bd3a5a0fd Mon Sep 17 00:00:00 2001 From: Chris Ackermann Date: Sun, 7 Dec 2025 18:02:41 -0500 Subject: [PATCH 25/25] Finished up writeup --- README.md | 14 ++++++++++++-- docs/github_actions_exercises.svg | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3251436..76e609e 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ This exercise illustrates one of the most fundamental parts of a CI/DC pipeline: Imagine you have completed making changes to the *Galactic Pizza Delivery Time Estimator* and are ready to push a new release out to your users. There are a variety of steps that could be entailed in a release process. For this exercise, we will have our GitHub Action automatically update the version of our application and create release notes. -ℹ️ [**Semantic versioning**](https://semver.org is a standardized way of assigning version numbers so that users can understand the scope and impact of changes in a release. A semantic version has the form `MAJOR.MINOR.PATCH` (e.g., `1.8.16`). The `MAJOR` number increases when changes break backward compatibility, `MINOR` increases when new features are added without breaking existing behavior, and `PATCH` increases for backwards-compatible bug fixes. +ℹ️ [**Semantic versioning**](https://semver.org) is a standardized way of assigning version numbers so that users can understand the scope and impact of changes in a release. A semantic version has the form `MAJOR.MINOR.PATCH` (e.g., `1.8.16`). The `MAJOR` number increases when changes break backward compatibility, `MINOR` increases when new features are added without breaking existing behavior, and `PATCH` increases for backwards-compatible bug fixes. Keep up with version can be tedious. So we will let GitHub Action handle the versioning for us. Create a new file in `.github/workflows` and copy the content below: @@ -248,6 +248,8 @@ Now, let's see if we can make our Action update the `Minor` part of the semantic Create the PR and check again on the Action execution and then the changes it made. Did it work to increase the `minor` part of the version number? +Let's keep this PR open since we'll use it in the next exercise. + This exercise illustrated how we can use GitHub Actions to automate the release process, letting developers focus on being productive and leaving tedious task up to the CI/CD pipeline. ## Exercise 3: Deploy @@ -296,13 +298,21 @@ jobs: - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: - path: "./spacedelivery/web" + path: "./spacedelivery/web" # directory containing the web app files - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ``` +Now, push the changes to the `development` branch. Go to the PR that should still be open. If not, you can just create a new PR merging the `development` branch into the `main` branch. Next, click on `Merge pull request`. That event will trigger the deployment script above and deploy the app to gitHub pages. Go to the page: + +https://enpm611.github.io/github-actions + +but replace the user name to matched your forked repository. You should see the app running. + +This exercise illustated the last step of the CI/CD pipeline, which is delivering the application to its final destination from where users will be able to access and interact with it. You have now implemented your own CI/CD pipeline. You can find many more actions in the (GitHub Marketplace)[https://github.com/marketplace?type=actions]. + # Release notes diff --git a/docs/github_actions_exercises.svg b/docs/github_actions_exercises.svg index 2ba03b7..c3b1d5e 100644 --- a/docs/github_actions_exercises.svg +++ b/docs/github_actions_exercises.svg @@ -1,3 +1,3 @@ -
push
Automatically run unit tests
Coding
Test
Release
create PR
Deploy
merge
CI/CD
Update release version and update README with release notes
Deploy web version to GitHub Pages
GitHub Events
GitHub Actions
test.yml
release.yml
deploy.yml
\ No newline at end of file +
push
Automatically run unit tests
Coding
QA
Release
create PR
Host
merge
CI/CD
Update release version and update README with release notes
Deploy web version to GitHub Pages
GitHub Events
GitHub Actions
test.yml
release.yml
deploy.yml
\ No newline at end of file