Skip to content

Build Preview for "Repo sync" (#454) #619

Build Preview for "Repo sync" (#454)

Build Preview for "Repo sync" (#454) #619

name: Build Preview
run-name: 'Build Preview for "${{ github.event.pull_request.title }}" (#${{ github.event.pull_request.number }})'
on:
pull_request_target:
types: [opened, synchronize]
branches:
- main
- develop
# paths:
# Hello Security 👋, we are checking to make sure forked repo PR changed paths are only in content/** inside the job security-check.
# We are doing this so we can also reuse this workflow for internal PRs, as pull_request_target also triggers on internal PRs. (As does pull_request)
concurrency:
group: ${{ github.workflow }}-${{github.event_name}}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
pull-requests: write
contents: read # for embargoed content repos
jobs:
get-changed-files:
name: Get Changed Files
runs-on: ubuntu-latest
outputs:
changed_markdown_content_files: ${{ steps.changed-files.outputs.markdown_content_all_changed_files }}
changed_content_files_count: ${{ steps.changed-files.outputs.content_all_changed_files_count }}
not_content_bad_boy_naughty_files_count: ${{ steps.changed-files.outputs.not_content_bad_boy_naughty_all_changed_files_count }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Get changed files in the content/ subdirectories
id: changed-files
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8 # v45.0.7
with:
files_yaml: |
content:
- 'content/**'
markdown_content:
- 'content/**/*.mdx'
not_content_bad_boy_naughty:
- '!content/**'
base_sha: ${{ github.event.pull_request.base.sha }}
sha: ${{ github.event.pull_request.head.sha }}
security-check:
name: Security Check
runs-on: ubuntu-latest
needs: [get-changed-files]
steps:
- name: If in a forked repo fail if any changes are outside of content/**
run: |
: # Cases:
: # 1. PR from forked repo, changes outside of content/**; fail
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ] && [ ${{ needs.get-changed-files.outputs.not_content_bad_boy_naughty_files_count }} -gt 0 ]; then
echo "❌ This is a PR from a forked repo with changes outside of content/\*\*. **Please only edit files in the content/\*\* directory.**" >> $GITHUB_STEP_SUMMARY
exit 1
: # 2. PR from forked repo, changes only in content/**; pass
elif [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ] && [ ${{ needs.get-changed-files.outputs.not_content_bad_boy_naughty_files_count }} -eq 0 ]; then
echo "✅ This is a PR from a forked repo with NO changes outside of content/\*\*. Proceeding with the workflow." >> $GITHUB_STEP_SUMMARY
exit 0
fi
: # 3. PR from internal repo, changes outside of content/**; pass
: # 4. PR from internal repo, changes only in content/**; pass
echo "✅ This is an internal PR. Proceeding with the workflow." >> $GITHUB_STEP_SUMMARY
exit 0
deploy-unified-docs-api-preview:
name: Deploy Unified Docs API Preview
runs-on: ubuntu-latest
needs: [security-check]
outputs:
preview_url: ${{ steps.unified_docs_preview_url.outputs.preview_url }}
preview_url_to_fetch_deployment: ${{ steps.unified_docs_preview_url.outputs.preview_url_to_fetch_deployment }}
inspector_url: ${{ steps.unified_docs_inspector_url.outputs.inspector_url }}
created_utc: ${{ steps.unified_docs_preview_url.outputs.created_utc }}
steps:
- name: Initial comment on PR
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
with:
header: preview-notice
message: |
## Deploying Vercel Previews...
| Name | Status | Preview | Updated (UTC) |
| :--- | :----- | :------ | :------------ |
| Dev Portal | 🔄 Building ([Inspect](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})) | --- | --- |
| Unified Docs API | 🔄 Building ([Inspect](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})) | --- | --- |
- name: Checkout hashicorp/web-unified-docs
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Add commit link to summary
run: |
echo "[Built using commit $(echo ${{ github.event.pull_request.head.sha }} | cut -c -7)](https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }}/commits/${{ github.event.pull_request.head.sha }})" >> $GITHUB_STEP_SUMMARY
- name: Setup Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
cache: 'npm'
node-version-file: 'package.json'
- name: Use cache
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
with:
path: |
~/.npm
${{ github.workspace }}/.next/cache
# Generate a new cache whenever packages or source files change.
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.mjs', '**/*.ts', '**/*.tsx', '**/*.mdx', '**/*.json') }}
# If source files changed but packages didn't, rebuild from a prior cache.
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
- name: Install Vercel CLI
run: npm i --global vercel@latest
- name: Link web-unified-docs Vercel Project
run: vercel link --yes --project web-unified-docs --token=${{ secrets.VERCEL_TOKEN }}
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --target=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy Project Artifacts and Set GitHub Outputs
id: unified_docs_preview_url
# save preview url from deployment and save copy of the preview url w/o https to fetch the deployment via Vercel REST API in next step
run: |
preview_url=$(vercel deploy --prebuilt --target=preview --token=${{ secrets.VERCEL_TOKEN }} --archive=tgz)
echo "preview_url=$preview_url" >> $GITHUB_OUTPUT
created_utc=$(date -u)
echo "created_utc=$created_utc" >> $GITHUB_OUTPUT
preview_url_to_fetch_deployment=$(echo "$preview_url" | sed 's/^https:\/\///')
echo "preview_url_to_fetch_deployment=$preview_url_to_fetch_deployment" >> $GITHUB_OUTPUT
echo "deployment url is $preview_url"
echo "deployment url for REST API request is $preview_url_to_fetch_deployment"
echo "created at is $created_utc"
# as of March 2025, the Vercel CLI does not return the inspect URL in the output of the vercel deploy command, which is needed for the PR comment
# we need to fetch the deployment info via the Vercel REST API using the preview_url_to_fetch_deployment output from the last step and parse the inspect URL from it (inspectorUrl prop name)
- name: Vercel REST API Request to Fetch Inspect URL and Set GitHub Output
id: unified_docs_inspector_url
run: |
response=$(curl -sS -G "https://api.vercel.com/v13/deployments/${{ steps.unified_docs_preview_url.outputs.preview_url_to_fetch_deployment }}" \
-H "Authorization: Bearer ${{ secrets.VERCEL_TOKEN }}" \
-H "Content-Type: application/json" \
-d "teamId=${{ secrets.VERCEL_TEAM_ID }}")
inspector_url=$(echo "$response" | jq -r ".inspectorUrl")
echo "inspector_url=$inspector_url" >> $GITHUB_OUTPUT
echo "Inspect URL is $inspector_url"
- name: Update Comment with Unified Docs API Data
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
with:
header: preview-notice
message: |
## Vercel Previews Deployed
| Name | Status | Preview | Updated (UTC) |
| :--- | :--- | :--- | :--- |
| Dev Portal | 🔄 Building ([Inspect](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})) | --- | --- |
| Unified Docs API | ✅ Ready ([Inspect](${{ steps.unified_docs_inspector_url.outputs.inspector_url }} )) | [Visit Preview](${{ steps.unified_docs_preview_url.outputs.preview_url }}) | ${{ steps.unified_docs_preview_url.outputs.created_utc }} |
deploy-dev-portal-preview:
name: Deploy Dev Portal Preview
runs-on: ubuntu-latest
needs: [deploy-unified-docs-api-preview]
outputs:
preview_url: ${{ steps.deploy_dev_portal_preview.outputs.preview_url }}
steps:
- name: Checkout hashicorp/dev-portal (Frontend)
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
with:
repository: hashicorp/dev-portal
path: ./unified-docs-frontend-preview
- name: Use cache
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
with:
path: |
~/.npm
${{ github.workspace }}/unified-docs-frontend-preview/.next/cache
# Generate a new cache whenever packages or source files change.
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx', '**/*.mdx') }}
# If source files changed but packages didn't, rebuild from a prior cache.
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
- name: Setup Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
cache: 'npm'
cache-dependency-path: 'unified-docs-frontend-preview/package-lock.json'
node-version-file: 'unified-docs-frontend-preview/package.json'
- name: Setup Vercel CLI
run: npm i --global vercel@latest
- run: vercel pull --yes --environment=preview --scope=hashicorp --token=${{ secrets.VERCEL_TOKEN }}
working-directory: unified-docs-frontend-preview
- name: inject env vars
run: |
cd unified-docs-frontend-preview
echo "HASHI_ENV=unified-docs-sandbox" >> .env
echo "UNIFIED_DOCS_API=${{ needs.deploy-unified-docs-api-preview.outputs.preview_url }}" >> .env
echo "VERCEL_AUTOMATION_BYPASS_SECRET=${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}" >> .env
- name: Build dev-portal
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
env:
# Used to read docs from private repos, once all docs are in UDR we can remove this
GITHUB_TOKEN: ${{ secrets.CI_GITHUB_TOKEN }}
with:
shell: bash
timeout_minutes: 10
max_attempts: 2
command: |
cd unified-docs-frontend-preview
vercel build --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy Project Artifacts and Set GitHub Outputs
id: deploy_dev_portal_preview
run: |
preview_url=$(vercel deploy --prebuilt --archive=tgz --scope=hashicorp --token=${{ secrets.VERCEL_TOKEN }})
echo "preview_url=$preview_url" >> $GITHUB_OUTPUT
created_utc=$(date -u)
echo "created_utc=$created_utc" >> $GITHUB_OUTPUT
preview_url_to_fetch_deployment=$(echo "$preview_url" | sed 's/^https:\/\///')
echo "preview_url_to_fetch_deployment=$preview_url_to_fetch_deployment" >> $GITHUB_OUTPUT
echo "deployment url is $preview_url"
echo "deployment url for REST API request is $preview_url_to_fetch_deployment"
echo "created at is $created_utc"
working-directory: unified-docs-frontend-preview
# as of March 2025, the Vercel CLI does not return the inspect URL in the output of the vercel deploy command, which is needed for the PR comment
# we need to fetch the deployment info via the Vercel REST API using the preview_url_to_fetch_deployment output from the last step and parse the inspect URL from it (inspectorUrl prop name)
- name: Vercel REST API Request to Fetch Inspect URL and Set GitHub Output
id: dev_portal_inspector_url
run: |
response=$(curl -sS -G "https://api.vercel.com/v13/deployments/${{ steps.deploy_dev_portal_preview.outputs.preview_url_to_fetch_deployment }}" \
-H "Authorization: Bearer ${{ secrets.VERCEL_TOKEN }}" \
-H "Content-Type: application/json" \
-d "teamId=${{ secrets.VERCEL_TEAM_ID }}")
inspector_url=$(echo "$response" | jq -r ".inspectorUrl")
echo "inspector_url=$inspector_url" >> $GITHUB_OUTPUT
echo "Inspect URL is $inspector_url"
- name: Update PR Comment with Dev Portal Data
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
with:
header: preview-notice
message: |
## Vercel Previews Deployed
| Name | Status | Preview | Updated (UTC) |
| :--- | :--- | :--- | :--- |
| Dev Portal | ✅ Ready ([Inspect](${{ steps.dev_portal_inspector_url.outputs.inspector_url }})) | [Visit Preview](${{ steps.deploy_dev_portal_preview.outputs.preview_url }}) | ${{ steps.deploy_dev_portal_preview.outputs.created_utc }} |
| Unified Docs API | ✅ Ready ([Inspect](${{ needs.deploy-unified-docs-api-preview.outputs.inspector_url }} )) | [Visit Preview](${{ needs.deploy-unified-docs-api-preview.outputs.preview_url }}) | ${{ needs.deploy-unified-docs-api-preview.outputs.created_utc }} |
check-links:
name: Run Link Checker
needs: [get-changed-files, deploy-dev-portal-preview]
if: needs.get-changed-files.outputs.changed_content_files_count > 0
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checking links in files
run: |
echo "Checking links in files:"
echo "${{ needs.get-changed-files.outputs.changed_markdown_content_files }}" | tr ' ' '\n'
- name: Run lychee link checker
id: lychee
uses: lycheeverse/lychee-action@f613c4a64e50d792e0b31ec34bbcbba12263c6a6 # v2.3.0
with:
args: >-
${{ needs.get-changed-files.outputs.changed_markdown_content_files }}
-b ${{ needs.deploy-dev-portal-preview.outputs.preview_url }}
--exclude-all-private
--exclude '\.(svg|gif|jpg|png)'
--exclude 'gnu\.org'
--accept 200,408,429
--timeout=60
--max-concurrency 24
--no-progress
--verbose
--header x-vercel-protection-bypass=${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}
fail: false
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Print lychee exit code
run: |
echo "Lychee exit code:"
echo ${{ steps.lychee.outputs.exit_code }}
- name: Add Broken Link Checker header to lychee output
if: steps.lychee.outputs.exit_code != 0
run: |
sed -i '1s/^/## Broken Link Checker\n/' ./lychee/out.md
# Get length of lychee output
- name: lychee output size check
id: char-count
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
if: steps.lychee.outputs.exit_code != 0
with:
script: |
const size = require('fs').readFileSync('./lychee/out.md').length;
console.log(`${size} characters`);
core.setOutput('size', size);
# If the char count of the lychee report is too long, it's going to break
# the sticky-pull-request-comment action because of a body size limitation
# on the GitHub PR comment API. So, instead, upload the full report to GH
# artifacts and just link to that instead
- name: Upload lychee report to GitHub artifacts
id: upload-artifact
if: steps.lychee.outputs.exit_code != 0 && fromJson(steps.char-count.outputs.size) >= fromJson(vars.BROKEN_LINK_REPORT_CHAR_MAX)
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # 4.6.2
with:
path: ./lychee/out.md
name: Link Checker Report
- name: Comment on PR with link to full link checker report
if: steps.lychee.outputs.exit_code != 0 && fromJson(steps.char-count.outputs.size) >= fromJson(vars.BROKEN_LINK_REPORT_CHAR_MAX)
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
with:
header: Link Checker Report
message: |
## Broken Link Checker
Report exceeds max length of ${{vars.BROKEN_LINK_REPORT_CHAR_MAX}} characters, so it cannot be displayed in GitHub comments. [Download full report.](${{steps.upload-artifact.outputs.artifact-url}})
- name: Comment on PR with link checker report
if: steps.lychee.outputs.exit_code != 0 && fromJson(steps.char-count.outputs.size) < fromJson(vars.BROKEN_LINK_REPORT_CHAR_MAX)
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
with:
header: Link Checker Report
path: ./lychee/out.md
# Fail github action if lychee exit code is anything other than the success code (0)
- name: lychee exit code check
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
if: steps.lychee.outputs.exit_code != 0
with:
script: |
core.setFailed('lychee failed with exit code ${{steps.lychee.outputs.exit_code}}')
# If all previous Github actions run (indicating success), this one will run and overwrite the comment with a success message
- name: Comment on PR about successful link check
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
with:
header: Link Checker Report
message: |
## Broken Link Checker
No broken links found! 🎉
# Delete the Link Checker PR comment if no files have changed
skip-check-links:
name: Skip Link Checker
needs: [get-changed-files, deploy-dev-portal-preview]
if: needs.get-changed-files.outputs.changed_content_files_count == 0
runs-on: ubuntu-latest
steps:
- name: Update PR comment
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
with:
header: Link Checker Report
delete: true