Skip to content

Commit d2e8790

Browse files
Chris AckermannChris Ackermann
authored andcommitted
Added new actions
1 parent 828a15d commit d2e8790

File tree

14 files changed

+443
-2
lines changed

14 files changed

+443
-2
lines changed

.github/workflows/deploy.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
7+
permissions:
8+
contents: read
9+
pages: write
10+
id-token: write
11+
12+
jobs:
13+
deploy:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout source
18+
uses: actions/checkout@v4
19+
20+
- name: Upload static site
21+
uses: actions/upload-pages-artifact@v2
22+
with:
23+
path: .
24+
25+
- name: Deploy to GitHub Pages
26+
uses: actions/deploy-pages@v4

.github/workflows/release.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Add Release Notes to README
2+
3+
on:
4+
pull_request:
5+
types: [opened]
6+
7+
jobs:
8+
update_readme:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout repository
13+
uses: actions/checkout@v4
14+
with:
15+
fetch-depth: 0
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: "3.x"
21+
22+
- name: Increase version number
23+
env:
24+
PR_TITLE: ${{ github.event.pull_request.title }}
25+
run: |
26+
python deployment/update_version_number.py
27+
28+
- name: Update release notes
29+
env:
30+
PR_TITLE: ${{ github.event.pull_request.title }}
31+
PR_BODY: ${{ github.event.pull_request.body }}
32+
run: |
33+
python deployment/update_release_notes.py
34+
35+
- name: Commit changes
36+
run: |
37+
git config user.name "github-actions[bot]"
38+
git config user.email "github-actions[bot]@users.noreply.github.com"
39+
git add README.md
40+
git commit -m "Add release notes for PR #${{ github.event.pull_request.number }}" || echo "No changes to commit"
41+
git push

.vscode/settings.json

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,35 @@
1212
"coverage-gutters.showLineCoverage": true,
1313
"python.testing.pytestArgs": [
1414
"tests"
15-
]
15+
],
16+
"files.exclude": {
17+
"**/.git": true,
18+
"**/.svn": true,
19+
"**/.hg": true,
20+
"**/CVS": true,
21+
"**/.DS_Store": true,
22+
"**/Thumbs.db": true,
23+
"**/*.pyc": {
24+
"when": "$(basename).py"
25+
},
26+
"**/__pycache__": true,
27+
"**/app.egg-info": true,
28+
"**/env": true,
29+
"**/.env.dist": true,
30+
"**/*.log": true,
31+
"**/.0": true
32+
},
33+
"workbench.colorCustomizations": {
34+
"tab.activeBorder": "#ff0000",
35+
"tab.unfocusedActiveBorder": "#000000",
36+
"tab.activeBackground": "#045980"
37+
},
38+
"workbench.editor.wrapTabs": true,
39+
"debug.toolBarLocation": "docked",
40+
"python.formatting.provider": "autopep8",
41+
"editor.formatOnSave": true,
42+
"[python]": {
43+
"editor.defaultFormatter": "ms-python.autopep8"
44+
},
45+
"python.REPL.enableREPLSmartSend": false
1646
}

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,35 @@ After you created the file and copied the action above, push the change to the r
125125
* **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.
126126

127127
* **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.
128+
129+
130+
131+
132+
Task 1
133+
134+
Automated testing on commit
135+
136+
a) Create a new branch called `test` and push it to the repository. Then create a PR for that branch.
137+
b) Observe the test results
138+
c) Introduce a bug and push. Observe the test results.
139+
140+
141+
142+
Task 2
143+
144+
Add release notes to README
145+
146+
a) Create a new branch called `release` and push it to the repository.
147+
b) Then create a PR for that branch and add a bulleted list of changes.
148+
b) Check that the release notes are added to the `README.md` file.
149+
150+
151+
Task 3
152+
153+
Deploy on merge
154+
155+
a) Create a new branch called `deploy1` and push it to the repository. Then create a PR for that branch.
156+
b) Merge the PR into `main`.
157+
c) Navigate to the deployed app
158+
d) Change the app title and create a new PR. Merge the PR into `main`. Navigate to the deployed app again.Observe the changes.
159+

__version__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# coding: utf-8
2+
3+
__title__ = 'enpm611-ghactions'
4+
__version__ = '1.3.8'
5+
__author__ = 'ENPM611'
6+
__url__ = 'https://github.com/enpm611/github-actions'
7+
__description__ = ("Exercise to use GitHub Actions for CI/CD task.")

deployment/update_release_notes.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
3+
import os
4+
import re
5+
from datetime import datetime
6+
from pathlib import Path
7+
8+
9+
def get_current_version() -> str:
10+
# Read version file
11+
VERSION_FILE = Path("__version__.py")
12+
version_text = VERSION_FILE.read_text()
13+
# Extract current version string
14+
match = re.search(r"__version__\s*=\s*['\"](\d+\.\d+\.\d+)['\"]", version_text)
15+
if not match:
16+
raise ValueError("Could not find __version__ in file.")
17+
return match.group(1)
18+
19+
20+
def update_release_notes() -> None:
21+
22+
# Read the environment variables that were passed in from
23+
# the GitHub Action workflow.
24+
pr_title: str = os.environ.get("PR_TITLE", "").strip()
25+
pr_body: str = os.environ.get("PR_BODY", "").strip()
26+
# Check for missing environment variables
27+
if not pr_title:
28+
raise ValueError("PR_TITLE environment variable is missing.")
29+
30+
# Get current version from version file
31+
version: str = get_current_version()
32+
33+
# Create release note entry
34+
date_str: str = datetime.utcnow().strftime("%Y-%m-%d")
35+
entry_lines: list[str] = [
36+
"",
37+
f"## Release Notes — v{version}{pr_title} ({date_str})",
38+
"",
39+
pr_body,
40+
"",
41+
]
42+
43+
# Append to README
44+
with open("README.md", "a", encoding="utf-8") as f:
45+
f.write("\n".join(entry_lines))
46+
47+
print("README updated with release notes.")
48+
49+
if __name__ == "__main__":
50+
update_release_notes()
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
"""
3+
Bumps the version number in the `__version__.py` file when a Pull
4+
Request is created.
5+
"""
6+
7+
8+
import re
9+
import os
10+
from pathlib import Path
11+
from typing import Any, Literal
12+
13+
14+
def get_current_version(version_text:str) -> str:
15+
# Extract current version string
16+
match = re.search(r"__version__\s*=\s*['\"](\d+\.\d+\.\d+)['\"]", version_text)
17+
if not match:
18+
raise ValueError("Could not find __version__ in file.")
19+
return match.group(1)
20+
21+
def get_release_type() -> Literal["patch", "minor", "major"]:
22+
""" Determine the type of release based on the PR title """
23+
24+
# Read release title from env
25+
pr_title: str = os.environ.get("PR_TITLE", "").strip()
26+
# Determine release type based on terms in title
27+
if "minor" in pr_title.lower():
28+
return "minor"
29+
elif "major" in pr_title.lower():
30+
return "major"
31+
else:
32+
return "patch"
33+
34+
def bump_version():
35+
36+
# Read version file
37+
VERSION_FILE = Path("__version__.py")
38+
version_text = VERSION_FILE.read_text()
39+
40+
old_version: str = get_current_version(version_text)
41+
major, minor, patch = map(int, old_version.split("."))
42+
43+
# Increment based on the requested level
44+
level: Literal['patch', 'minor', 'major'] = get_release_type()
45+
if level == "patch":
46+
patch += 1
47+
elif level == "minor":
48+
minor += 1
49+
patch = 0
50+
elif level == "major":
51+
major += 1
52+
minor = 0
53+
patch = 0
54+
else:
55+
raise ValueError("level must be 'major', 'minor', or 'patch'")
56+
57+
new_version = f"{major}.{minor}.{patch}"
58+
59+
# Replace the version string in the file
60+
new_text = version_text.replace(old_version,new_version)
61+
62+
VERSION_FILE.write_text(new_text)
63+
print(f"Version bumped to {new_version}")
64+
return new_version
65+
66+
67+
68+
69+
if __name__ == "__main__":
70+
bump_version()

spacedelivery/web/estimator.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
const PLANET_DISTANCE = {
2+
Mercury: 3,
3+
Venus: 2,
4+
Earth: 0.5,
5+
Mars: 4,
6+
Jupiter: 25,
7+
Saturn: 50,
8+
Neptune: 200,
9+
};
10+
11+
const MODE_SPEED = {
12+
1: 10, // NORMAL
13+
2: 25, // TURBO
14+
3: 100, // HYPERJUMP
15+
};
16+
17+
// Populate planet dropdown
18+
window.onload = () => {
19+
const select = document.getElementById("planet");
20+
Object.keys(PLANET_DISTANCE).forEach((planet) => {
21+
const option = document.createElement("option");
22+
option.value = planet;
23+
option.textContent = planet;
24+
select.appendChild(option);
25+
});
26+
};
27+
28+
function estimateDeliveryTime(planet, mode, surgeLoad, weatherDelay) {
29+
if (!(planet in PLANET_DISTANCE)) {
30+
throw new Error("Unknown destination");
31+
}
32+
if (!(mode in MODE_SPEED)) {
33+
throw new Error("Invalid delivery mode");
34+
}
35+
if (surgeLoad < 1) {
36+
throw new Error("surgeLoad must be >= 1");
37+
}
38+
if (weatherDelay < 0) {
39+
throw new Error("weatherDelay must be >= 0");
40+
}
41+
42+
const distance = PLANET_DISTANCE[planet];
43+
const speed = MODE_SPEED[mode];
44+
45+
let travelTime = distance / speed;
46+
47+
// Fatigue penalty for extreme distances
48+
if (distance > 100) {
49+
travelTime *= 1.2;
50+
}
51+
52+
const total = travelTime * surgeLoad + weatherDelay;
53+
return Math.round(total * 100) / 100;
54+
}
55+
56+
// Wire UI to estimator
57+
document.getElementById("estimate").onclick = () => {
58+
const planet = document.getElementById("planet").value;
59+
const mode = Number(document.getElementById("mode").value);
60+
const surge = Number(document.getElementById("surge").value);
61+
const weather = Number(document.getElementById("weather").value);
62+
63+
try {
64+
const time = estimateDeliveryTime(planet, mode, surge, weather);
65+
document.getElementById("result").textContent =
66+
`Estimated delivery time: ${time} hours`;
67+
} catch (err) {
68+
document.getElementById("result").textContent = "Error: " + err.message;
69+
}
70+
};

spacedelivery/web/index.html

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Galactic Pizza Delivery Estimator</title>
7+
<link rel="stylesheet" href="style.css" />
8+
</head>
9+
<body>
10+
11+
<div class="container">
12+
<h1>🚀 Galactic Pizza Delivery Estimator</h1>
13+
14+
<div class="form">
15+
<label>Destination Planet:</label>
16+
<select id="planet"></select>
17+
18+
<label>Delivery Mode:</label>
19+
<select id="mode">
20+
<option value="1">Normal</option>
21+
<option value="2">Turbo</option>
22+
<option value="3">Hyperjump</option>
23+
</select>
24+
25+
<label>Surge Load (1.0 = none):</label>
26+
<input type="number" id="surge" value="1.0" min="1" step="0.1" />
27+
28+
<label>Simulated Weather Delay (hours):</label>
29+
<input type="number" id="weather" value="0" step="0.1" />
30+
31+
<button id="estimate">Estimate Delivery Time</button>
32+
</div>
33+
34+
<div class="result" id="result"></div>
35+
</div>
36+
37+
<script src="estimator.js"></script>
38+
</body>
39+
</html>

0 commit comments

Comments
 (0)