Skip to content

Commit aee4dfd

Browse files
authored
Merge branch 'main' into update_ar1_turningpts
2 parents a91b076 + a7648c0 commit aee4dfd

File tree

7 files changed

+1480
-1057
lines changed

7 files changed

+1480
-1057
lines changed

.github/workflows/ci.yml

Lines changed: 255 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
name: Build Project [using jupyter-book]
22
on:
33
pull_request:
4+
types: [opened, synchronize, reopened]
45
workflow_dispatch:
6+
inputs:
7+
preview_page:
8+
description: 'Specific page to preview (e.g., aiyagari.html)'
9+
required: false
10+
type: string
511
jobs:
612
preview:
713
runs-on: "runs-on=${{ github.run_id }}/family=g4dn.2xlarge/image=quantecon_ubuntu2404/disk=large"
814
steps:
915
- uses: actions/checkout@v5
1016
with:
1117
ref: ${{ github.event.pull_request.head.sha }}
18+
fetch-depth: 0
1219
- name: Setup Anaconda
1320
uses: conda-incubator/setup-miniconda@v3
1421
with:
@@ -78,13 +85,255 @@ jobs:
7885
with:
7986
name: execution-reports
8087
path: _build/html/reports
88+
- name: Install Node.js and Netlify CLI
89+
shell: bash -l {0}
90+
run: |
91+
# Install Node.js via system package manager since conda-forge doesn't have npm
92+
sudo apt-get update
93+
sudo apt-get install -y nodejs npm
94+
sudo npm install -g netlify-cli
95+
- name: Detect Changed Lecture Files
96+
id: detect-changes
97+
shell: bash -l {0}
98+
run: |
99+
if [ "${{ github.event_name }}" = "pull_request" ]; then
100+
echo "Detecting changed lecture files..."
101+
echo "Base SHA: ${{ github.event.pull_request.base.sha }}"
102+
echo "Head SHA: ${{ github.event.pull_request.head.sha }}"
103+
104+
# Ensure we have both base and head commits available
105+
git fetch origin ${{ github.event.pull_request.base.sha }}:refs/remotes/origin/pr-base || true
106+
git fetch origin ${{ github.event.pull_request.head.sha }}:refs/remotes/origin/pr-head || true
107+
108+
# Get changed files using git diff with status to see the type of change
109+
echo "Getting diff between commits..."
110+
all_changed=$(git diff --name-status ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} 2>/dev/null || echo "")
111+
112+
if [ -z "$all_changed" ]; then
113+
echo "No changes detected or error in git diff"
114+
echo "changed_files=" >> $GITHUB_OUTPUT
115+
exit 0
116+
fi
117+
118+
echo "All changed files with status:"
119+
echo "$all_changed"
120+
121+
# Filter for lecture files that are Added or Modified (not Deleted)
122+
# Format: M lectures/file.md or A lectures/file.md
123+
changed_lecture_files=""
124+
while IFS=$'\t' read -r status file; do
125+
# Skip if empty line
126+
[ -z "$status" ] && continue
127+
128+
echo "Processing: status='$status' file='$file'"
129+
130+
# Only include Added (A) or Modified (M) files, skip Deleted (D)
131+
if [[ "$status" =~ ^[AM] ]] && [[ "$file" =~ ^lectures/.*\.md$ ]] && [[ ! "$file" =~ ^lectures/_ ]] && [[ "$file" != "lectures/intro.md" ]]; then
132+
# Double-check that the file exists and has real content changes
133+
if [ -f "$file" ]; then
134+
# Use git show to check if there are actual content changes (not just metadata)
135+
content_diff=$(git diff ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} -- "$file" | grep -E '^[+-]' | grep -v '^[+-]{3}' | wc -l)
136+
if [ "$content_diff" -gt 0 ]; then
137+
echo "✓ Confirmed content changes in: $file"
138+
if [ -z "$changed_lecture_files" ]; then
139+
changed_lecture_files="$file"
140+
else
141+
changed_lecture_files="$changed_lecture_files"$'\n'"$file"
142+
fi
143+
else
144+
echo "⚠ No content changes found in: $file (possibly metadata only)"
145+
fi
146+
else
147+
echo "⚠ File not found in working directory: $file"
148+
fi
149+
else
150+
echo "⚠ Skipping: $file (status: $status, doesn't match lecture file pattern or is excluded)"
151+
fi
152+
done <<< "$all_changed"
153+
154+
if [ ! -z "$changed_lecture_files" ]; then
155+
echo ""
156+
echo "Final validated changed lecture files:"
157+
echo "$changed_lecture_files"
158+
echo "changed_files<<EOF" >> $GITHUB_OUTPUT
159+
echo "$changed_lecture_files" >> $GITHUB_OUTPUT
160+
echo "EOF" >> $GITHUB_OUTPUT
161+
else
162+
echo "No lecture files with actual content changes found"
163+
echo "changed_files=" >> $GITHUB_OUTPUT
164+
fi
165+
else
166+
echo "Not a PR, skipping change detection"
167+
echo "changed_files=" >> $GITHUB_OUTPUT
168+
fi
81169
- name: Preview Deploy to Netlify
82-
uses: nwtgck/actions-netlify@v3
83-
with:
84-
publish-dir: '_build/html/'
85-
production-branch: main
86-
github-token: ${{ secrets.GITHUB_TOKEN }}
87-
deploy-message: "Preview Deploy from GitHub Actions"
170+
id: netlify-deploy
171+
shell: bash -l {0}
172+
run: |
173+
if [ "${{ github.event_name }}" = "pull_request" ]; then
174+
# Deploy to Netlify and capture the response
175+
deploy_message="Preview Deploy from GitHub Actions PR #${{ github.event.pull_request.number }} (commit: ${{ github.event.pull_request.head.sha }})"
176+
177+
netlify_output=$(netlify deploy \
178+
--dir _build/html/ \
179+
--site ${{ secrets.NETLIFY_SITE_ID }} \
180+
--auth ${{ secrets.NETLIFY_AUTH_TOKEN }} \
181+
--context pr-preview \
182+
--alias pr-${{ github.event.pull_request.number }} \
183+
--message "${deploy_message}" \
184+
--json)
185+
186+
echo "Netlify deployment output:"
187+
echo "$netlify_output"
188+
189+
# Extract the actual deploy URL from the JSON response
190+
deploy_url=$(echo "$netlify_output" | jq -r '.deploy_url')
191+
192+
echo "deploy_url=$deploy_url" >> $GITHUB_OUTPUT
193+
echo "✅ Deployment completed!"
194+
echo "🌐 Actual Deploy URL: $deploy_url"
195+
196+
# Generate preview URLs for changed files using the actual deploy URL
197+
if [ ! -z "${{ steps.detect-changes.outputs.changed_files }}" ]; then
198+
echo ""
199+
echo "📚 Direct links to changed lecture pages:"
200+
while read -r file; do
201+
if [ ! -z "$file" ]; then
202+
basename=$(basename "$file" .md)
203+
html_file="${basename}.html"
204+
echo "- ${basename}: ${deploy_url}/${html_file}"
205+
fi
206+
done <<< "${{ steps.detect-changes.outputs.changed_files }}"
207+
fi
208+
209+
# Display manual preview page if specified
210+
if [ ! -z "${{ github.event.inputs.preview_page }}" ]; then
211+
echo ""
212+
echo "🎯 Manual preview page: ${deploy_url}/${{ github.event.inputs.preview_page }}"
213+
fi
214+
else
215+
# Handle manual deployment
216+
deploy_message="Manual Deploy from GitHub Actions (commit: ${{ github.sha }})"
217+
218+
netlify_output=$(netlify deploy \
219+
--dir _build/html/ \
220+
--site ${{ secrets.NETLIFY_SITE_ID }} \
221+
--auth ${{ secrets.NETLIFY_AUTH_TOKEN }} \
222+
--alias manual-${{ github.run_id }} \
223+
--context dev \
224+
--message "${deploy_message}" \
225+
--json)
226+
227+
echo "Netlify deployment output:"
228+
echo "$netlify_output"
229+
230+
# Extract the actual deploy URL from the JSON response
231+
deploy_url=$(echo "$netlify_output" | jq -r '.deploy_url')
232+
233+
echo "deploy_url=$deploy_url" >> $GITHUB_OUTPUT
234+
echo "✅ Manual deployment completed!"
235+
echo "🌐 Actual Deploy URL: $deploy_url"
236+
237+
if [ ! -z "${{ github.event.inputs.preview_page }}" ]; then
238+
echo "🎯 Preview page: ${deploy_url}/${{ github.event.inputs.preview_page }}"
239+
fi
240+
fi
88241
env:
89242
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
90243
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
244+
- name: Post PR Comment with Preview Links
245+
if: github.event_name == 'pull_request'
246+
uses: actions/github-script@v7
247+
with:
248+
script: |
249+
const changedFiles = `${{ steps.detect-changes.outputs.changed_files }}`;
250+
const manualPage = `${{ github.event.inputs.preview_page }}`;
251+
const deployUrl = `${{ steps.netlify-deploy.outputs.deploy_url }}`;
252+
const prNumber = ${{ github.event.pull_request.number }};
253+
const commitSha = `${{ github.event.pull_request.head.sha }}`;
254+
const shortSha = commitSha.substring(0, 7);
255+
256+
console.log(`Checking for existing comments for commit: ${commitSha}`);
257+
console.log(`Deploy URL: ${deployUrl}`);
258+
console.log(`Changed files: ${changedFiles}`);
259+
260+
// Get all comments on this PR to check for duplicates
261+
const comments = await github.rest.issues.listComments({
262+
issue_number: prNumber,
263+
owner: context.repo.owner,
264+
repo: context.repo.repo,
265+
});
266+
267+
console.log(`Found ${comments.data.length} comments on PR`);
268+
269+
// Look for existing comment with this exact commit SHA and deploy URL
270+
const duplicateComment = comments.data.find(comment => {
271+
const hasMarker = comment.body.includes('**📖 Netlify Preview Ready!**');
272+
const hasCommitSha = comment.body.includes(`([${shortSha}]`);
273+
const hasDeployUrl = comment.body.includes(deployUrl);
274+
275+
console.log(`Comment ${comment.id}: hasMarker=${hasMarker}, hasCommitSha=${hasCommitSha}, hasDeployUrl=${hasDeployUrl}`);
276+
277+
return hasMarker && hasCommitSha && hasDeployUrl;
278+
});
279+
280+
if (duplicateComment) {
281+
console.log(`Duplicate comment found (${duplicateComment.id}) for commit ${shortSha} and deploy URL ${deployUrl}, skipping...`);
282+
return;
283+
}
284+
285+
console.log(`No duplicate found, creating new comment for commit ${shortSha}`);
286+
287+
const commitUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${commitSha}`;
288+
289+
let comment = `**📖 Netlify Preview Ready!**\n\n`;
290+
comment += `**Preview URL:** ${deployUrl} ([${shortSha}](${commitUrl}))\n\n`;
291+
292+
// Add manual preview page if specified
293+
if (manualPage) {
294+
comment += `🎯 **Manual Preview:** [${manualPage}](${deployUrl}/${manualPage})\n\n`;
295+
}
296+
297+
// Add direct links to changed lecture pages
298+
if (changedFiles && changedFiles.trim()) {
299+
console.log('Processing changed files for preview links...');
300+
const files = changedFiles.split('\n').filter(f => f.trim() && f.includes('lectures/') && f.endsWith('.md'));
301+
console.log('Filtered lecture files:', files);
302+
303+
if (files.length > 0) {
304+
comment += `📚 **Changed Lecture Pages:** `;
305+
306+
const pageLinks = [];
307+
for (const file of files) {
308+
const cleanFile = file.trim();
309+
if (cleanFile && cleanFile.startsWith('lectures/') && cleanFile.endsWith('.md')) {
310+
const fileName = cleanFile.replace('lectures/', '').replace('.md', '');
311+
console.log(`Creating preview link: ${cleanFile} -> ${fileName}.html`);
312+
const pageUrl = `${deployUrl}/${fileName}.html`;
313+
pageLinks.push(`[${fileName}](${pageUrl})`);
314+
}
315+
}
316+
317+
if (pageLinks.length > 0) {
318+
comment += pageLinks.join(', ') + '\n\n';
319+
} else {
320+
console.log('No valid page links created');
321+
}
322+
} else {
323+
console.log('No lecture files in changed files list');
324+
}
325+
} else {
326+
console.log('No changed files detected');
327+
}
328+
329+
console.log('Final comment:', comment);
330+
331+
// Post the comment
332+
await github.rest.issues.createComment({
333+
issue_number: prNumber,
334+
owner: context.repo.owner,
335+
repo: context.repo.repo,
336+
body: comment
337+
});
338+
339+
console.log('Comment posted successfully');

.github/workflows/collab.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,3 @@ jobs:
9090
title: "Weekly Colab Execution Check Failed - ${{ github.run_id }}"
9191
content-filepath: execution-failure-report.md
9292
labels: execution-failure, automated-issue, colab
93-
- name: Preview Deploy to Netlify
94-
uses: nwtgck/actions-netlify@v3
95-
with:
96-
publish-dir: '_build/html/'
97-
production-branch: main
98-
github-token: ${{ secrets.GITHUB_TOKEN }}
99-
deploy-message: "Preview Deploy from GitHub Actions"
100-
env:
101-
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
102-
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
_build/
33
lectures/_build/
44
.ipynb_checkpoints/
5-
.virtual_documents/
5+
.virtual_documents/
6+
node_modules/
7+
package-lock.json

0 commit comments

Comments
 (0)