Fake update #261
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Generate Students Notebooks branch | |
| on: | |
| push: | |
| branches: [main] | |
| paths: ['**.ipynb'] | |
| workflow_dispatch: | |
| defaults: | |
| run: | |
| shell: bash | |
| permissions: | |
| contents: write | |
| actions: write | |
| jobs: | |
| process: | |
| runs-on: ubuntu-latest | |
| env: | |
| CONFIG_PATH: .github/conversion.json | |
| SUMMARY_FILE: /tmp/README.md | |
| steps: | |
| - name: Install Python dependencies | |
| run: pip install chardet | |
| - name: Initialize summary file | |
| run: | | |
| rm -f "$SUMMARY_FILE" | |
| mkdir -p "$(dirname "$SUMMARY_FILE")" | |
| - name: Checkout repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate JSON config | |
| run: | | |
| # JSON syntax validation with jq | |
| if ! jq empty "$CONFIG_PATH" >/dev/null 2>&1; then | |
| printf "## ❌ Error in JSON configuration file\n" >> $SUMMARY_FILE | |
| printf "Please fix $CONFIG_PATH error:\n" >> $SUMMARY_FILE | |
| jq empty "$CONFIG_PATH" 2>&1 | sed 's/^jq: //' >> $SUMMARY_FILE | |
| exit 1 | |
| fi | |
| npm install ajv@8 | |
| node - <<'EOF' | |
| const fs = require('fs'); | |
| const Ajv = require('ajv').default; | |
| const summaryFile = process.env.SUMMARY_FILE || '/tmp/README.md'; | |
| const configPath = process.env.CONFIG_PATH || '.github/conversion.json'; | |
| const schema = { | |
| type: 'object', | |
| required: [ | |
| 'solution_marker', 'placeholder', 'generate_zip', | |
| 'notebooks_dir', 'student_postfix', 'tutor_postfix' | |
| ], | |
| properties: { | |
| solution_marker: { | |
| type: 'object', | |
| required: ['code', 'markdown'], | |
| properties: { code: {type: 'string'}, markdown: {type: 'string'} }, | |
| additionalProperties: false | |
| }, | |
| placeholder: { | |
| type: 'object', | |
| required: ['code', 'markdown'], | |
| properties: { code: {type: 'string'}, markdown: {type: 'string'} }, | |
| additionalProperties: false | |
| }, | |
| generate_zip: {type: 'boolean'}, | |
| notebooks_dir: {type: 'array', items: {type: 'string'}, minItems: 1}, | |
| pre_processing: {type: 'string'}, | |
| post_processing: {type: 'string'}, | |
| tutor_postfix: {type: 'string'}, | |
| student_postfix: {type: 'string'}, | |
| rebuild_all: {type: 'boolean'} | |
| } | |
| }; | |
| try { | |
| const config = JSON.parse(fs.readFileSync(configPath)); | |
| const ajv = new Ajv({allErrors: true, strict: true}); | |
| const validate = ajv.compile(schema); | |
| if (!validate(config)) { | |
| const lines = []; | |
| lines.push("## ❌ Error in JSON configuration file"); | |
| lines.push("Config validation failed:"); | |
| lines.push("``` | |
| validate.errors.forEach(err => { | |
| lines.push(`- ${err.instancePath || '/'} ${err.message}`); | |
| }); | |
| lines.push("```"); | |
| fs.appendFileSync(summaryFile, lines.join('\n') + '\n'); | |
| process.exit(1); | |
| } | |
| } catch (error) { | |
| const lines = []; | |
| lines.push("## ❌ Error in JSON configuration file"); | |
| lines.push("Parsing or validation failed:"); | |
| lines.push("``` | |
| lines.push(error.message); | |
| lines.push("```"); | |
| fs.appendFileSync(summaryFile, lines.join('\n') + '\n'); | |
| process.exit(1); | |
| } | |
| EOF | |
| - name: Check monitored directories existence | |
| run: | | |
| EXIT_WITH_ERROR=false | |
| ERROR_HEADER_CREATED=false | |
| while IFS= read -r dir; do | |
| if [ ! -d "$dir" ]; then | |
| if [ "$ERROR_HEADER_CREATED" = false ]; then | |
| printf "## ❌ Error: Missing notebook directories\n" >> $SUMMARY_FILE | |
| printf "The following directories specified in $CONFIG_PATH don't exist:\n" >> $SUMMARY_FILE | |
| ERROR_HEADER_CREATED=true | |
| fi | |
| printf -- "* \`\`\`%s\`\`\`\n" "$dir" >> $SUMMARY_FILE | |
| EXIT_WITH_ERROR=true | |
| fi | |
| done < <(jq -r '.notebooks_dir[]' "$CONFIG_PATH") | |
| if [ "$EXIT_WITH_ERROR" = true ]; then | |
| printf "\nPlease create these directories or update the configuration file.\n" >> $SUMMARY_FILE | |
| exit 1 | |
| fi | |
| - name: Store pre and post-processing command for future execution | |
| run: | | |
| echo "PRE_PROCESSING=$(jq -r '.pre_processing // empty' "$CONFIG_PATH")" >> $GITHUB_ENV | |
| echo "POST_PROCESSING=$(jq -r '.post_processing // empty' "$CONFIG_PATH")" >> $GITHUB_ENV | |
| - name: Check pre/post-processing commands syntax | |
| run: | | |
| # Use bash -n to check shell command syntax without execution | |
| if [ -n "$PRE_PROCESSING" ]; then | |
| ERROR_OUTPUT=$(echo "$PRE_PROCESSING" | bash -n 2>&1) || { | |
| printf "## ❌ Error: Pre-processing command syntax error\n" >> $SUMMARY_FILE | |
| printf "Please fix your pre-processing command syntax:\n" >> $SUMMARY_FILE | |
| printf "%s\n" "$PRE_PROCESSING" >> $SUMMARY_FILE | |
| printf "\n" >> $SUMMARY_FILE | |
| printf "**Error details:**\n" >> $SUMMARY_FILE | |
| printf "%s\n" "$ERROR_OUTPUT" >> $SUMMARY_FILE | |
| exit 1 | |
| } | |
| fi | |
| if [ -n "$POST_PROCESSING" ]; then | |
| ERROR_OUTPUT=$(echo "$POST_PROCESSING" | bash -n 2>&1) || { | |
| printf "## ❌ Error: Post-processing command syntax error\n" >> $SUMMARY_FILE | |
| printf "Please fix your post-processing command syntax:\n" >> $SUMMARY_FILE | |
| printf "%s\n" "$POST_PROCESSING" >> $SUMMARY_FILE | |
| printf "\n" >> $SUMMARY_FILE | |
| printf "**Error details:**\n" >> $SUMMARY_FILE | |
| printf "%s\n" "$ERROR_OUTPUT" >> $SUMMARY_FILE | |
| exit 1 | |
| } | |
| fi | |
| - name: Setup Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: '3.12' | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: ".github/scripts/student_version.py" | |
| - name: Execute pre-processing command | |
| run: | | |
| OUTPUT=$(bash -c "$PRE_PROCESSING" 2>&1) | |
| EXIT_CODE=$? | |
| if [ $EXIT_CODE -eq 0 ]; then | |
| printf "## Pre-processing executed successfully ✅\n" >> $SUMMARY_FILE | |
| if [ -n "$OUTPUT" ]; then | |
| printf "%s\n" "$OUTPUT" >> $SUMMARY_FILE | |
| else | |
| printf "\n" >> $SUMMARY_FILE | |
| fi | |
| else | |
| printf "## Post-processing failed ❌\n" >> $SUMMARY_FILE | |
| printf "Exit code: %d\n" "$EXIT_CODE" >> $SUMMARY_FILE | |
| if [ -n "$OUTPUT" ]; then | |
| printf "\n" >> $SUMMARY_FILE | |
| printf "Command output (including errors):\n" >> $SUMMARY_FILE | |
| printf "%s\n" "$OUTPUT" >> $SUMMARY_FILE | |
| fi | |
| fi | |
| - name: Prepare Students branch | |
| run: | | |
| git fetch origin Students || true | |
| # Create or update Students branch as needed | |
| git checkout Students || git checkout -b Students origin/Students || git checkout -b Students origin/main | |
| git merge origin/main --strategy-option=theirs --allow-unrelated-histories || true | |
| git push origin Students --force | |
| if [ "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" ]; then | |
| echo "STUDENTS_FRESHLY_CREATED=true" >> "$GITHUB_ENV" | |
| else | |
| echo "STUDENTS_FRESHLY_CREATED=false" >> "$GITHUB_ENV" | |
| fi | |
| - name: Detect changed notebooks | |
| id: detect_notebooks | |
| shell: bash | |
| run: | | |
| CONFIG_PATH=".github/conversion.json" | |
| DIRS=$(jq -r '.notebooks_dir[]' "$CONFIG_PATH") | |
| # Build patterns for target notebook files | |
| PATTERNS="" | |
| for dir in $DIRS; do | |
| dir=$(echo "$dir" | sed 's:/*$::') | |
| if [ -n "$PATTERNS" ]; then | |
| PATTERNS+="|" | |
| fi | |
| PATTERNS+="^${dir}/.*\.ipynb$" | |
| done | |
| REBUILD_ALL=$(jq -r '.rebuild_all // false' "$CONFIG_PATH") | |
| BEFORE=${{ github.event.before }} | |
| AFTER=${{ github.event.after }} | |
| echo "===== DEBUG DETECT NOTEBOOKS STEP =====" | |
| echo "STUDENTS_FRESHLY_CREATED=\"$STUDENTS_FRESHLY_CREATED\"" | |
| echo "REBUILD_ALL=\"$REBUILD_ALL\"" | |
| echo "BEFORE=$BEFORE" | |
| echo "AFTER=$AFTER" | |
| echo "PATTERNS=\"$PATTERNS\"" | |
| echo "---------------" | |
| if [[ "${STUDENTS_FRESHLY_CREATED}" == "true" || "$REBUILD_ALL" == "true" ]]; then | |
| NOTEBOOKS_ON_MAIN=$(git ls-tree -r --name-only "$AFTER" | grep -E "$PATTERNS" || true) | |
| echo "$NOTEBOOKS_ON_MAIN" > notebooks_to_convert.txt | |
| echo "== FULL NOTEBOOKS LIST (FORCED)==" | |
| echo "$NOTEBOOKS_ON_MAIN" | |
| else | |
| (git diff --name-only "$BEFORE" "$AFTER" | grep -E "$PATTERNS" || true) > notebooks_to_convert.txt | |
| echo "== NOTEBOOKS FOUND BY DIFF ==" | |
| git diff --name-only "$BEFORE" "$AFTER" | grep -E "$PATTERNS" || true | |
| fi | |
| echo "CONTENTS OF notebooks_to_convert.txt:" | |
| cat notebooks_to_convert.txt | |
| echo "--- END DEBUG ---" | |
| echo "notebooks<<EOF" >> $GITHUB_OUTPUT | |
| cat notebooks_to_convert.txt >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - name: Convert changed notebooks | |
| run: | | |
| printf "## Processing Report\n" >> $SUMMARY_FILE | |
| printf "| Notebook | Questions | Code Blocks | ZIP |\n" >> $SUMMARY_FILE | |
| printf "|----------|-----------|-------------|------|\n" >> $SUMMARY_FILE | |
| echo "===== DEBUG CONVERT STEP =====" | |
| echo "RAW NOTEBOOKS INPUT:" | |
| echo "${{ steps.detect_notebooks.outputs.notebooks }}" | cat -A | |
| echo "--- Starting conversion loop ---" | |
| echo "${{ steps.detect_notebooks.outputs.notebooks }}" | while IFS= read -r nb; do | |
| [ -z "$nb" ] && continue | |
| echo "[DEBUG] Converting notebook: '$nb'" | |
| git checkout origin/main -- "$nb" | |
| uv run .github/scripts/student_version.py "$nb" \ | |
| --config "$CONFIG_PATH" \ | |
| --hide-header >> $SUMMARY_FILE | |
| done | |
| echo "--- END OF CONVERT STEP ---" | |
| - name: Execute post-processing command | |
| run: | | |
| if [ -n "$POST_PROCESSING" ]; then | |
| OUTPUT=$(bash -c "$POST_PROCESSING" 2>&1) | |
| EXIT_CODE=$? | |
| if [ $EXIT_CODE -eq 0 ]; then | |
| printf "## Post-processing executed successfully ✅\n" >> $SUMMARY_FILE | |
| if [ -n "$OUTPUT" ]; then | |
| printf "%s\n" "$OUTPUT" >> $SUMMARY_FILE | |
| else | |
| printf "\n" >> $SUMMARY_FILE | |
| fi | |
| else | |
| printf "## Post-processing failed ❌\n" >> $SUMMARY_FILE | |
| printf "Exit code: %d\n" "$EXIT_CODE" >> $SUMMARY_FILE | |
| if [ -n "$OUTPUT" ]; then | |
| printf "\n" >> $SUMMARY_FILE | |
| printf "Command output (including errors):\n" >> $SUMMARY_FILE | |
| printf "%s\n" "$OUTPUT" >> $SUMMARY_FILE | |
| fi | |
| fi | |
| fi | |
| - name: Manage summary | |
| run: | | |
| cp -a $SUMMARY_FILE . | |
| cat README.md >> $GITHUB_STEP_SUMMARY | |
| - name: Set up Git identity | |
| run: | | |
| git config --global user.name "GitHub Actions" | |
| git config --global user.email "actions@github.com" | |
| - name: Commit and push changes | |
| run: | | |
| git commit -m "Update student materials: $(date +'%Y-%m-%d %H:%M:%S')" || echo "No changes" | |
| git push origin Students |