diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..3c0186f --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,74 @@ +name: Build +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + generate-matrix: + runs-on: ubuntu-latest + outputs: + apps: ${{ steps.set-matrix.outputs.apps }} + steps: + - uses: actions/checkout@v4 + + - name: Find all apps + id: set-matrix + run: | + echo "apps=$(make echo-apps-json)" >> "$GITHUB_OUTPUT" + + build-app: + needs: generate-matrix + runs-on: ubuntu-latest + strategy: + matrix: + app: ${{ fromJson(needs.generate-matrix.outputs.apps) }} + steps: + - uses: actions/checkout@v4 + + - name: Install Wasm Rust target + run: | + rustup target add wasm32-wasip1 + + - name: Install wizer + env: + WIZER_VERSION: v9.0.0 + run: | + wget -O wizer-${{ env.WIZER_VERSION }}-x86_64-linux.tar.xz \ + https://github.com/bytecodealliance/wizer/releases/download/${{ env.WIZER_VERSION }}/wizer-${{ env.WIZER_VERSION }}-x86_64-linux.tar.xz + tar -xf wizer-${{ env.WIZER_VERSION }}-x86_64-linux.tar.xz + mv wizer-${{ env.WIZER_VERSION }}-x86_64-linux/wizer /usr/local/bin/wizer + + - uses: actions/setup-go@v5 + with: + go-version: '1.23' + cache: false + + - name: Setup TinyGo + uses: acifani/setup-tinygo@v2 + with: + tinygo-version: '0.35.0' + + - name: Install pnpm + run: | + npm install -g pnpm + + - name: Install Spin + uses: fermyon/actions/spin/setup@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Build ${{ matrix.app }} + env: + APPS: ${{ matrix.app }} + ENABLE_WASM_OPT: false + run: make build-apps + + # TODO: strategy for app-specific tests (see scripts/test.sh) + # - name: Test ${{ matrix.app }} + # env: + # APPS: ${{ matrix.app }} + # ENABLE_WASM_OPT: false + # TIMEOUT: 2m + # run: make test-apps \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..50576e0 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +SHELL := /bin/bash +MAKE_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) +APPS ?= $(shell find ./samples ./tutorials -type f -name 'spin.toml' -exec dirname {} \; | sort -u) + +default: build-apps + +# Run a command for an app +.PHONY: $(APPS) +$(APPS): + @echo "Running '$(SCRIPT)' for app: $@" + @cd $(MAKE_DIR)$@ && \ + $(MAKE_DIR)scripts/$(SCRIPT) || { \ + echo "❌ Error: '$(SCRIPT)' failed for app: $@"; \ + exit 1; \ + }; + +# Build the apps +.PHONY: build-apps +build-apps: + @SCRIPT='build.sh' $(MAKE) $(APPS) + +# Test the apps +.PHONY: test-apps +test-apps: build-apps + @SCRIPT="test.sh" $(MAKE) $(APPS) + +# Used by the GitHub test workflow +.PHONY: echo-apps-json +echo-apps-json: + @jq -Rn --arg str "$(APPS)" '$$str | split(" ")' | tr -d '\n' diff --git a/samples/geo-ip/.gitignore b/samples/geo-ip/.gitignore index 7152895..3c851fe 100644 --- a/samples/geo-ip/.gitignore +++ b/samples/geo-ip/.gitignore @@ -1,3 +1,4 @@ target/ .spin/ .spin-aka/ +geoip-static-db/geoip.mmdb diff --git a/samples/geo-ip/Makefile b/samples/geo-ip/Makefile index eb4d70f..e3440d1 100644 --- a/samples/geo-ip/Makefile +++ b/samples/geo-ip/Makefile @@ -2,4 +2,9 @@ build: @test -f geoip-static-db/geoip.mmdb || (echo "Error: geoip-static-db/geoip.mmdb not found!" && exit 1) cd geoip-static-db && ./build.sh geoip.mmdb - cargo build --target wasm32-wasip1 --release \ No newline at end of file + cargo build --target wasm32-wasip1 --release + +.PHONY: setup +setup: + cp ./etc/GeoIP2-City-Test.mmdb \ + ./geoip-static-db/geoip.mmdb diff --git a/samples/large-scale-redirects/.gitignore b/samples/large-scale-redirects/.gitignore index 7152895..fb4e7b9 100644 --- a/samples/large-scale-redirects/.gitignore +++ b/samples/large-scale-redirects/.gitignore @@ -1,3 +1,4 @@ target/ .spin/ .spin-aka/ +output/ \ No newline at end of file diff --git a/samples/large-scale-redirects/Makefile b/samples/large-scale-redirects/Makefile new file mode 100644 index 0000000..99ec1b4 --- /dev/null +++ b/samples/large-scale-redirects/Makefile @@ -0,0 +1,9 @@ +.PHONY: build-rules-manager +build-rules-manager: + cargo build --release -p rules-manager + +.PHONY: setup +setup: build-rules-manager + ./target/release/rules-manager \ + --add-rules example-redirects.txt \ + --output-dir output diff --git a/samples/large-scale-redirects/build.sh b/samples/large-scale-redirects/build.sh index b586d49..c9f0839 100755 --- a/samples/large-scale-redirects/build.sh +++ b/samples/large-scale-redirects/build.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -e +ENABLE_WASM_OPT="${ENABLE_WASM_OPT:-true}" + # Check if the correct number of arguments is provided if [ "$#" -ne 4 ]; then echo "Usage: $0 " @@ -11,7 +13,7 @@ fi cargo build --target wasm32-wasip1 --release echo "$1 $2 $3" | wizer --allow-wasi --wasm-bulk-memory true --dir . -o "$4" target/wasm32-wasip1/release/redirects_rs.wasm # If wasm-opt is installed, run it to optimize the output -if command -v wasm-opt &> /dev/null +if [[ "${ENABLE_WASM_OPT}" == "true" ]] && command -v wasm-opt &> /dev/null then wasm-opt -O3 --enable-bulk-memory-opt -o "$4" "$4" fi diff --git a/samples/large-scale-redirects/spin.toml b/samples/large-scale-redirects/spin.toml index d45d49e..6e2bb92 100644 --- a/samples/large-scale-redirects/spin.toml +++ b/samples/large-scale-redirects/spin.toml @@ -14,5 +14,5 @@ component = "redirects-rs" source = "target/redirect.wasm" allowed_outbound_hosts = [] [component.redirects-rs.build] -command = "./build.sh example-redirects.txt" +command = "./build.sh output/sources.fst output/targets.fcsd 302 target/redirect.wasm" watch = ["src/**/*.rs", "Cargo.toml", "build.sh", "redirects.txt"] diff --git a/samples/traffic-splitting/request-analytics/src/metadata.ts b/samples/traffic-splitting/request-analytics/src/metadata.ts index b8a885a..366e5b6 100644 --- a/samples/traffic-splitting/request-analytics/src/metadata.ts +++ b/samples/traffic-splitting/request-analytics/src/metadata.ts @@ -1,4 +1,4 @@ -import { Variables } from "@fermyon/spin-sdk"; +import * as Variables from '@spinframework/spin-variables'; export class Metadata { url?: string; diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..0aec2a4 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -euo pipefail + +# Some apps require extra setup steps +current_dir=$(basename "${PWD}") +if [[ "${current_dir}" == "geo-ip" || \ + "${current_dir}" == "large-scale-redirects" ]]; then + make setup +fi + +spin build diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..740a47e --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -beuo pipefail + +# TODO: some apps have specific instructions for their requests, eg headers, paths, variables, etc. +# Perhaps ensure each app dir has a Makefile or script with specific test steps, defaulting to something like below? + +# find free port, to support concurrent invocations on the same host +# (although 'spin up' has a '--find-free-port' option, we need to know it ahead of time for the subsequent curl request) +port=$(python3 -c "import socket; s=socket.socket(); s.bind(('', 0)); print(s.getsockname()[1]); s.close()") + +spin up --listen "127.0.0.1:${port}" & + +timeout ${TIMEOUT:-30s} bash -c 'until [ "$(curl -sL -o /dev/null -w "%{http_code}" 127.0.0.1:$0)" = "200" ]; do sleep 1; done' "${port}" + +trap 'kill -s SIGTERM $(jobs -p)' EXIT