Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 83 additions & 3 deletions .github/scripts/build_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,84 @@
PDF_LIST_MARKER = "<!-- PDF_LIST -->"
GENERATED_MARKER = "<!-- GENERATED -->"

# The documents are listed in waterfall order, which is not the order in which
# the course creates them: the V&V plan is written before the design, but is
# read after it. Listing them this way reinforces the rational design process
# the course asks students to fake, and makes the documentation easier to
# follow for a reader from outside the course.
#
# Taken from the Final Documentation (Revision 1) list in the course outline.
# A directory not named here is listed after these, alphabetically, so adding
# a document folder cannot make it disappear from the page.
SECTION_ORDER = [
("ProblemStatementAndGoals", "Problem Statement and Goals"),
("DevelopmentPlan", "Development Plan"),
("SRS", "Requirements (SRS)"),
("SRS-Volere", "Requirements, Volere template"),
("SRS-Meyer", "Requirements, Meyer template"),
("HazardAnalysis", "Hazard Analysis"),
("Design", "Design"),
("VnVPlan", "Verification and Validation Plan"),
("VnVReport", "Verification and Validation Report"),
("UserGuide", "User Guide"),
("CDs", "Custom Documents"),
("ReflectAndTrace", "Reflection and Traceability"),
("projMngmnt", "Project Management"),
("Checklists", "Checklists"),
]

# Within a section, documents that should not be alphabetical. The checklists
# mirror the deliverables, so they follow the same order as the sections above;
# the design documents go architecture first, then detailed design.
FILE_ORDER = {
"Checklists": [
"GettingStarted-Checklist.pdf",
"ProbState-Checklist.pdf",
"DevPlan-Checklist.pdf",
"SRS-Checklist.pdf",
"SRS-SciComp-Checklist.pdf",
"HA-Checklist.pdf",
"MG-Checklist.pdf",
"MIS-Checklist.pdf",
"VnV-Checklist.pdf",
"POC-Checklist.pdf",
"Code-Checklist.pdf",
"Writing-Checklist.pdf",
"FinalDoc-Checklist.pdf",
],
"Design": ["MG.pdf", "MIS.pdf"],
# The requirements document first, then the questions about it.
"SRS": ["SRS.pdf", "SRS-FAQ.pdf"],
# Chronological: proof of concept, then revision 0, then final.
"projMngmnt": [
"POC_Productivity_Rep.pdf",
"Rev0_Productivity_Rep.pdf",
"Final_Productivity_Rep.pdf",
],
}


def section_rank(directory):
"""Position of a section, with unlisted ones sorted after the known ones."""
for index, (name, _title) in enumerate(SECTION_ORDER):
if name == directory:
return (0, index, "")
return (1, 0, directory.lower())


def section_title(directory):
for name, title in SECTION_ORDER:
if name == directory:
return title
return directory


def file_rank(directory, filename):
order = FILE_ORDER.get(directory)
if order and filename in order:
return (0, order.index(filename), "")
return (1, 0, filename.lower())


def git_last_updated(repo_relative_path):
"""Commit time of a path, or None when git knows nothing about it."""
Expand Down Expand Up @@ -86,10 +164,12 @@ def collect(public_dir, tracked_dir):

def render(sections):
lines = []
for section in sorted(sections):
lines.append("<h2>%s</h2>" % escape(section))
for section in sorted(sections, key=section_rank):
lines.append("<h2>%s</h2>" % escape(section_title(section)))
lines.append("<ul>")
for href, name, moment in sections[section]:
entries = sorted(sections[section],
key=lambda e: file_rank(section, e[1]))
for href, name, moment in entries:
lines.append(
' <li><a href="%s">%s</a>%s</li>'
% (escape(href), escape(name),
Expand Down
5 changes: 4 additions & 1 deletion .github/scripts/select_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
# Instructor-owned prose and things this pipeline never builds from. Changes
# to these must not trigger the full-rebuild fallback.
IGNORED_BASENAMES = {"README.md", "README.txt", ".gitignore"}
IGNORED_PREFIXES = ("pdfs/", "docs/SRS-Meyer/", ".github/")
# site/ is the index page template. It changes what the published page
# looks like, never the content of a PDF, so it must not trigger a
# rebuild even though it does need to trigger the workflow.
IGNORED_PREFIXES = ("pdfs/", "docs/SRS-Meyer/", ".github/", "site/")

# Changing how documents are built can change every document, even though no
# document source changed: the package list decides which LaTeX packages are
Expand Down
77 changes: 77 additions & 0 deletions .github/scripts/update_pages_link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env python3
"""Point the README's GitHub Pages link at this repository's own page.

The template ships with a link to the template's own page and a comment
asking teams to update it, which is easy to miss. Since the build already
commits to the repository, it can correct the link itself: every team's
README then links to their documentation rather than to the template's.

Any Markdown link in the README whose target is a github.io address is
treated as the project's Pages link. Nothing is reported as an error if no
such link exists, because a team is free to reword or remove it.

Usage: update_pages_link.py <owner/repo> [README.md]
"""

import os
import re
import sys

MARKDOWN_LINK = re.compile(r"(\]\()\s*(https?://[^)\s]*github\.io[^)\s]*)\s*(\))")


def pages_url(slug):
"""The Pages URL for owner/repo, as GitHub serves it."""
if "/" not in slug:
raise ValueError("expected owner/repo, got %r" % slug)
owner, repo = slug.split("/", 1)
# GitHub serves Pages from a lowercased owner name.
owner_host = owner.lower() + ".github.io"
if repo.lower() == owner_host:
# The owner's user/organisation site is served from the host root.
return "https://%s/" % owner_host
return "https://%s/%s/" % (owner_host, repo)


def main():
if len(sys.argv) < 2:
sys.exit("usage: update_pages_link.py <owner/repo> [README.md]")

slug = sys.argv[1]
readme = sys.argv[2] if len(sys.argv) > 2 else "README.md"
url = pages_url(slug)

if not os.path.exists(readme):
print("update_pages_link: no %s, nothing to do" % readme)
return

with open(readme) as handle:
original = handle.read()

replaced = []

def swap(match):
was = match.group(2)
if was == url:
return match.group(0)
replaced.append(was)
return match.group(1) + url + match.group(3)

updated = MARKDOWN_LINK.sub(swap, original)

if not replaced:
if url in original:
print("update_pages_link: %s already points at %s" % (readme, url))
else:
print("update_pages_link: no github.io link found in %s" % readme)
return

with open(readme, "w") as handle:
handle.write(updated)

for was in replaced:
print("update_pages_link: %s -> %s" % (was, url))


if __name__ == "__main__":
main()
11 changes: 8 additions & 3 deletions .github/workflows/latex-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ name: Build LaTeX and Deploy PDFs
on:
push:
branches: main
paths: [docs/**, refs/**, Makefile, .github/scripts/**, .github/workflows/latex-pages.yml]
paths: [docs/**, refs/**, site/**, Makefile, .github/scripts/**, .github/workflows/latex-pages.yml]
pull_request:
branches: main
paths: [docs/**, refs/**, Makefile, .github/scripts/**, .github/workflows/latex-pages.yml]
paths: [docs/**, refs/**, site/**, Makefile, .github/scripts/**, .github/workflows/latex-pages.yml]
workflow_dispatch:

permissions:
Expand Down Expand Up @@ -163,12 +163,17 @@ jobs:
rm -rf pdfs
mkdir -p pdfs
rsync -av --delete build-pdf/ pdfs/
- name: Point the README at this repository's Pages site
run: |
# The template ships with a link to the template's own page. Every
# repository made from it would otherwise keep pointing there.
python3 .github/scripts/update_pages_link.py "${{ github.repository }}"
- name: Commit PDFs to repo
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add pdfs .pdf-deps.json
git add pdfs .pdf-deps.json README.md
if git diff --cached --quiet; then
echo "No PDF changes to commit"
else
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ src - Source code
test - Test cases
etc.

The documentation for this project is updated on the project's [GitHub page](https://smiths.github.io/capTemplate/). <!-- update for your project! -->
The documentation for this project is updated on the project's [GitHub page](https://smiths.github.io/capTemplate/). <!-- Kept up to date automatically; the build points this at your own repository's page. -->
4 changes: 4 additions & 0 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
</head>
<body>
<h1>Available PDFs</h1>
<p class="intro">The documents are listed in the order they are meant to be
read, which is not the order in which they are written. Reading them in this
order follows the rational design process the project documentation
presents.</p>
<p class="generated-line">Site generated <!-- GENERATED --></p>
<!-- PDF_LIST -->

Expand Down
6 changes: 6 additions & 0 deletions site/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ li {
font-size: .85rem;
white-space: nowrap;
}

.intro {
color: #333;
max-width: 60ch;
line-height: 1.5;
}