From 461baa98100265c6966b0aa775f78263a5874be2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Oct 2025 18:42:48 +0000
Subject: [PATCH 1/3] Initial plan
From 46c3f2ec4062cf607b0e05d36d5e04b8189ee5a0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Oct 2025 18:49:27 +0000
Subject: [PATCH 2/3] Add corrected check-media-attachments.yml workflow with
all fixes
Co-authored-by: A1L13N <193832434+A1L13N@users.noreply.github.com>
---
.github/workflows/check-media-attachments.yml | 189 ++++++++++++++++++
1 file changed, 189 insertions(+)
create mode 100644 .github/workflows/check-media-attachments.yml
diff --git a/.github/workflows/check-media-attachments.yml b/.github/workflows/check-media-attachments.yml
new file mode 100644
index 000000000..50a2e54cf
--- /dev/null
+++ b/.github/workflows/check-media-attachments.yml
@@ -0,0 +1,189 @@
+name: Check PR for media attachments when HTML files change
+
+"on":
+ pull_request:
+ types: [opened, synchronize, reopened]
+ paths:
+ - '**/*.html'
+ - '**/*.htm'
+ - '**/*.xhtml'
+
+concurrency:
+ group: check-media-attachments-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
+
+jobs:
+ check-media-attachments:
+ runs-on: ubuntu-latest
+ name: Check media attachments in HTML files
+ permissions:
+ contents: read
+ pull-requests: write
+ issues: write
+ steps:
+ - name: Check for media attachments in HTML files
+ uses: actions/github-script@v7
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const { owner, repo } = context.repo;
+ const { number } = context.payload.pull_request;
+
+ console.log(`Checking PR #${number} for media attachments in HTML files`);
+
+ // Get all changed files across all pages
+ const files = await github.paginate(
+ github.rest.pulls.listFiles,
+ { owner, repo, pull_number: number, per_page: 100 }
+ );
+
+ // Filter for HTML files that were added, modified, or renamed
+ const htmlFiles = files.filter(file =>
+ /\.(?:html?|xhtml)$/i.test(file.filename) &&
+ ['added', 'modified', 'renamed'].includes(file.status)
+ );
+
+ if (htmlFiles.length === 0) {
+ console.log('No HTML files were changed in this PR.');
+ return;
+ }
+
+ console.log(`Found ${htmlFiles.length} HTML file(s) to check:`);
+ htmlFiles.forEach(file => console.log(`- ${file.filename}`));
+
+ let hasIssues = false;
+ const issues = [];
+ const mediaReferences = [];
+
+ for (const file of htmlFiles) {
+ console.log(`\nAnalyzing ${file.filename}...`);
+
+ try {
+ // Get file content from the PR branch
+ const { data: fileData } = await github.rest.repos.getContent({
+ owner,
+ repo,
+ path: file.filename,
+ ref: context.payload.pull_request.head.sha
+ });
+
+ // Handle truncated content or non-file responses
+ if (Array.isArray(fileData) || fileData.type !== 'file') {
+ throw new Error('Not a file content response');
+ }
+
+ let content;
+ if (fileData.encoding === 'base64' && fileData.content) {
+ content = Buffer.from(fileData.content, 'base64').toString('utf8');
+ } else if (fileData.sha) {
+ const { data: blob } = await github.rest.git.getBlob({
+ owner,
+ repo,
+ file_sha: fileData.sha
+ });
+ content = Buffer.from(blob.content, 'base64').toString('utf8');
+ } else {
+ throw new Error('Unable to retrieve file content');
+ }
+
+ // Check for images without alt attributes
+ const imgWithoutAlt = content.match(/
]*\balt=)[^>]*>/gi);
+ if (imgWithoutAlt && imgWithoutAlt.length > 0) {
+ hasIssues = true;
+ issues.push(`**${file.filename}**: Found ${imgWithoutAlt.length} image(s) without alt attributes`);
+ console.log(` - Found ${imgWithoutAlt.length} img tag(s) without alt attributes`);
+ }
+
+ // Check for media files referenced (including poster, src, href, and srcset)
+ const direct = [...content.matchAll(/\b(?:src|href|poster)\s*=\s*["']([^"']+\.(?:jpg|jpeg|png|gif|webp|svg|mp4|avi|mov|pdf))(?:\?[^"']*)?["']/gi)]
+ .map(m => m[1])
+ .filter(u => !/^data:/i.test(u));
+ const srcsetUrls = [...content.matchAll(/\bsrcset\s*=\s*["']([^"']+)["']/gi)]
+ .flatMap(m => m[1].split(',').map(s => s.trim().split(/\s+/)[0]))
+ .filter(u => /\.(?:jpg|jpeg|png|gif|webp|svg)$/i.test(u) && !/^data:/i.test(u));
+ const allMedia = [...new Set([...direct, ...srcsetUrls])];
+
+ if (allMedia.length > 0) {
+ mediaReferences.push(`**${file.filename}**: References ${allMedia.length} media file(s)`);
+ console.log(` - Found ${allMedia.length} media reference(s)`);
+
+ // Check for large image formats that could be optimized
+ const unoptimizedImages = allMedia.filter(u => /\.(jpg|jpeg|png)$/i.test(u));
+ if (unoptimizedImages.length > 0) {
+ issues.push(`**${file.filename}**: Consider using WebP format for ${unoptimizedImages.length} image(s) for better performance`);
+ }
+ }
+
+ // Check for missing figure captions for accessibility
+ const figureBlocks = Array.from(content.matchAll(/]*>([\s\S]*?)<\/figure>/gi));
+ const figuresWithoutCaption = figureBlocks.filter(match => !/]/i.test(match[1]));
+ if (figuresWithoutCaption.length > 0) {
+ issues.push(`**${file.filename}**: Found ${figuresWithoutCaption.length} figure(s) without figcaption for accessibility`);
+ }
+
+ } catch (error) {
+ console.error(`Error processing ${file.filename}: ${error.message}`);
+ issues.push(`**${file.filename}**: Could not analyze file - ${error.message}`);
+ }
+ }
+
+ // Create summary comment
+ let commentBody = '## 📸 Media Attachments Analysis\n\n';
+
+ if (mediaReferences.length > 0) {
+ commentBody += '### Media Files Found\n';
+ commentBody += mediaReferences.map(ref => `- ${ref}`).join('\n') + '\n\n';
+ }
+
+ if (hasIssues) {
+ commentBody += '### ⚠️ Issues Found\n';
+ commentBody += issues.map(issue => `- ${issue}`).join('\n') + '\n\n';
+ commentBody += '**Recommendations:**\n';
+ commentBody += '- Add `alt` attributes to all images for accessibility\n';
+ commentBody += '- Consider using WebP format for better performance\n';
+ commentBody += '- Add `` to `` elements for screen readers\n\n';
+ } else {
+ commentBody += '### ✅ All Checks Passed\n';
+ commentBody += 'No media-related issues found in the HTML files.\n\n';
+ }
+
+ commentBody += '*This check was automatically performed when HTML files were modified.*';
+
+ // Check if we already commented on this PR
+ const { data: comments } = await github.rest.issues.listComments({
+ owner,
+ repo,
+ issue_number: number,
+ });
+
+ const botComment = comments.find(comment =>
+ comment.user.login === 'github-actions[bot]' &&
+ comment.body.includes('📸 Media Attachments Analysis')
+ );
+
+ if (botComment) {
+ // Update existing comment
+ await github.rest.issues.updateComment({
+ owner,
+ repo,
+ comment_id: botComment.id,
+ body: commentBody
+ });
+ console.log('Updated existing media attachments comment');
+ } else {
+ // Create new comment
+ await github.rest.issues.createComment({
+ owner,
+ repo,
+ issue_number: number,
+ body: commentBody
+ });
+ console.log('Created new media attachments comment');
+ }
+
+ // Don't fail the workflow, just inform
+ if (hasIssues) {
+ console.log('⚠️ Media attachment issues found, but not failing the workflow');
+ } else {
+ console.log('✅ All media attachment checks passed!');
+ }
From e0869f4e552f264e2b736b6fe1877996effe855c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 8 Oct 2025 15:13:09 +0000
Subject: [PATCH 3/3] Add linked issue media detection to workflow
Co-authored-by: A1L13N <193832434+A1L13N@users.noreply.github.com>
---
.github/workflows/check-media-attachments.yml | 50 ++++++++++++++++++-
1 file changed, 48 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/check-media-attachments.yml b/.github/workflows/check-media-attachments.yml
index 50a2e54cf..39b7b9479 100644
--- a/.github/workflows/check-media-attachments.yml
+++ b/.github/workflows/check-media-attachments.yml
@@ -127,14 +127,60 @@ jobs:
}
}
+ // Check linked issues for media attachments
+ const issueMediaReferences = [];
+ const prBody = context.payload.pull_request.body || '';
+
+ // Extract issue numbers from PR body (e.g., "Fixes #123", "Closes #456", etc.)
+ const issueMatches = prBody.matchAll(/(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi);
+ const linkedIssues = [...new Set([...issueMatches].map(match => parseInt(match[1])))];
+
+ for (const issueNumber of linkedIssues) {
+ try {
+ const { data: issue } = await github.rest.issues.get({
+ owner,
+ repo,
+ issue_number: issueNumber
+ });
+
+ const issueBody = issue.body || '';
+
+ // Check for media in issue body using same detection logic
+ const issueDirect = [...issueBody.matchAll(/\b(?:src|href|poster)\s*=\s*["']([^"']+\.(?:jpg|jpeg|png|gif|webp|svg|mp4|avi|mov|pdf))(?:\?[^"']*)?["']/gi)]
+ .map(m => m[1])
+ .filter(u => !/^data:/i.test(u));
+ const issueSrcset = [...issueBody.matchAll(/\bsrcset\s*=\s*["']([^"']+)["']/gi)]
+ .flatMap(m => m[1].split(',').map(s => s.trim().split(/\s+/)[0]))
+ .filter(u => /\.(?:jpg|jpeg|png|gif|webp|svg)$/i.test(u) && !/^data:/i.test(u));
+ const issueMedia = [...new Set([...issueDirect, ...issueSrcset])];
+
+ // Also check for direct image/video URLs in markdown format
+ const markdownMedia = [...issueBody.matchAll(/!\[([^\]]*)\]\(([^)]+\.(?:jpg|jpeg|png|gif|webp|svg|mp4))\)/gi)]
+ .map(m => m[2]);
+ const allIssueMedia = [...new Set([...issueMedia, ...markdownMedia])];
+
+ if (allIssueMedia.length > 0) {
+ issueMediaReferences.push(`**Issue #${issueNumber}** ([${issue.title}](${issue.html_url})): ${allIssueMedia.length} media file(s) found`);
+ console.log(` - Found ${allIssueMedia.length} media reference(s) in issue #${issueNumber}`);
+ }
+ } catch (error) {
+ console.log(`Could not check issue #${issueNumber}: ${error.message}`);
+ }
+ }
+
// Create summary comment
let commentBody = '## 📸 Media Attachments Analysis\n\n';
if (mediaReferences.length > 0) {
- commentBody += '### Media Files Found\n';
+ commentBody += '### Media Files Found in Changed HTML Files\n';
commentBody += mediaReferences.map(ref => `- ${ref}`).join('\n') + '\n\n';
}
+ if (issueMediaReferences.length > 0) {
+ commentBody += '### Media Files Found in Linked Issues\n';
+ commentBody += issueMediaReferences.map(ref => `- ${ref}`).join('\n') + '\n\n';
+ }
+
if (hasIssues) {
commentBody += '### ⚠️ Issues Found\n';
commentBody += issues.map(issue => `- ${issue}`).join('\n') + '\n\n';
@@ -142,7 +188,7 @@ jobs:
commentBody += '- Add `alt` attributes to all images for accessibility\n';
commentBody += '- Consider using WebP format for better performance\n';
commentBody += '- Add `` to `` elements for screen readers\n\n';
- } else {
+ } else if (mediaReferences.length === 0 && issueMediaReferences.length === 0) {
commentBody += '### ✅ All Checks Passed\n';
commentBody += 'No media-related issues found in the HTML files.\n\n';
}