name: Deploy to S3 on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "22" # setup-node installs Node but not Yarn. GitHub's hosted images happen to # ship Yarn preinstalled, so this workflow was silently depending on the # image rather than on anything declared here — and broke the moment the # act_runner image changed, with `yarn: command not found` (exit 127). # Pin to 1.x: the lockfile is v1 format and `--frozen-lockfile` is v1 # syntax (v2+ renamed it `--immutable`). - name: Install Yarn run: npm install -g yarn@1 - name: Install dependencies run: yarn install --frozen-lockfile - name: Build run: yarn build # `apt-get install awscli` failed with "no installation candidate" — the # package is only in Ubuntu's universe component, so whether it resolves # depends entirely on which image the runner happens to use. Install the # official v2 bundle instead: self-contained, no distro packaging, and # identical across images. The banner exists so the log identifies the # image, since the failures so far have all been image drift. - name: Install AWS CLI run: | echo "runner image: $( . /etc/os-release 2>/dev/null; echo "${PRETTY_NAME:-unknown}") $(uname -m)" if command -v aws >/dev/null 2>&1; then aws --version; exit 0; fi apt-get update -qq apt-get install -y -qq curl unzip >/dev/null curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip" -o /tmp/awscliv2.zip unzip -q /tmp/awscliv2.zip -d /tmp /tmp/aws/install --update aws --version - name: Deploy to S3 env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} run: | aws s3 sync _site/ s3://${{ vars.S3_BUCKET }} --delete # sync guesses text/markdown for .md, which Firefox downloads # instead of displaying; text/plain shows the raw text in the tab aws s3 cp _site/CLAUDE.md s3://${{ vars.S3_BUCKET }}/CLAUDE.md \ --content-type "text/plain; charset=utf-8" - name: Invalidate CloudFront if: vars.CF_DISTRIBUTION_ID != '' env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} run: | aws cloudfront create-invalidation \ --distribution-id ${{ vars.CF_DISTRIBUTION_ID }} \ --paths "/*"