Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comment PRs with updated schedule information #1576

Merged
merged 5 commits into from
Jan 12, 2024
Merged
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
27 changes: 27 additions & 0 deletions .github/workflows/course-schedule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: "Course Schedule Updates"
on:
pull_request:
paths:
- "src/**.md"

jobs:
course-schedule:
runs-on: ubuntu-latest
name: Make Course Schedule Comment
permissions:
pull-requests: write
Comment on lines +11 to +12
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From Permissions for the GITHUB_TOKEN, I think this will be ineffective for PRs that come from forks.

I guess we'll figure it out soon after merging it 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I misunderstood earlier suggestions - does this not run when we click "Run Actions" for an untrusted fork?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does run, but it fails because the token is downgraded. That's how I interpret the error I just saw in #1693:

image

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me think that we should remove this again, sorry!

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Rust cache
uses: ./.github/workflows/setup-rust-cache

- name: Generate Schedule
run: cargo run -p mdbook-course --bin course-schedule > course-schedule.md

- name: Comment PR
uses: thollander/actions-comment-pull-request@v2
with:
filePath: course-schedule.md
comment_tag: course-schedule
10 changes: 10 additions & 0 deletions mdbook-course/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ below:

```yaml
minutes: NNN
target_minutes: NNN
course: COURSE NAME
session: SESSION NAME
```
Expand Down Expand Up @@ -59,6 +60,9 @@ require in the `minutes` field. This information is summed, with breaks
automatically added between segments, to give time estimates for segments,
sessions, and courses.

Each session should list a `target_minutes` that is the target duration of the
session.

## Directives

Within the course material, the following directives can be used:
Expand All @@ -73,3 +77,9 @@ Within the course material, the following directives can be used:
These will be replaced with a markdown outline of the current segment, session,
or course. The last directive can refer to another course by name and is used in
the "Running the Course" section.

# Course-Schedule Comments

The `course-schedule` binary generates Markdown output that is included in a
GitHub pull request comment, based on the information provided in the above
format.
61 changes: 61 additions & 0 deletions mdbook-course/src/bin/course-schedule.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use mdbook::MDBook;
use mdbook_course::course::{Course, Courses};
use mdbook_course::markdown::duration;

fn main() {
pretty_env_logger::init();
let root_dir = ".";
let mdbook = MDBook::load(root_dir).expect("Unable to load the book");
let (courses, _) = Courses::extract_structure(mdbook.book)
.expect("Unable to extract course structure");

println!("## Course Schedule");
println!("With this pull request applied, the course schedule is as follows:");
for course in &courses {
print_summary(course);
}
}

fn timediff(actual: u64, target: u64, slop: u64) -> String {
if actual > target + slop {
format!(
"{} (\u{23f0} *{} too long*)",
duration(actual),
duration(actual - target),
)
} else if actual < target - slop {
format!("{}: ({} short)", duration(actual), duration(target - actual),)
} else {
format!("{}", duration(actual))
}
}

fn print_summary(course: &Course) {
if course.target_minutes() == 0 {
return;
}
println!("### {}", course.name);
println!("_{}_", timediff(course.minutes(), course.target_minutes(), 15));

for session in course {
println!(
"* {} - _{}_",
session.name,
timediff(session.minutes(), session.target_minutes(), 5)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

mod course;
mod frontmatter;
mod markdown;
mod replacements;
mod timing_info;

use crate::course::{Course, Courses};
use crate::markdown::duration;
use clap::{Arg, Command};
use mdbook::book::BookItem;
use mdbook::preprocess::CmdPreprocessor;
use mdbook_course::course::Courses;
use mdbook_course::{replacements, timing_info};
use std::io::{stdin, stdout};
use std::process;

Expand All @@ -46,47 +40,9 @@ fn main() {
}
}

fn timediff(actual: u64, target: u64) -> String {
if actual > target {
format!(
"{}: {} OVER TARGET {}",
duration(actual),
duration(actual - target),
duration(target)
)
} else if actual < target {
format!(
"{}: {} shorter than target {}",
duration(actual),
duration(target - actual),
duration(target)
)
} else {
format!("{}: right on time", duration(actual))
}
}

fn print_summary(fundamentals: &Course) {
eprintln!("Fundamentals: {}", timediff(fundamentals.minutes(), 8 * 3 * 60));

eprintln!("Sessions:");
for session in fundamentals {
eprintln!(" {}: {}", session.name, timediff(session.minutes(), 3 * 60));
for segment in session {
eprintln!(" {}: {}", segment.name, duration(segment.minutes()));
}
}
}

fn preprocess() -> anyhow::Result<()> {
let (ctx, book) = CmdPreprocessor::parse_input(stdin())?;
let (_, book) = CmdPreprocessor::parse_input(stdin())?;
let (courses, mut book) = Courses::extract_structure(book)?;
let verbose = ctx
.config
.get_preprocessor("course")
.and_then(|t| t.get("verbose"))
.and_then(|v| v.as_bool())
.unwrap_or_default();

book.for_each_mut(|chapter| {
if let BookItem::Chapter(chapter) = chapter {
Expand All @@ -108,15 +64,6 @@ fn preprocess() -> anyhow::Result<()> {
}
});

// Print a summary of times for the "Fundamentals" course.
// Translations with a POT-Creation-Date before 2023-11-29 (when
// we merged #1073) will have no frontmatter.
if verbose {
if let Some(fundamentals) = courses.find_course("Fundamentals") {
print_summary(fundamentals);
}
}

serde_json::to_writer(stdout(), &book)?;
Ok(())
}
22 changes: 22 additions & 0 deletions mdbook-course/src/course.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub struct Course {
pub struct Session {
pub name: String,
pub segments: Vec<Segment>,
target_minutes: u64,
}

/// A Segment is a collection of slides with a related theme.
Expand Down Expand Up @@ -143,6 +144,7 @@ impl Courses {
{
let course = courses.course_mut(course_name);
let session = course.session_mut(session_name);
session.target_minutes += frontmatter.target_minutes.unwrap_or(0);
session.add_segment(frontmatter, chapter)?;
}
}
Expand Down Expand Up @@ -232,6 +234,15 @@ impl Course {
self.into_iter().map(|s| s.minutes()).sum()
}

/// Return the target duration of this course, as the sum of all segment
/// target durations.
///
/// This includes breaks between segments, but does not count time between
/// sessions.
pub fn target_minutes(&self) -> u64 {
self.into_iter().map(|s| s.target_minutes()).sum()
}

/// Generate a Markdown schedule for this course, for placement at the given
/// path.
pub fn schedule(&self, at_source_path: impl AsRef<Path>) -> String {
Expand Down Expand Up @@ -333,6 +344,17 @@ impl Session {
* BREAK_DURATION;
instructional_time + breaks
}

/// Return the target duration of this session.
///
/// This includes breaks between segments.
pub fn target_minutes(&self) -> u64 {
if self.target_minutes > 0 {
self.target_minutes
} else {
self.minutes()
}
}
}

impl<'a> IntoIterator for &'a Session {
Expand Down
1 change: 1 addition & 0 deletions mdbook-course/src/frontmatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use serde::Deserialize;
#[derive(Deserialize, Debug, Default)]
pub struct Frontmatter {
pub minutes: Option<u64>,
pub target_minutes: Option<u64>,
pub course: Option<String>,
pub session: Option<String>,
}
Expand Down
19 changes: 19 additions & 0 deletions mdbook-course/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod course;
pub mod frontmatter;
pub mod markdown;
pub mod replacements;
pub mod timing_info;
1 change: 1 addition & 0 deletions src/welcome-day-1-afternoon.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
session: Day 1 Afternoon
target_minutes: 180
---

# Welcome Back
Expand Down
1 change: 1 addition & 0 deletions src/welcome-day-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
minutes: 5
course: Fundamentals
session: Day 1 Morning
target_minutes: 180
---

# Welcome to Day 1
Expand Down
1 change: 1 addition & 0 deletions src/welcome-day-2-afternoon.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
session: Day 2 Afternoon
target_minutes: 180
---

# Welcome Back
Expand Down
1 change: 1 addition & 0 deletions src/welcome-day-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
minutes: 3
course: Fundamentals
session: Day 2 Morning
target_minutes: 180
---

# Welcome to Day 2
Expand Down
1 change: 1 addition & 0 deletions src/welcome-day-3-afternoon.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
session: Day 3 Afternoon
target_minutes: 180
---

# Welcome Back
Expand Down
1 change: 1 addition & 0 deletions src/welcome-day-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
minutes: 3
course: Fundamentals
session: Day 3 Morning
target_minutes: 180
---

# Welcome to Day 3
Expand Down
1 change: 1 addition & 0 deletions src/welcome-day-4-afternoon.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
session: Day 4 Afternoon
target_minutes: 180
---

# Welcome Back
Expand Down
1 change: 1 addition & 0 deletions src/welcome-day-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
minutes: 3
course: Fundamentals
session: Day 4 Morning
target_minutes: 180
---

# Welcome to Day 4
Expand Down