Skip to content

Build a working show/hide app+phone demo video player #418

Build a working show/hide app+phone demo video player

Build a working show/hide app+phone demo video player #418

Workflow file for this run

name: CI
on: [push, workflow_dispatch]
jobs:
build:
name: Build & test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.11.1
cache: 'npm'
# Install & build & test:
- run: npm ci
# Build without secrets for previews, in non-push cases:
- name: Build for preview
if: github.event_name != 'push'
run: npm run build
env:
NODE_ENV: development
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Build with secrets for production, on push only:
- name: Build for production
if: github.event_name == 'push'
run: npm run build
env:
NODE_ENV: production
NEXT_PUBLIC_POSTHOG_KEY: ${{ vars.POSTHOG_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v4
with:
name: out
path: out/*
if-no-files-found: error
- uses: actions/upload-artifact@v4
with:
name: rss
path: out/rss.xml
if-no-files-found: error
check-blog-changes:
name: Check for new blog posts to announce
if: false
# TODO: Put back to `github.event_name == 'push' && github.ref == 'refs/heads/main'` after
# the big site switchover is done, with some careful testing
runs-on: ubuntu-latest
needs: build
outputs:
new-blog-post: ${{ steps.detect-changes.outputs.new-blog-post }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: rss
path: local-rss
- id: detect-changes
name: 'Check for RSS differences'
shell: bash
run: |
curl -f https://httptoolkit.com/rss.xml > remote-rss.xml
sudo apt-get update && sudo apt-get install xmlstarlet
LOCAL_POSTS=$(xmlstarlet sel -t -v '//rss/channel/item/link' local-rss/rss.xml)
REMOTE_POSTS=$(xmlstarlet sel -t -v '//rss/channel/item/link' remote-rss.xml)
# Matches remote posts against each local post, excludes those matches,
# and returns the remaining lines (or nothing, if there are none):
NEW_POSTS=$(grep -vFxf <(echo "$REMOTE_POSTS") <(echo "$LOCAL_POSTS") || true)
if [[ $(echo "$NEW_POSTS" | wc -l) -gt 1 ]]; then
echo "More than one new post found - something odd is happening, failing the job"
exit 1
fi
# Grab the slug (the last path chunk) from each URL:
NEW_POST_SLUGS=$(echo $NEW_POSTS | sed -E 's|.*/([^/]+)/?$|\1|')
# Ensure the output is exactly an empty string, if not a post (trim newlines etc):
if [[ ! -z "$(echo "$NEW_POST_SLUGS" | tr -d '\n')" ]]; then
echo "New blog post: $NEW_POST_SLUGS"
echo "new-blog-post=$(echo $NEW_POST_SLUGS)" >> "$GITHUB_OUTPUT"
else
echo "No new blog posts"
echo "new-blog-post=" >> "$GITHUB_OUTPUT"
fi
publish-docker:
name: Build & publish container to Docker Hub
if: github.event_name == 'push' && !startsWith(github.ref, 'refs/heads/dependabot/')
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: out
path: out
- uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
images: httptoolkit/website
tags: |
type=raw,value=prod,enable=${{ github.ref == 'refs/heads/main' }}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
type=raw,value=staging,enable=${{ github.ref == 'refs/heads/next' }}
type=sha
- name: Publish to Docker Hub
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
publish-scaleway:
name: Deploy to Scaleway
environment: ${{ github.ref == 'refs/heads/main' && 'production' || github.ref == 'refs/heads/next' && 'staging' || 'no-environment-deploy-skipped' }}
runs-on: ubuntu-latest
needs: publish-docker
steps:
- name: Redeploy container
uses: httptoolkit/deploy-scaleway-serverless-container-action@v1
with:
container_id: ${{ vars.SCW_API_CONTAINER_ID }}
region: ${{ vars.SCW_API_CONTAINER_REGION }}
secret_key: ${{ secrets.SCW_SECRET_KEY }}
registry_image_url: "registry.hub.docker.com/httptoolkit/website:${{ vars.DOCKER_IMAGE_TAG }}"
- name: Redeploy failover container
uses: httptoolkit/deploy-scaleway-serverless-container-action@v1
if: ${{ vars.SCW_FAILOVER_API_CONTAINER_ID }}
with:
container_id: ${{ vars.SCW_FAILOVER_API_CONTAINER_ID }}
region: ${{ vars.SCW_FAILOVER_API_CONTAINER_REGION }}
secret_key: ${{ secrets.SCW_SECRET_KEY }}
registry_image_url: "registry.hub.docker.com/httptoolkit/website:${{ vars.DOCKER_IMAGE_TAG }}"
- name: Flush CDN cache
if: ${{ vars.BUNNY_PULL_ZONE_ID }}
run: |
# Clear CDN cache to re-request content:
curl -f --request POST \
--url https://api.bunny.net/pullzone/$PULL_ZONE_ID/purgeCache \
--header "AccessKey: $BUNNY_SITE_API_KEY"
env:
PULL_ZONE_ID: ${{ vars.BUNNY_PULL_ZONE_ID }}
BUNNY_SITE_API_KEY: ${{ secrets.BUNNY_SITE_API_KEY }}
announce-blog-changes:
name: Announce new blog posts
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.check-blog-changes.outputs.new-blog-post != ''
runs-on: ubuntu-latest
needs:
- check-blog-changes
- publish-scaleway
steps:
- uses: actions/checkout@v4
- name: Send an email about the new blog post with Mailcoach
run: |
SLUG="${{ needs.check-blog-changes.outputs.new-blog-post }}"
URL="https://httptoolkit.com/blog/$SLUG/"
MARKDOWN=$(cat "src/posts/$SLUG.md")
FRONTMATTER=$(echo "$MARKDOWN" | sed -n '/^---$/,/^---$/p')
# Get the title - stripping any surrounding quotes if required
TITLE=$(echo "$FRONTMATTER" |
sed -n 's/^title: //p' |
sed 's/^"//; s/"$//' |
sed "s/^'//; s/'$//"
)
# Get the post content, stripping out frontmatter:
CONTENT=$(echo "$MARKDOWN" | sed '0,/^---$/d; 0,/^---$/d')
API_ENDPOINT="https://http-toolkit.mailcoach.app/api/campaigns"
# Create a Mailcoach campaign for this blog post email, scheduled to send
# in 3 hours from now:
CAMPAIGN_ID=$(
curl \
-f -X POST $API_ENDPOINT \
-H "Authorization: Bearer $MAILCOACH_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"name\": \"Blog post: $TITLE\",
\"subject\": \"$TITLE\",
\"schedule_at\":\"$(date -u -d "3 hours" +"%Y-%m-%d %H:%M:%S")\",
\"email_list_uuid\": \"$MAILING_LIST_UUID\",
\"template_uuid\": \"$EMAIL_TEMPLATE_ID\",
\"fields\": {
\"url\": \"$URL\",
\"title\": \"$TITLE\",
\"content\": $(echo "$CONTENT" | jq -R -r -s @json)
}
}" \
| jq -r .data.uuid
)
# Send a test email with this content immediately:
curl -f -X POST "$API_ENDPOINT/$CAMPAIGN_ID/send-test" \
-H "Authorization: Bearer $MAILCOACH_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"email":"'$TEST_EMAIL'"}'
env:
MAILCOACH_TOKEN: ${{ secrets.MAILCOACH_TOKEN }}
EMAIL_TEMPLATE_ID: ${{ vars.BLOG_POST_EMAIL_TEMPLATE_ID }}
MAILING_LIST_UUID: ${{ vars.BLOG_POST_MAILING_LIST_UUID }}
TEST_EMAIL: ${{ vars.BLOG_POST_TEST_EMAIL }}