1+ name : Build and deploy Docusaurus site to Azure Blob Storage
2+
3+ on :
4+ push :
5+ branches :
6+ - main
7+ - dev
8+ workflow_dispatch :
9+ inputs :
10+ environment :
11+ description : ' Environment to deploy to'
12+ required : true
13+ default : ' development'
14+ type : choice
15+ options :
16+ - development
17+ - production
18+
19+ jobs :
20+ determine-environment :
21+ runs-on : ubuntu-latest
22+ outputs :
23+ environment : ${{ steps.set-env.outputs.environment }}
24+ steps :
25+ - name : Determine environment
26+ id : set-env
27+ run : |
28+ if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
29+ echo "environment=${{ github.event.inputs.environment }}" >> $GITHUB_OUTPUT
30+ elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
31+ echo "environment=production" >> $GITHUB_OUTPUT
32+ else
33+ echo "environment=development" >> $GITHUB_OUTPUT
34+ fi
35+
36+ build :
37+ runs-on : self-hosted
38+ needs : determine-environment
39+ environment : ${{ needs.determine-environment.outputs.environment }}
40+ permissions :
41+ contents : read
42+
43+ steps :
44+ - name : Check out source code
45+ uses : actions/checkout@v4
46+
47+ - name : Set up Node.js
48+ uses : actions/setup-node@v3
49+ with :
50+ node-version : ' 22.x'
51+
52+ - name : Cache Node.js dependencies
53+ uses : actions/cache@v3
54+ with :
55+ path : ~/.npm
56+ key : ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
57+ restore-keys : |
58+ ${{ runner.os }}-node-
59+
60+ - name : Cache Docusaurus build
61+ uses : actions/cache@v3
62+ id : cache-build
63+ with :
64+ path : |
65+ .docusaurus
66+ build
67+ key : ${{ runner.os }}-docusaurus-build-${{ hashFiles('src/**', 'docs/**', 'blog/**', 'docusaurus.config.js', 'sidebars.js', 'package-lock.json') }}
68+ restore-keys : |
69+ ${{ runner.os }}-docusaurus-build-
70+
71+ - name : Cache webpack
72+ uses : actions/cache@v3
73+ with :
74+ path : node_modules/.cache
75+ key : ${{ runner.os }}-webpack-${{ hashFiles('**/package-lock.json') }}
76+ restore-keys : |
77+ ${{ runner.os }}-webpack-
78+
79+ - name : Install dependencies and build site
80+ run : |
81+ npm ci
82+
83+ # Check if we have a valid cached build
84+ if [[ "${{ steps.cache-build.outputs.cache-hit }}" == "true" ]]; then
85+ echo "Build cache found, checking if rebuild needed..."
86+ # Docusaurus will intelligently rebuild only what's changed
87+ else
88+ echo "No build cache found, performing full build..."
89+ fi
90+
91+ # Run build - Docusaurus will use its internal caching
92+ npm run build
93+ env :
94+ NODE_OPTIONS : " --max-old-space-size=16384"
95+ DOCUSAURUS_URL : " https://${{ secrets.STORAGE_ACCOUNT_NAME }}.z13.web.core.windows.net"
96+ # Add any other environment-specific build variables here
97+ NODE_ENV : ${{ needs.determine-environment.outputs.environment }}
98+
99+ - name : Upload artifact for deployment
100+ uses : actions/upload-artifact@v4
101+ with :
102+ name : build-output
103+ path : build/
104+
105+ deploy :
106+ runs-on : ubuntu-latest
107+ needs : [build, determine-environment]
108+ environment : ${{ needs.determine-environment.outputs.environment }}
109+
110+ steps :
111+ - name : Download build artifact
112+ uses : actions/download-artifact@v4
113+ with :
114+ name : build-output
115+ path : build/
116+
117+ - name : Install azcopy
118+ run : |
119+ # Download and install azcopy for faster uploads
120+ wget -O azcopy.tar.gz https://aka.ms/downloadazcopy-v10-linux
121+ tar -xf azcopy.tar.gz --strip-components=1
122+ sudo mv azcopy /usr/local/bin/
123+ azcopy --version
124+
125+ - name : Upload to Azure Blob Storage with AzCopy and comprehensive MIME types
126+ run : |
127+ echo "Deploying to ${{ needs.determine-environment.outputs.environment }} environment"
128+ echo "Starting high-performance sync of changed files with proper MIME types..."
129+
130+ # Create SAS token for azcopy (more secure than using key directly)
131+ end_date=$(date -u -d "30 minutes" '+%Y-%m-%dT%H:%MZ')
132+ sas_token=$(az storage container generate-sas \
133+ --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} \
134+ --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} \
135+ --name '$web' \
136+ --permissions dlrw \
137+ --expiry $end_date \
138+ --output tsv)
139+
140+ # Create comprehensive content type mapping file for azcopy
141+ cat > content-type-map.json << EOF
142+ {
143+ "*.css": "text/css",
144+ "*.js": "application/javascript",
145+ "*.mjs": "application/javascript",
146+ "*.json": "application/json",
147+ "*.html": "text/html",
148+ "*.htm": "text/html",
149+ "*.xml": "application/xml",
150+ "*.txt": "text/plain",
151+ "*.md": "text/markdown",
152+
153+ "*.png": "image/png",
154+ "*.jpg": "image/jpeg",
155+ "*.jpeg": "image/jpeg",
156+ "*.gif": "image/gif",
157+ "*.webp": "image/webp",
158+ "*.avif": "image/avif",
159+ "*.svg": "image/svg+xml",
160+ "*.bmp": "image/bmp",
161+ "*.tiff": "image/tiff",
162+ "*.ico": "image/x-icon",
163+
164+ "*.woff": "font/woff",
165+ "*.woff2": "font/woff2",
166+ "*.ttf": "font/ttf",
167+ "*.otf": "font/otf",
168+ "*.eot": "application/vnd.ms-fontobject",
169+
170+ "*.pdf": "application/pdf",
171+ "*.doc": "application/msword",
172+ "*.docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
173+ "*.xls": "application/vnd.ms-excel",
174+ "*.xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
175+ "*.ppt": "application/vnd.ms-powerpoint",
176+ "*.pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
177+ "*.odt": "application/vnd.oasis.opendocument.text",
178+ "*.ods": "application/vnd.oasis.opendocument.spreadsheet",
179+ "*.odp": "application/vnd.oasis.opendocument.presentation",
180+
181+ "*.zip": "application/zip",
182+ "*.rar": "application/vnd.rar",
183+ "*.7z": "application/x-7z-compressed",
184+ "*.tar": "application/x-tar",
185+ "*.gz": "application/gzip",
186+ "*.bz2": "application/x-bzip2",
187+
188+ "*.mp4": "video/mp4",
189+ "*.webm": "video/webm",
190+ "*.avi": "video/x-msvideo",
191+ "*.mov": "video/quicktime",
192+ "*.wmv": "video/x-ms-wmv",
193+
194+ "*.mp3": "audio/mpeg",
195+ "*.wav": "audio/wav",
196+ "*.ogg": "audio/ogg",
197+ "*.m4a": "audio/mp4",
198+
199+ "*.csv": "text/csv",
200+ "*.rtf": "application/rtf",
201+ "*.epub": "application/epub+zip",
202+ "*.mobi": "application/x-mobipocket-ebook"
203+ }
204+ EOF
205+
206+ # Use azcopy sync with comprehensive content type mapping
207+ azcopy sync "./build/" \
208+ "https://${{ secrets.STORAGE_ACCOUNT_NAME }}.blob.core.windows.net/\$web?$sas_token" \
209+ --delete-destination=true \
210+ --compare-hash=MD5 \
211+ --log-level=INFO \
212+ --cap-mbps=0 \
213+ --block-size-mb=4 \
214+ --content-type-map="content-type-map.json"
215+
216+ echo "Sync completed with comprehensive MIME types!"
217+
218+ - name : Fallback MIME type setting for critical files
219+ run : |
220+ echo "Setting MIME types for critical files as fallback (in case azcopy mapping failed)..."
221+
222+ # Install Azure CLI if not available
223+ if ! command -v az &> /dev/null; then
224+ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
225+ fi
226+
227+ # Set MIME types for most critical files (CSS and JS) that affect styling
228+ echo "Ensuring CSS files have correct MIME type..."
229+ az storage blob update-batch \
230+ --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} \
231+ --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} \
232+ --source '$web' \
233+ --pattern "*.css" \
234+ --content-type "text/css" \
235+ --if-unmodified-since "1970-01-01T00:00:00Z" \
236+ --no-progress || echo "CSS MIME type update completed (some files may have been skipped)"
237+
238+ echo "Ensuring JS files have correct MIME type..."
239+ az storage blob update-batch \
240+ --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }} \
241+ --account-key ${{ secrets.STORAGE_ACCOUNT_KEY }} \
242+ --source '$web' \
243+ --pattern "*.js" \
244+ --content-type "application/javascript" \
245+ --if-unmodified-since "1970-01-01T00:00:00Z" \
246+ --no-progress || echo "JS MIME type update completed (some files may have been skipped)"
247+
248+ echo "Critical MIME types verified!"
249+
250+ - name : Purge CDN endpoint (if configured)
251+ run : |
252+ if [[ -n "${{ secrets.CDN_ENDPOINT_NAME }}" ]] && [[ -n "${{ secrets.CDN_PROFILE_NAME }}" ]] && [[ -n "${{ secrets.CDN_RESOURCE_GROUP }}" ]]; then
253+ echo "Note: CDN purge requires Azure login. Skipping CDN purge when using storage key authentication."
254+ echo "To use CDN purge, you'll need to use Azure AD authentication or purge CDN manually."
255+ else
256+ echo "CDN configuration not found, skipping CDN purge."
257+ fi
258+
259+ - name : Display deployment URL
260+ run : |
261+ echo "🚀 Deployment complete!"
262+ echo "Environment: ${{ needs.determine-environment.outputs.environment }}"
263+ echo "URL: https://${{ secrets.STORAGE_ACCOUNT_NAME }}.z13.web.core.windows.net"
264+ if [[ -n "${{ secrets.CUSTOM_DOMAIN }}" ]]; then
265+ echo "Custom Domain: ${{ secrets.CUSTOM_DOMAIN }}"
266+ fi
267+ echo "All files deployed with proper MIME types for optimal browser compatibility!"
0 commit comments