Skip to content

Commit d0fe1f8

Browse files
EdwardAngertClaude
and
Claude
committed
Add simplified docs preview GitHub action
Creates a simplified docs preview action that comments on PRs with Vercel preview links. The action shows changed files and highlights newly added documentation from manifest.json. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 109e73b commit d0fe1f8

File tree

2 files changed

+244
-0
lines changed

2 files changed

+244
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
name: 'Docs Preview Action'
2+
description: 'A composite action to provide Vercel preview links for documentation changes'
3+
author: 'Coder'
4+
inputs:
5+
github-token:
6+
description: 'GitHub token for API operations'
7+
required: true
8+
docs-dir:
9+
description: 'Path to the docs directory'
10+
required: false
11+
default: 'docs'
12+
vercel-domain:
13+
description: 'Vercel deployment domain'
14+
required: false
15+
default: 'coder-docs-git'
16+
changed-files:
17+
description: 'JSON string of changed files (from tj-actions/changed-files)'
18+
required: true
19+
manifest-changed:
20+
description: 'Boolean indicating if manifest.json has changed (from tj-actions/changed-files)'
21+
required: true
22+
23+
outputs:
24+
has_changes:
25+
description: 'Boolean indicating if documentation files have changed'
26+
value: ${{ steps.docs-analysis.outputs.has_changes }}
27+
changed_files:
28+
description: 'List of changed documentation files formatted for comment'
29+
value: ${{ steps.docs-analysis.outputs.changed_files }}
30+
url:
31+
description: 'Vercel preview URL'
32+
value: ${{ steps.vercel-preview.outputs.url }}
33+
has_new_docs:
34+
description: 'Boolean indicating if new docs were added in manifest.json'
35+
value: ${{ steps.manifest-analysis.outputs.has_new_docs || 'false' }}
36+
new_docs:
37+
description: 'List of newly added docs formatted for comment'
38+
value: ${{ steps.manifest-analysis.outputs.new_docs || '' }}
39+
preview_links:
40+
description: 'List of preview links for newly added docs'
41+
value: ${{ steps.manifest-analysis.outputs.preview_links || '' }}
42+
43+
runs:
44+
using: 'composite'
45+
steps:
46+
- name: Set security environment
47+
shell: bash
48+
run: |
49+
# Secure the environment by clearing potentially harmful variables
50+
unset HISTFILE
51+
umask 077
52+
53+
# Validate that docs directory exists
54+
if [ ! -d "${{ inputs.docs-dir }}" ]; then
55+
echo "::error::Docs directory '${{ inputs.docs-dir }}' does not exist"
56+
exit 1
57+
fi
58+
59+
- name: Analyze docs changes
60+
id: docs-analysis
61+
shell: bash
62+
run: |
63+
# Parse changed files from input and write to temp file with strict permissions
64+
echo '${{ inputs.changed-files }}' > changed_files.json
65+
66+
# Count total changed doc files
67+
DOC_FILES_COUNT=$(jq -r '.[] | select(startswith("${{ inputs.docs-dir }}/"))' changed_files.json | wc -l)
68+
echo "doc_files_count=$DOC_FILES_COUNT" >> $GITHUB_OUTPUT
69+
70+
# Format changed files for comment
71+
FORMATTED_FILES=$(jq -r '.[] | select(startswith("${{ inputs.docs-dir }}/")) | "- `" + . + "`"' changed_files.json)
72+
echo "changed_files<<EOF" >> $GITHUB_OUTPUT
73+
echo "$FORMATTED_FILES" >> $GITHUB_OUTPUT
74+
echo "EOF" >> $GITHUB_OUTPUT
75+
76+
# Determine if docs have changed
77+
if [ "$DOC_FILES_COUNT" -gt 0 ]; then
78+
echo "has_changes=true" >> $GITHUB_OUTPUT
79+
else
80+
echo "has_changes=false" >> $GITHUB_OUTPUT
81+
fi
82+
83+
# Clean up sensitive file
84+
rm -f changed_files.json
85+
86+
- name: Generate Vercel preview URL
87+
id: vercel-preview
88+
if: steps.docs-analysis.outputs.has_changes == 'true'
89+
shell: bash
90+
run: |
91+
# Get PR number for Vercel preview URL using GitHub event file
92+
PR_NUMBER=$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
93+
94+
# Input validation - ensure PR number is a number
95+
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
96+
echo "::error::Invalid PR number: $PR_NUMBER"
97+
exit 1
98+
fi
99+
100+
# Generate and output Vercel preview URL with sanitized inputs
101+
VERCEL_DOMAIN="${{ inputs.vercel-domain }}"
102+
# Remove any dangerous characters from domain
103+
VERCEL_DOMAIN=$(echo "$VERCEL_DOMAIN" | tr -cd 'a-zA-Z0-9-.')
104+
105+
VERCEL_PREVIEW_URL="https://${VERCEL_DOMAIN}-${PR_NUMBER}.vercel.app"
106+
echo "url=$VERCEL_PREVIEW_URL" >> $GITHUB_OUTPUT
107+
108+
- name: Analyze manifest changes
109+
id: manifest-analysis
110+
if: inputs.manifest-changed == 'true'
111+
shell: bash
112+
run: |
113+
# Get PR number for links
114+
PR_NUMBER=$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
115+
116+
# Get the base SHA for diff
117+
BASE_SHA=$(git merge-base HEAD origin/main)
118+
119+
# Extract new docs from manifest.json diff with safe patterns
120+
NEW_DOCS=$(git diff "$BASE_SHA"..HEAD -- "${{ inputs.docs-dir }}/manifest.json" | grep -E '^\+.*"path":' | sed -E 's/.*"path": *"(.*)".*/\1/g')
121+
122+
if [ -n "$NEW_DOCS" ]; then
123+
echo "has_new_docs=true" >> $GITHUB_OUTPUT
124+
125+
# Format new docs for comment
126+
FORMATTED_NEW_DOCS=$(echo "$NEW_DOCS" | sort | uniq | grep -v "^$" | sed 's/^/- `/g' | sed 's/$/`/g')
127+
echo "new_docs<<EOF" >> $GITHUB_OUTPUT
128+
echo "$FORMATTED_NEW_DOCS" >> $GITHUB_OUTPUT
129+
echo "EOF" >> $GITHUB_OUTPUT
130+
131+
# Generate preview links for new docs
132+
PREVIEW_LINKS=""
133+
while IFS= read -r doc_path; do
134+
# Skip empty lines
135+
[ -z "$doc_path" ] && continue
136+
137+
# Clean the path and sanitize
138+
clean_path=${doc_path#./}
139+
clean_path=$(echo "$clean_path" | tr -cd 'a-zA-Z0-9_./-')
140+
141+
# Generate preview URL
142+
url_path=$(echo "$clean_path" | sed 's/\.md$//')
143+
VERCEL_DOMAIN="${{ inputs.vercel-domain }}"
144+
VERCEL_DOMAIN=$(echo "$VERCEL_DOMAIN" | tr -cd 'a-zA-Z0-9-.')
145+
preview_url="https://${VERCEL_DOMAIN}-${PR_NUMBER}.vercel.app/${url_path}"
146+
147+
# Extract doc title or use filename safely
148+
if [ -f "$doc_path" ]; then
149+
title=$(grep -m 1 "^# " "$doc_path" | sed 's/^# //')
150+
title=$(echo "$title" | tr -cd 'a-zA-Z0-9 _.,-')
151+
[ -z "$title" ] && title=$(basename "$doc_path" .md | tr -cd 'a-zA-Z0-9_.-')
152+
else
153+
title=$(basename "$doc_path" .md | tr -cd 'a-zA-Z0-9_.-')
154+
fi
155+
156+
PREVIEW_LINKS="${PREVIEW_LINKS}- [$title]($preview_url)\n"
157+
done <<< "$NEW_DOCS"
158+
159+
echo "preview_links<<EOF" >> $GITHUB_OUTPUT
160+
echo -e "$PREVIEW_LINKS" >> $GITHUB_OUTPUT
161+
echo "EOF" >> $GITHUB_OUTPUT
162+
else
163+
echo "has_new_docs=false" >> $GITHUB_OUTPUT
164+
fi

.github/workflows/docs-preview.yaml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Docs Preview
2+
on:
3+
pull_request:
4+
types: [opened, synchronize, reopened]
5+
paths:
6+
- 'docs/**'
7+
8+
permissions:
9+
contents: read
10+
pull-requests: write
11+
12+
jobs:
13+
preview:
14+
name: Generate docs preview
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Harden Runner
18+
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
19+
with:
20+
egress-policy: audit
21+
22+
- name: Checkout
23+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Get changed files
28+
id: changed-files
29+
uses: tj-actions/changed-files@2a398787e7b39c6ca11ce0843e5956d0b4165c80 # v43.0.0
30+
with:
31+
files: |
32+
docs/**
33+
34+
- name: Check if manifest changed
35+
id: manifest-check
36+
run: |
37+
echo "changed=${{ contains(steps.changed-files.outputs.all_changed_files, 'docs/manifest.json') }}" >> $GITHUB_OUTPUT
38+
39+
- name: Generate docs preview
40+
id: docs-preview
41+
uses: ./.github/actions/docs-preview
42+
with:
43+
github-token: ${{ secrets.GITHUB_TOKEN }}
44+
changed-files: ${{ steps.changed-files.outputs.all_changed_files_json }}
45+
manifest-changed: ${{ steps.manifest-check.outputs.changed }}
46+
47+
- name: Find existing comment
48+
if: steps.docs-preview.outputs.has_changes == 'true'
49+
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
50+
id: find-comment
51+
with:
52+
issue-number: ${{ github.event.pull_request.number }}
53+
comment-author: 'github-actions[bot]'
54+
body-includes: '## 📚 Docs Preview'
55+
56+
- name: Create or update preview comment
57+
if: steps.docs-preview.outputs.has_changes == 'true'
58+
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
59+
with:
60+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
61+
issue-number: ${{ github.event.pull_request.number }}
62+
body: |
63+
## 📚 Docs Preview
64+
65+
Your documentation changes are available for preview at:
66+
**🔗 [Vercel Preview](${{ steps.docs-preview.outputs.url }})**
67+
68+
### Changed Documentation Files
69+
${{ steps.docs-preview.outputs.changed_files }}
70+
71+
${{ steps.docs-preview.outputs.has_new_docs == 'true' && '### Newly Added Documentation' || '' }}
72+
${{ steps.docs-preview.outputs.has_new_docs == 'true' && steps.docs-preview.outputs.new_docs || '' }}
73+
74+
${{ steps.docs-preview.outputs.has_new_docs == 'true' && '### Preview Links for New Docs' || '' }}
75+
${{ steps.docs-preview.outputs.has_new_docs == 'true' && steps.docs-preview.outputs.preview_links || '' }}
76+
77+
---
78+
<sub>🤖 This comment is automatically generated and updated when documentation changes.</sub>
79+
edit-mode: replace
80+
reactions: eyes

0 commit comments

Comments
 (0)