11on :
22 pull_request :
33 branches : [main, prerelease]
4+ paths-ignore :
5+ - ' .github/**'
46 issue_comment :
57 types : [created]
68
@@ -63,10 +65,24 @@ jobs:
6365 runs-on : ubuntu-latest
6466 steps :
6567 - name : Check out repository
66- uses : actions/checkout@v4
67- with :
68+ uses : actions/checkout@v6
69+ with :
6870 ref : refs/pull/${{ github.event.pull_request.number || github.event.issue.number }}/merge
6971
72+ # On issue_comment events (e.g. /deploy-preview), github.event.pull_request
73+ # is not populated so tj-actions/changed-files can't determine the base commit
74+ # to diff against. Fetch it from the API so we can pass it explicitly.
75+ - name : Get PR base SHA
76+ if : github.event_name != 'pull_request'
77+ id : pr-info
78+ env :
79+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
80+ run : |
81+ pr_number=${{ github.event.issue.number }}
82+ base_sha=$(gh -R $GITHUB_REPOSITORY pr view $pr_number --json baseRefOid --jq '.baseRefOid')
83+ echo "base_sha=$base_sha" >> "$GITHUB_OUTPUT"
84+ shell : bash
85+
7086 - name : Get latest pre-release from github
7187 id : github-release
7288 env :
@@ -127,20 +143,23 @@ jobs:
127143
128144 - name : Get changed files
129145 id : changed-files
130- uses : tj-actions/changed-files@v46 .0.5
146+ uses : tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47 .0.5
131147 with :
148+ base_sha : ${{ github.event.pull_request.base.sha || steps.pr-info.outputs.base_sha }}
132149 files : |
133150 # don't consider modifications on file used for includes for now.
134151 license.md
135152 docs/**/[^_]*.qmd
136153 docs/**/[^_]*.md
137154 docs/extensions/listings/*.yml
155+ docs/reference/**/*.json
156+ docs/cli/*.json
138157 json : true
139158 escape_json : false
140159
141160 - name : Create custom PR comment
142161 if : github.event.pull_request || github.event.issue.pull_request
143- uses : actions/github-script@v7
162+ uses : actions/github-script@v8
144163 env :
145164 DEPLOY_URL : ${{ steps.netlify-deploy.outputs.deploy-url }}
146165 CHANGED_FILES : ${{ steps.changed-files.outputs.all_changed_files }}
@@ -149,40 +168,76 @@ jobs:
149168 script : |
150169 const prNumber = context.payload.pull_request?.number || context.payload.issue.number;
151170 const deployUrl = process.env.DEPLOY_URL;
152- const changedFiles = JSON.parse(process.env.CHANGED_FILES);
153-
171+ const changedFiles = JSON.parse(process.env.CHANGED_FILES || '[]' );
172+
154173 let commentBody = `## 📝 Preview Deployment\n\n`;
155174 commentBody += `🔍 Full site preview: [${deployUrl}](${deployUrl})\n\n`;
156-
175+
157176 if (changedFiles.length > 0) {
158- commentBody += `### 🔄 Modified Documents\n\n`;
177+ // Explicit mapping for files that don't follow standard naming conventions
178+ const specialFileMapping = {
179+ 'docs/extensions/listings/shortcodes-and-filters.yml': 'docs/extensions/index.html',
180+ 'docs/extensions/listings/journal-articles.yml': 'docs/extensions/index.html',
181+ 'docs/extensions/listings/custom-formats.yml': 'docs/extensions/index.html',
182+ 'docs/extensions/listings/revealjs-formats.yml': 'docs/extensions/index.html',
183+ 'docs/extensions/listings/revealjs.yml': 'docs/extensions/index.html',
184+ 'docs/cli/cli-info.json': 'docs/reference/index.html',
185+ };
186+
187+ // Projects/ JSON files have many-to-one mapping to .qmd pages
188+ const projectsJsonMapping = {
189+ 'book': 'docs/reference/projects/books.html',
190+ 'manuscript': 'docs/reference/projects/manuscripts.html',
191+ 'project': 'docs/reference/projects/options.html',
192+ 'preview': 'docs/reference/projects/options.html',
193+ 'serve': 'docs/reference/projects/options.html',
194+ };
195+ const projectsDefault = 'docs/reference/projects/websites.html';
196+
197+ // Resolve each changed file to its preview URL path
198+ // Group files by their target page for deduplication
199+ const pageToFiles = new Map();
200+
159201 changedFiles.forEach(file => {
160202 let fileUrlPath;
161203
162- // Define a mapping for special files to their corresponding URLs
163- const specialFileMapping = {
164- 'docs/extensions/listings/shortcodes-and-filters.yml': 'docs/extensions/index.html',
165- 'docs/extensions/listings/journal-articles.yml': 'docs/extensions/index.html',
166- 'docs/extensions/listings/custom-formats.yml': 'docs/extensions/index.html',
167- 'docs/extensions/listings/revealjs-formats.yml': 'docs/extensions/index.html',
168- 'docs/extensions/listings/revealjs.yml': 'docs/extensions/index.html'
169- };
170-
171- // Check if the file is in the special mapping
172204 if (specialFileMapping[file]) {
173205 fileUrlPath = specialFileMapping[file];
174206 } else if (file.endsWith('.qmd') || file.endsWith('.md')) {
175- // Convert path to URL (removing file extension and adding appropriate path)
176207 fileUrlPath = file.replace(/\.(qmd|md)$/, '.html');
208+ } else if (file.startsWith('docs/reference/projects/') && file.endsWith('.json')) {
209+ const stem = file.split('/').pop().replace('.json', '');
210+ fileUrlPath = projectsJsonMapping[stem] || projectsDefault;
211+ } else if (file.endsWith('.json')) {
212+ // Generic: formats/, cells/, metadata/ JSON have sibling .qmd files
213+ fileUrlPath = file.replace(/\.json$/, '.html');
177214 }
178215
179216 if (fileUrlPath) {
180- const fileUrl = `${deployUrl}/${fileUrlPath}`;
181- commentBody += `- [${file}](${fileUrl})\n`;
217+ if (!pageToFiles.has(fileUrlPath)) {
218+ pageToFiles.set(fileUrlPath, []);
219+ }
220+ pageToFiles.get(fileUrlPath).push(file);
182221 }
183222 });
223+
224+ if (pageToFiles.size > 0) {
225+ commentBody += `### 🔄 Modified Documents\n\n`;
226+ for (const [page, files] of pageToFiles) {
227+ const fileUrl = `${deployUrl}/${page}`;
228+ if (files.length === 1) {
229+ commentBody += `- [${page}](${fileUrl})\n`;
230+ } else {
231+ // Multiple source files map to one page - show page with file summary
232+ const basenames = files.map(f => f.split('/').pop());
233+ const shown = basenames.slice(0, 3).join(', ');
234+ const rest = basenames.length > 3 ? `, +${basenames.length - 3} more` : '';
235+ commentBody += `- [${page}](${fileUrl}) (${shown}${rest})\n`;
236+ }
237+ }
238+ }
184239 }
185-
240+
186241 github.rest.issues.createComment({
187242 issue_number: prNumber,
188243 owner: context.repo.owner,
0 commit comments