Skip to content

Commit

Permalink
feat(spotlight): Add self-contained spotlight binary creation (#559)
Browse files Browse the repository at this point in the history
This PR adds a new release type which is a self-contained CLI akin to
running `npx @spotlightjs/spotlight` but without any `node` or `npx`
or any other requirements on the system.

It also changes how we serve the static assets: instead of serving the
entire folder, which can be dangerous as it allows access to arbitrary
files, we now use the `manifest.json` generated when compiling it and
only serve files listed there, directly from memory. This should also
increase the performance.
  • Loading branch information
BYK authored Nov 25, 2024
1 parent 00fd0d0 commit 5c0b162
Show file tree
Hide file tree
Showing 14 changed files with 417 additions and 105 deletions.
7 changes: 7 additions & 0 deletions .changeset/violet-trees-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@spotlightjs/spotlight': minor
'@spotlightjs/sidecar': minor
---

Create a self-contained executable for Linux, macOS, and Windows for Spotlight.
Docker images now use these binaries instead of a Node build in the image.
61 changes: 37 additions & 24 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,17 @@ jobs:
runs-on: ubuntu-latest
# For whatever reason, yaml does not like the full "meta(changelog): Update package versions" string
# So we check this in two parts
if: |
(contains(github.event.head_commit.message, 'meta(changelog)')
&& contains(github.event.head_commit.message, 'Update package versions'))
|| inputs.npm
if: >-
(
contains(github.event.head_commit.message, 'meta(changelog)')
&&
contains(github.event.head_commit.message, 'Update package versions')
) || inputs.npm
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Node
uses: actions/setup-node@v4
Expand All @@ -57,6 +61,28 @@ jobs:
publish: pnpm changeset:publish
createGithubReleases: true

- name: Store standalone spotlight binary
uses: actions/upload-artifact@v4
with:
name: spotlight
if-no-files-found: error
path: packages/spotlight/dist/spotlight-*

- name: Gets latest created release info
id: latest_release_info
uses: gregziegan/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file_glob: true
file: packages/spotlight/dist/spotlight-*
tag: ${{ steps.latest_release_info.outputs.tag_name }}
make_latest: false

docker:
name: Docker Image
needs: npm
Expand All @@ -66,31 +92,20 @@ jobs:
&& (inputs.docker || github.event_name == 'push')
&& (needs.npm.result == 'success' || needs.npm.result == 'skipped')
steps:
- name: Checkout Repo
uses: actions/checkout@v4

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- uses: docker/setup-qemu-action@v3

- uses: docker/setup-buildx-action@v3

- name: Build and Push Docker Image
uses: docker/build-push-action@v5
with:
context: .
cache-from: type=gha,scope=prod
no-cache: ${{ inputs.nocache == true }}
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/getsentry/spotlight:latest
ghcr.io/getsentry/spotlight:${{ github.sha }}
- name: Push Docker Image as latest
run: >-
docker buildx imagetools create
--tag ghcr.io/getsentry/spotlight:latest
ghcr.io/getsentry/spotlight:${{ github.sha }}
- name: Summarize
run: |
Expand All @@ -104,14 +119,12 @@ jobs:
!cancelled()
&& (inputs.electron || github.event_name == 'push')
&& (needs.npm.result == 'success' || needs.npm.result == 'skipped')
# strategy:
# fail-fast: false
# matrix:
# platform: [x64, arm64]
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Node
uses: actions/setup-node@v4
Expand Down
95 changes: 76 additions & 19 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ on:
branches: [main]
pull_request:

defaults:
run:
shell: bash


env:
BUILD_CACHE_KEY: ${{ github.event.inputs.commit || github.sha }}
CACHED_BUILD_PATHS: |
Expand All @@ -29,47 +34,96 @@ jobs:
node-version-file: 'package.json'
cache: 'pnpm'

- name: Setup dependencies
- name: Setup NPM dependencies
run: pnpm install

- name: Setup Codesign Dependencies
env:
APPLE_CERT_DATA: ${{ secrets.CSC_LINK }}
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
run: |
curl -L 'https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.28.0/apple-codesign-0.28.0-x86_64-unknown-linux-musl.tar.gz' | tar -xz --strip-components=1
mv rcodesign /usr/local/bin/rcodesign
# Export certs
echo "$APPLE_CERT_DATA" | base64 --decode > /tmp/certs.p12
echo 'APPLE_CERT_PATH=/tmp/certs.p12' >> $GITHUB_ENV
echo "$APPLE_API_KEY" | base64 -d > /tmp/apple_key.json
echo 'APPLE_API_KEY_PATH=/tmp/apple_key.json' >> $GITHUB_ENV
- name: Build packages
env:
BUILD_PLATFORMS: 'linux-x64,linux-arm64,win-x64,darwin-x64,darwin-arm64'
APPLE_CERT_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.TEAMID }}
run: pnpm build

- name: Smoke test
env:
SPOTLIGHT_BINARY: ${{ github.workspace }}/packages/spotlight/dist/spotlight-${{ runner.os }}-${{ runner.arch }}
run: |
# Lowercase the binary name because `runner.os` and `runner.arch` are uppercase :facepalm:
SPOTLIGHT_BINARY=$(echo "$SPOTLIGHT_BINARY" | tr '[:upper:]' '[:lower:]')
[ -f "$SPOTLIGHT_BINARY" ]
$SPOTLIGHT_BINARY &
SPOTLIGHT_PID=$!
curl -sf --retry 3 --retry-all-errors -o /dev/null 'http://localhost:8969/' && echo "Spotlight ran successfully"
kill -2 $SPOTLIGHT_PID
- name: Store Spotlight CJS
uses: actions/upload-artifact@v4
with:
name: spotlight-cjs
if-no-files-found: error
path: |
packages/spotlight/dist/spotlight.cjs
packages/spotlight/dist/overlay/
- name: Store standalone spotlight binary
uses: actions/upload-artifact@v4
with:
name: spotlight
if-no-files-found: error
path: packages/spotlight/dist/spotlight-*

- name: Update build cache
uses: actions/cache@v4
with:
path: ${{ env.CACHED_BUILD_PATHS }}
key: ${{ env.BUILD_CACHE_KEY }}

test-docker:
name: Docker Test
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Rename x64 to amd64
# This is because Node ecosystem uses x64, but Docker uses amd64 :shrug:
run: mv packages/spotlight/dist/spotlight-linux-x64 packages/spotlight/dist/spotlight-linux-amd64

- name: Get changed files
id: changed-files-yaml
uses: tj-actions/changed-files@v41
- name: Login to GHCR
uses: docker/login-action@v3
with:
files_yaml: |
docker:
- Dockerfile
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Setup QEMU for cross-compilation
uses: docker/setup-qemu-action@v3

- name: Configure Docker Context
if: ${{ inputs.force || steps.changed-files-yaml.outputs.docker_any_changed == 'true' }}
uses: docker/setup-buildx-action@v3

- name: Build Docker Image
if: ${{ inputs.force || steps.changed-files-yaml.outputs.docker_any_changed == 'true' }}
uses: docker/build-push-action@v5
with:
context: .
cache-from: type=gha,scope=prod
cache-to: type=gha,mode=max,scope=prod
no-cache: ${{ inputs.nocache == 'true' }}
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/getsentry/spotlight:${{ github.sha }}

- name: Test Docker Image
run: |
docker run --rm -d -p 8969:8969 ghcr.io/getsentry/spotlight:${{ github.sha }}
curl -sf --retry 3 --retry-all-errors -o /dev/null 'http://localhost:8969/' && echo "Spotlight ran successfully"
test-unit:
name: Unit Tests
Expand Down Expand Up @@ -111,14 +165,17 @@ jobs:
report_paths: '**/junit.xml'

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

test-e2e:
name: E2E Tests
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
node_version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -130,7 +187,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version-file: 'package.json'
node-version: ${{ matrix.version }}
cache: 'pnpm'

- name: Setup dependencies
Expand Down
10 changes: 9 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
{
"editor.formatOnSave": true,
"cSpell.words": [
"APPLEID",
"APPLEIDPASS",
"Astro",
"Astro's",
"astrojs",
"codesign",
"contextlines",
"Endcaps",
"fontsource",
"getsentry",
"iife",
"nextjs",
"notarytool",
"outro",
"pageload",
"postject",
"spotlightjs",
"svgr",
"tailwindcss",
"TEAMID",
"treeshake",
"ttfb",
"unsign",
"uuidv",
"webvitals"
"webvitals",
"xcrun"
]
}
24 changes: 4 additions & 20 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
FROM node:lts-bullseye-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable

FROM base AS build
FROM debian:bookworm-slim
ARG TARGETARCH
WORKDIR /app
COPY . /app
# https://github.com/pnpm/pnpm/issues/6295
RUN echo "dedupe-peer-dependents=false" > .npmrc
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run --filter="./packages/sidecar" build && \
pnpm run --filter="./packages/overlay" build
RUN pnpm run --filter="./packages/spotlight" build
RUN pnpm deploy --filter="./packages/spotlight" --prod /deploy/spotlight
COPY --chmod=555 packages/spotlight/dist/spotlight-linux-$TARGETARCH /app/spotlight

FROM base as spotlight
# FROM gcr.io/distroless/nodejs20-debian12 as sidecar
COPY --from=build /deploy/spotlight /app
WORKDIR /app
EXPOSE 8969
ENTRYPOINT [ "./bin/run.js" ]
ENTRYPOINT ["/app/spotlight"]
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
},
"packageManager": "[email protected]",
"volta": {
"node": "20.10.0",
"node": "22.11.0",
"pnpm": "9.13.0"
}
}
Loading

0 comments on commit 5c0b162

Please sign in to comment.