Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6ed7a0a
Major refactor for notification system
robbykap Feb 13, 2026
27aa6c6
Fix action paths
robbykap Feb 13, 2026
963d88b
Update mdxcanvas_automation.yaml
robbykap Feb 13, 2026
c61eb59
Fix paths
robbykap Feb 13, 2026
9ad268b
Revert "Fix paths"
robbykap Feb 13, 2026
71fea04
Update mdxcanvas_automation.yaml
robbykap Feb 13, 2026
9c33d8e
Update mdxcanvas_automation.yaml
robbykap Feb 13, 2026
fee6ec8
Update mdxcanvas_automation.yaml
robbykap Mar 4, 2026
3e2fb33
Update mdxcanvas_automation.yaml
robbykap Mar 4, 2026
0009f21
Update mdxcanvas_automation.yaml
robbykap Mar 4, 2026
191a83a
Update formatting_utils.py
robbykap Mar 4, 2026
3e3834b
Update formatting_utils.py
robbykap Mar 4, 2026
7d94cf4
Update formatting_utils.py
robbykap Mar 4, 2026
8be61ad
Redesign Discord notification infrastructure
robbykap Mar 30, 2026
f57e22e
Fix action references to use claude/wonderful-lovelace branch
robbykap Mar 30, 2026
d99d6b9
Handle null avatar URLs gracefully
robbykap Mar 30, 2026
2e5e4ee
Move permissions from workflow level to job level
robbykap Mar 30, 2026
a8d697f
Fix nested reusable workflow: use full repo ref for check_toml.yaml
robbykap Mar 30, 2026
e925267
Remove secrets: inherit from nested check_toml call
robbykap Mar 30, 2026
5c19bd2
Inline check_toml logic into poetry_publish to fix startup_failure
robbykap Mar 30, 2026
865e68a
Test: remove permissions block to debug startup_failure
robbykap Mar 30, 2026
2c43a7a
Fix utils checkout refs and null PyPI version handling
robbykap Mar 30, 2026
8e0a7ca
Add markdowndata dependency to all notification workflow steps
robbykap Mar 30, 2026
3d0cd73
Restore id-token: write permission for OIDC PyPI publishing
robbykap Mar 30, 2026
1d87c4e
Update all branch refs to @main for production
robbykap Mar 30, 2026
6871369
Update README with OIDC migration guide and new workflow inputs
robbykap Mar 31, 2026
7b7ccaf
Update .gitignore
robbykap Apr 1, 2026
38f5f4a
Redesign course notifications as plain text
robbykap Apr 1, 2026
556616a
Fix reusable workflow checkout refs
robbykap Apr 1, 2026
1508b63
Add explicit utils_ref for reusable workflow tests
robbykap Apr 1, 2026
a0b4b37
Install markdowndata for course notifications
robbykap Apr 1, 2026
0ddf516
Polish Discord course notification layout
robbykap Apr 1, 2026
7b00ab6
Merge updated Discord notification fixes
robbykap Apr 1, 2026
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
63 changes: 63 additions & 0 deletions .github/actions/send-course-notification/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Send Course Notification
description: Create fallback output if needed and send course notification to Discord

inputs:
notification-type:
description: "Type of notification: 'canvas' or 'docker'"
required: true
output-type:
description: "Output type for fallback: 'MDXCanvas' or 'Docker'"
required: true
payload-path:
description: "Path to the output JSON file"
required: true
stdout-log:
description: "Path to stdout log file"
required: true
stderr-log:
description: "Path to stderr log file"
required: true
course-id:
description: "Course ID"
required: true
course-name:
description: "Course name"
required: true
course-url:
description: "Course URL"
required: true
discord-role:
description: "Discord CI/CD role ID"
required: true
discord-webhook-url:
description: "Discord webhook URL"
required: true

runs:
using: composite
steps:
- name: Create fallback output if needed
shell: bash
run: |
PYTHONPATH=utils python -m notifications.fallback \
--output-type "${{ inputs.output-type }}" \
--output-path "${{ inputs.payload-path }}" \
--stdout-log "${{ inputs.stdout-log }}" \
--stderr-log "${{ inputs.stderr-log }}" \
--action-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"

- name: Send course notification to Discord
shell: bash
env:
DISCORD_WEBHOOK_URL: ${{ inputs.discord-webhook-url }}
run: |
PYTHONPATH=utils python -m notifications.send_course \
--type "${{ inputs.notification-type }}" \
--payload "${{ inputs.payload-path }}" \
--course-id "${{ inputs.course-id }}" \
--course-name "${{ inputs.course-name }}" \
--course-url "${{ inputs.course-url }}" \
--author "${{ github.actor }}" \
--branch "${{ github.ref_name }}" \
--cicd-id "${{ inputs.discord-role }}" \
--action-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
62 changes: 62 additions & 0 deletions .github/actions/send-pypi-notification/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Send PyPI Notification
description: Get GitHub avatar and send PyPI update notification to Discord

inputs:
pypi-package:
description: "PyPI package name"
required: true
success:
description: "Whether the publish succeeded ('true' or 'false')"
required: true
toml-updated:
description: "Whether pyproject.toml version was bumped ('true' or 'false')"
required: true
version:
description: "Package version"
required: true
discord-role:
description: "Discord CI/CD role ID"
required: true
discord-webhook-url:
description: "Discord webhook URL"
required: true
old-version:
description: "Previous PyPI version (for version transition display)"
required: false
default: ""

runs:
using: composite
steps:
- name: Get user avatar
id: avatar
shell: bash
run: |
AVATAR_URL=$(curl -s "https://api.github.com/users/${{ github.actor }}" | jq -r '.avatar_url // empty')
echo "url=${AVATAR_URL:-}" >> $GITHUB_OUTPUT

- name: Send PyPI notification to Discord
shell: bash
env:
DISCORD_WEBHOOK_URL: ${{ inputs.discord-webhook-url }}
run: |
CMD="PYTHONPATH=utils python -m notifications.send_pypi \
--type '${{ inputs.pypi-package }}' \
--author '${{ github.actor }}' \
--author-icon '${{ steps.avatar.outputs.url }}' \
--action-url 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'"

if [ '${{ inputs.success }}' == 'true' ] && \
[ '${{ inputs.toml-updated }}' == 'true' ]; then
CMD="$CMD --success 1"
fi

CMD="$CMD --version '${{ inputs.version }}' \
--cicd-id '${{ inputs.discord-role }}'"

if [ -n "${{ inputs.old-version }}" ]; then
CMD="$CMD --old-version '${{ inputs.old-version }}'"
fi

echo "$CMD"
eval "$CMD"
16 changes: 12 additions & 4 deletions .github/workflows/check_toml.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ on:
version:
description: "The version from pyproject.toml"
value: ${{ jobs.check.outputs.version }}
pypi_version:
description: "The current version on PyPI"
value: ${{ jobs.check.outputs.pypi_version }}

jobs:
check:
runs-on: ubuntu-latest
outputs:
uped_toml: ${{ steps.extract_update.outputs.uped_toml }}
version: ${{ steps.get_build_version.outputs.version }}
pypi_version: ${{ steps.get_pypi_version.outputs.pypi_version }}
steps:
- name: Checkout repo
uses: actions/checkout@v4
Expand All @@ -36,8 +40,9 @@ jobs:
- name: Get version from PyPI
id: get_pypi_version
run: |
VERSION=$(curl -s https://pypi.org/pypi/${{ inputs.pypi_package }}/json | jq -r .info.version)
echo "pypi_version=$VERSION" >> $GITHUB_ENV
VERSION=$(curl -s https://pypi.org/pypi/${{ inputs.pypi_package }}/json | jq -r '.info.version // empty')
echo "pypi_version=${VERSION:-}" >> $GITHUB_ENV
echo "pypi_version=${VERSION:-}" >> $GITHUB_OUTPUT

- name: Install Poetry and Version Plugin
run: pip install "poetry<2" poetry-version-from-file
Expand All @@ -57,5 +62,8 @@ jobs:
- name: Check for version update
id: extract_update
run: |
python3 utils/.github/scripts/check_version.py "${{ steps.get_build_version.outputs.version }}" "${{ env.pypi_version }}"
echo "uped_toml=true" >> $GITHUB_OUTPUT
if python3 utils/.github/scripts/check_version.py "${{ steps.get_build_version.outputs.version }}" "${{ env.pypi_version }}"; then
echo "uped_toml=true" >> $GITHUB_OUTPUT
else
echo "uped_toml=false" >> $GITHUB_OUTPUT
fi
59 changes: 28 additions & 31 deletions .github/workflows/docker_automation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ on:
course_id:
required: true
type: string
course_name:
required: true
type: string
course_url:
required: true
type: string
utils_ref:
required: false
default: main
type: string
secrets:
discord_role:
required: true
Expand Down Expand Up @@ -35,8 +45,13 @@ jobs:
uses: actions/checkout@v4
with:
repository: BYU-CS-Course-Ops/utils
ref: ${{ inputs.utils_ref }}
path: utils

- name: Install notification dependencies
shell: bash
run: pip install discord-webhook markdowndata

- name: Get changed files
run: |
files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }})
Expand Down Expand Up @@ -72,35 +87,17 @@ jobs:
--root-dir "${{ github.workspace }}" \
> "$STDOUT_LOG" 2> "$STDERR_LOG"

- name: Create fallback output if needed
- name: Send course notification
if: always()
run: |
python utils/course_updates/create_fallback.py \
--output-type Docker \
--output-path "${{ github.workspace }}/.github/logs/docker_output.json" \
--stdout-log "${{ github.workspace }}/.github/logs/docker_stdout.log" \
--stderr-log "${{ github.workspace }}/.github/logs/docker_stderr.log" \
--action-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"

- name: Get user avatar
run: |
AVATAR_URL=$(curl -s https://api.github.com/users/${{ github.actor }} | jq -r '.avatar_url')
echo "AVATAR_URL=$AVATAR_URL" >> $GITHUB_ENV

- name: Install discord_webhook
run: |
pip install discord-webhook

- name: Send Discord Notification
env:
DISCORD_WEBHOOK_URL: ${{ secrets.discord_webhook_url }}
run: |
python utils/course_updates/send_course_notification.py \
--type "docker" \
--payload "${{ github.workspace }}/.github/logs/docker_output.json" \
--course-id "${{ inputs.course_id }}" \
--author "${{ github.actor }}" \
--author-icon "$AVATAR_URL" \
--branch "${{ github.ref }}" \
--cicd-id "${{ secrets.discord_role }}" \
--action-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
uses: ./utils/.github/actions/send-course-notification
with:
notification-type: docker
output-type: Docker
payload-path: ${{ github.workspace }}/.github/logs/docker_output.json
stdout-log: ${{ github.workspace }}/.github/logs/docker_stdout.log
stderr-log: ${{ github.workspace }}/.github/logs/docker_stderr.log
course-id: ${{ inputs.course_id }}
course-name: ${{ inputs.course_name }}
course-url: ${{ inputs.course_url }}
discord-role: ${{ secrets.discord_role }}
discord-webhook-url: ${{ secrets.discord_webhook_url }}
70 changes: 37 additions & 33 deletions .github/workflows/mdxcanvas_automation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ on:
course_id:
required: true
type: string
course_name:
required: true
type: string
course_url:
required: true
type: string
utils_ref:
required: false
default: main
type: string
mdxcanvas_version:
required: true
type: string
Expand Down Expand Up @@ -43,7 +53,7 @@ jobs:
OUTPUT_PATH: ${{ github.workspace }}/.github/logs/mdxcanvas_output.json

steps:
- name: Checkout repos
- name: Checkout repo
uses: actions/checkout@v4
with:
fetch-depth: 0
Expand All @@ -53,12 +63,18 @@ jobs:
uses: actions/checkout@v4
with:
repository: BYU-CS-Course-Ops/utils
ref: ${{ inputs.utils_ref }}
path: utils

- name: Setup
run: |
mkdir -p "$LOGS_DIR"
pip install mdxcanvas==${{ inputs.mdxcanvas_version }} discord-webhook
- name: Install MDXCanvas
run: pip install mdxcanvas==${{ inputs.mdxcanvas_version }}

- name: Install notification dependencies
shell: bash
run: pip install discord-webhook markdowndata

- name: Create logs directory
run: mkdir -p "$LOGS_DIR"

- name: Run MDXCanvas
id: mdxcanvas
Expand All @@ -80,36 +96,24 @@ jobs:
> "$LOGS_DIR/mdxcanvas.stdout.log" \
2> "$LOGS_DIR/mdxcanvas.stderr.log"

- name: Process results and notify
env:
DISCORD_WEBHOOK_URL: ${{ secrets.discord_webhook_url }}
- name: Print debug logs
run: |
echo "=== MDXCanvas STDOUT ==="
cat "$LOGS_DIR/mdxcanvas.stdout.log"

echo "=== MDXCanvas STDERR ==="
cat "$LOGS_DIR/mdxcanvas.stderr.log"

# Create fallback if needed
python utils/course_updates/create_fallback.py \
--output-type MDXCanvas \
--output-path "$OUTPUT_PATH" \
--stdout-log "$LOGS_DIR/mdxcanvas.stdout.log" \
--stderr-log "$LOGS_DIR/mdxcanvas.stderr.log" \
--action-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"

echo "=== Updated Output ==="
cat "$OUTPUT_PATH"

# Get avatar and send notification
AVATAR_URL=$(curl -s "https://api.github.com/users/${{ github.actor }}" | jq -r '.avatar_url')

python utils/course_updates/send_course_notification.py \
--type "canvas" \
--payload "$OUTPUT_PATH" \
--course-id "${{ inputs.course_id }}" \
--author "${{ github.actor }}" \
--author-icon "$AVATAR_URL" \
--branch "${{ github.ref }}" \
--cicd-id "${{ secrets.discord_role }}" \
--action-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"

- name: Send course notification
uses: ./utils/.github/actions/send-course-notification
with:
notification-type: canvas
output-type: MDXCanvas
payload-path: ${{ env.OUTPUT_PATH }}
stdout-log: ${{ env.LOGS_DIR }}/mdxcanvas.stdout.log
stderr-log: ${{ env.LOGS_DIR }}/mdxcanvas.stderr.log
course-id: ${{ inputs.course_id }}
course-name: ${{ inputs.course_name }}
course-url: ${{ inputs.course_url }}
discord-role: ${{ secrets.discord_role }}
discord-webhook-url: ${{ secrets.discord_webhook_url }}
Loading