Skip to content

Commit adfc69f

Browse files
Copilotinfomofo
andcommitted
Remove failed CI card image generation feature and document lessons learned
- Revert .github/workflows/test.yml to simple lint/build/test workflow - Remove Tests/PlayingCardTests/DisplayCardSnapshotTests.swift (entire file) - Remove .github/workflows/cleanup-card-images.yml - Clean up .gitignore to remove card-images/ entries - Add comprehensive "FAILED APPROACHES" section to AGENTS.md documenting: * Technical failures of SwiftUI rendering in headless CI * Test discovery issues with conditional compilation * Complex fallback logic problems * Lessons for future attempts Co-authored-by: infomofo <539599+infomofo@users.noreply.github.com>
1 parent 1c8a41a commit adfc69f

5 files changed

Lines changed: 38 additions & 587 deletions

File tree

.github/workflows/cleanup-card-images.yml

Lines changed: 0 additions & 43 deletions
This file was deleted.

.github/workflows/test.yml

Lines changed: 0 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ on:
66
pull_request:
77
branches: [ "main" ]
88

9-
permissions:
10-
contents: read
11-
pull-requests: write
12-
issues: write
13-
149
jobs:
1510
test:
1611
runs-on: macos-latest
@@ -30,170 +25,3 @@ jobs:
3025

3126
- name: Run tests
3227
run: make test
33-
34-
- name: Generate sample card images
35-
run: |
36-
echo "🔍 Current working directory: $(pwd)"
37-
echo "🧪 Running image generation test..."
38-
swift test --filter PlayingCardTests.DisplayCardSnapshotTests.testGenerateSampleCardImages
39-
40-
- name: Check for generated images
41-
run: |
42-
echo "Checking for card images directory..."
43-
if [ -d "card-images" ]; then
44-
echo "✅ card-images directory exists"
45-
echo "Contents:"
46-
ls -la card-images/
47-
else
48-
echo "❌ card-images directory not found"
49-
echo "Current directory contents:"
50-
ls -la
51-
fi
52-
53-
- name: Commit card images to repository
54-
if: always()
55-
run: |
56-
# Configure git for the action
57-
git config --local user.email "action@github.com"
58-
git config --local user.name "GitHub Action"
59-
60-
# Create a temporary branch for images if it doesn't exist
61-
if [ -d "card-images" ]; then
62-
echo "📸 Committing generated card images..."
63-
64-
# Add the images to git
65-
git add card-images/
66-
67-
# Only commit if there are changes
68-
if ! git diff --cached --quiet; then
69-
git commit -m "Add generated card images for PR review [skip ci]"
70-
git push origin HEAD
71-
echo "✅ Images committed and pushed"
72-
else
73-
echo "ℹ️ No new images to commit"
74-
fi
75-
else
76-
echo "⚠️ No card-images directory found to commit"
77-
fi
78-
79-
- name: Upload card images as artifacts
80-
if: always()
81-
uses: actions/upload-artifact@v4
82-
with:
83-
name: sample-card-images
84-
path: card-images/
85-
retention-days: 30
86-
87-
- name: Comment PR with embedded card images
88-
if: github.event_name == 'pull_request' && always()
89-
uses: actions/github-script@v7
90-
with:
91-
script: |
92-
const fs = require('fs');
93-
94-
console.log('🔍 Starting PR comment generation...');
95-
96-
// Check if card images directory exists
97-
const cardImagesDir = 'card-images';
98-
if (!fs.existsSync(cardImagesDir)) {
99-
console.log('❌ No card images directory found');
100-
await github.rest.issues.createComment({
101-
issue_number: context.issue.number,
102-
owner: context.repo.owner,
103-
repo: context.repo.repo,
104-
body: `## ⚠️ Card Image Generation Failed\n\nThe workflow was unable to generate sample playing card images. This indicates an issue with the test execution.\n\n**Debug Info**: Generated at ${new Date().toISOString()}`
105-
});
106-
return;
107-
}
108-
109-
console.log('✅ Found card-images directory');
110-
111-
// Get list of generated files
112-
const allFiles = fs.readdirSync(cardImagesDir).sort();
113-
const imageFiles = allFiles.filter(file => file.endsWith('.png'));
114-
115-
console.log(`🖼️ Found ${imageFiles.length} PNG files: ${imageFiles.join(', ')}`);
116-
117-
// Read manifest for card information
118-
let cardList = [];
119-
const manifestFile = 'manifest.txt';
120-
if (allFiles.includes(manifestFile)) {
121-
const manifestPath = `${cardImagesDir}/${manifestFile}`;
122-
const manifestContent = fs.readFileSync(manifestPath, 'utf8');
123-
cardList = manifestContent.trim().split('\n').filter(line => line.trim());
124-
console.log(`📝 Manifest contains ${cardList.length} cards: ${cardList.join(', ')}`);
125-
}
126-
127-
// Create comment body
128-
let commentBody = `## 🃏 Sample Playing Cards Generated\n\n`;
129-
commentBody += `The following sample cards were generated from the \`DisplayCard\` SwiftUI component:\n\n`;
130-
131-
const suitEmojis = {
132-
'spades': '♠️',
133-
'hearts': '♥️',
134-
'diamonds': '♦️',
135-
'clubs': '♣️'
136-
};
137-
138-
// Get the current branch name for image URLs
139-
const currentBranch = context.ref.replace('refs/heads/', '');
140-
const repoUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}`;
141-
142-
if (cardList.length > 0 && imageFiles.length > 0) {
143-
// Create mapping from card description to image filename
144-
const cardImageMap = new Map();
145-
cardList.forEach(cardInfo => {
146-
const parts = cardInfo.split(' of ');
147-
if (parts.length === 2) {
148-
const rank = parts[0].toLowerCase();
149-
const suit = parts[1].toLowerCase();
150-
const expectedFilename = `${suit}_${rank}.png`;
151-
if (imageFiles.includes(expectedFilename)) {
152-
cardImageMap.set(cardInfo, expectedFilename);
153-
}
154-
}
155-
});
156-
157-
// Embed actual images
158-
for (const cardInfo of cardList) {
159-
// Add appropriate emoji based on suit
160-
let displayName = cardInfo;
161-
for (const [suit, emoji] of Object.entries(suitEmojis)) {
162-
if (cardInfo.toLowerCase().includes(suit)) {
163-
displayName = `${cardInfo} ${emoji}`;
164-
break;
165-
}
166-
}
167-
168-
const imageFilename = cardImageMap.get(cardInfo);
169-
if (imageFilename) {
170-
// Embed the image using GitHub's raw content URL
171-
const imageUrl = `${repoUrl}/raw/${currentBranch}/card-images/${imageFilename}`;
172-
commentBody += `### ${displayName}\n`;
173-
commentBody += `![${cardInfo}](${imageUrl})\n\n`;
174-
} else {
175-
commentBody += `### ${displayName}\n`;
176-
commentBody += `*Image generation failed for this card*\n\n`;
177-
}
178-
}
179-
180-
commentBody += `\n**Format**: ${imageFiles.length} PNG image(s) generated from SwiftUI DisplayCard component\n`;
181-
} else {
182-
commentBody += `Card generation completed but no valid cards were found.\n\n`;
183-
}
184-
185-
commentBody += `\n📁 **Artifacts**: The generated files are also available as artifacts in the [Actions tab](${context.payload.repository.html_url}/actions/runs/${context.runId}).\n\n`;
186-
commentBody += `These help reviewers visualize how the \`DisplayCard\` SwiftUI component renders different playing cards.\n\n`;
187-
commentBody += `**Generated**: ${allFiles.length} file(s) at ${new Date().toISOString()}`;
188-
189-
console.log('💬 Posting PR comment with embedded images...');
190-
191-
// Post comment on PR
192-
await github.rest.issues.createComment({
193-
issue_number: context.issue.number,
194-
owner: context.repo.owner,
195-
repo: context.repo.repo,
196-
body: commentBody
197-
});
198-
199-
console.log('✅ Successfully posted PR comment with embedded card images');

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,5 @@
1010
# Generated test images (uploaded as CI artifacts instead)
1111
Tests/PlayingCardTests/*.png
1212

13-
# Generated card images from snapshot tests (temporarily committed for PR comments)
14-
# card-images/
15-
1613
# SwiftLint temporary files
1714
.swiftlint_output

AGENTS.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,44 @@ Example of the transformation:
198198
3. Simplify GitHub Actions workflows to remove complex detection logic
199199
4. Focus on the user's actual need (images in PR comments) rather than perfect technical implementation
200200
- Use GitHub's file URLs: `https://github.com/owner/repo/raw/branch/path/to/image.png`
201+
202+
## ⚠️ FAILED APPROACHES - DO NOT REPEAT
203+
204+
### Card Image Generation in CI (August 2025)
205+
206+
**FAILED FEATURE**: Automated card image generation with PR comment embedding
207+
208+
**What was attempted**: A CI workflow that would generate sample playing card images during PR builds and embed them in PR comments to help reviewers visualize card rendering.
209+
210+
**Why it failed repeatedly**:
211+
1. **Test discovery inconsistency**: `#if canImport(SwiftUI)` conditional compilation meant tests didn't exist on some platforms, causing `swift test --filter` to succeed with 0 tests executed
212+
2. **SwiftUI rendering fragility**: Even on macOS CI runners, SwiftUI-to-image conversion (NSHostingView, SwiftUI.ImageRenderer) failed silently in headless environments
213+
3. **Complex fallback logic**: Multiple layers of fallback detection in GitHub Actions YAML became unmaintainable and introduced their own failure points
214+
4. **Iteration difficulty**: Agent couldn't predict failure scenarios, leading to 15+ commits of back-and-forth fixes without resolution
215+
216+
**Specific technical failures**:
217+
- NSHostingView couldn't create valid NSImage from SwiftUI views in headless CI
218+
- SwiftUI.ImageRenderer with @MainActor annotation still failed to render
219+
- GitHub Actions `||` fallback syntax was unreliable with proper exit code handling
220+
- Test filter patterns failed when tests were conditionally compiled out
221+
- Complex PNG generation fallbacks created invalid files that broke subsequent workflow steps
222+
223+
**Root cause**: **Over-engineering a simple problem**. The goal was just to show sample card images in PR comments, but the implementation became a complex system trying to handle every possible CI environment failure scenario.
224+
225+
**Lesson for future attempts**:
226+
- **Don't attempt SwiftUI rendering in CI** - it's fundamentally unreliable in headless environments
227+
- **Don't use conditional compilation for CI-critical tests** - tests should exist on all platforms
228+
- **Start with the simplest possible solution** - static placeholder images may be better than complex rendering
229+
- **Test the CI scenario locally first** - but recognize that local testing may not catch all CI environment issues
230+
- **Have a clear "abort" criteria** - if something fails more than 3-4 iterations, the approach is likely fundamentally flawed
231+
232+
**Alternative approaches to consider**:
233+
1. **Static sample images**: Pre-generated images committed to the repository
234+
2. **Manual image updates**: Developer-generated images updated when UI changes
235+
3. **Local-only image generation**: Developer runs script locally and commits results
236+
4. **Skip image generation entirely**: Focus on text-based PR descriptions of UI changes
237+
238+
**DO NOT** attempt to resurrect this exact approach without fundamentally different technical strategy.
201239
- Add cleanup workflows to remove images after PR closure
202240
- Consider image file sizes to avoid repository bloat
203241

0 commit comments

Comments
 (0)