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
0 commit comments