diff --git a/.github/workflows/zed-e2e.yml b/.github/workflows/zed-e2e.yml index 02f29e4..eebc87c 100644 --- a/.github/workflows/zed-e2e.yml +++ b/.github/workflows/zed-e2e.yml @@ -1,98 +1,51 @@ name: zed e2e (node + docker) + on: + pull_request: push: + branches: [main] workflow_dispatch: +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + ZED_INTERFACES_REF: 61f654d5e4ca718abc4a280a641472466689c278 + ZED_CLI_REF: 359ea72e21027ed54a29fad95b05f38a1ea142c3 + NODE_LIB_REF: 2d41e658a382fdff27ef87a0db24dbaff280a685 + jobs: test: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v4 - - - name: Prepare the Docker build context - run: | - mkdir -p "$RUNNER_TEMP/zed-docker-context" - git clone --depth 1 \ - https://github.com/zed-pkg/zed-interfaces \ - "$RUNNER_TEMP/zed-docker-context/zed-interfaces" - git clone --depth 1 \ - https://github.com/zed-pkg/zed-cli \ - "$RUNNER_TEMP/zed-docker-context/zed-cli" - - - name: Build Node + zed test image - run: | - docker build \ - --file .github/docker/Dockerfile \ - --tag zed-pkg-test/node-e2e \ - "$RUNNER_TEMP/zed-docker-context" - - - name: Publish node-lib inside Docker - run: | - git clone --depth 1 \ - https://github.com/zed-pkg-test/node-lib \ - "$RUNNER_TEMP/node-lib" - mkdir -p "$RUNNER_TEMP/zed-registry" "$RUNNER_TEMP/zed-home" - docker run --rm \ - --volume "$RUNNER_TEMP/node-lib:/package" \ - --volume "$RUNNER_TEMP/zed-registry:/registry" \ - --workdir /package \ - zed-pkg-test/node-e2e \ - zed publish --registry file:///registry --skip-vcs-checks + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - - name: Symlink install works with its store mounted - run: | - docker run --rm \ - --volume "$GITHUB_WORKSPACE:/work" \ - --volume "$RUNNER_TEMP/zed-registry:/registry:ro" \ - --volume "$RUNNER_TEMP/zed-home:/zed-home" \ - --workdir /work \ - zed-pkg-test/node-e2e \ - sh -euc ' - zed install \ - --registry file:///registry \ - --home /zed-home \ - --install-mode symlink - test -L .vendor/.zed/zed-pkg-test/node-lib - test -L node_modules/@zed-pkg-test/node-lib - node src/main.js - ' + - name: Validate workflow + uses: docker://rhysd/actionlint@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 + with: + args: .github/workflows/zed-e2e.yml - - name: Symlink install fails without its store mount - run: | - if docker run --rm \ - --volume "$GITHUB_WORKSPACE:/work:ro" \ - --workdir /work \ - node:22-bookworm-slim \ - node src/main.js - then - echo "expected the unmounted store-backed symlinks to fail" - exit 1 - fi - - - name: Frozen copy install contains no store symlinks - run: | - docker run --rm \ - --volume "$GITHUB_WORKSPACE:/work" \ - --volume "$RUNNER_TEMP/zed-registry:/registry:ro" \ - --volume "$RUNNER_TEMP/zed-home:/zed-home" \ - --workdir /work \ - zed-pkg-test/node-e2e \ - sh -euc ' - zed install \ - --frozen \ - --registry file:///registry \ - --home /zed-home \ - --install-mode copy - test ! -L .vendor/.zed/zed-pkg-test/node-lib - test ! -L node_modules/@zed-pkg-test/node-lib - test -z "$(find .vendor/.zed node_modules/@zed-pkg-test -type l -print -quit)" - node src/main.js - ' + - name: Validate executable test script + run: bash -n scripts/zed-e2e.sh - - name: Copy install runs in a fresh Node container + - name: Run pinned cross-container interoperability suite + shell: bash run: | - docker run --rm \ - --volume "$GITHUB_WORKSPACE:/work:ro" \ - --workdir /work \ - node:22-bookworm-slim \ - node src/main.js + set -o pipefail + bash scripts/zed-e2e.sh 2>&1 | tee "$RUNNER_TEMP/zed-node-e2e.log" + + - name: Upload interoperability diagnostics + if: ${{ always() }} + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + with: + name: zed-node-e2e-log + path: ${{ runner.temp }}/zed-node-e2e.log + if-no-files-found: warn + retention-days: 7 diff --git a/package.json b/package.json index 85bf0d9..db5ed35 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,11 @@ "name": "node-app", "version": "0.1.0", "private": true, - "description": "npm still owns these; zed provides @zed-pkg-test/node-lib", + "description": "npm still owns ordinary dependencies; zed provides @zed-pkg-test/node-lib.", + "scripts": { + "check": "node --check src/main.js", + "start": "node src/main.js" + }, + "license": "MIT", "devDependencies": {} } diff --git a/scripts/zed-e2e.sh b/scripts/zed-e2e.sh new file mode 100644 index 0000000..7cc6667 --- /dev/null +++ b/scripts/zed-e2e.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${ZED_INTERFACES_REF:?ZED_INTERFACES_REF is required}" +: "${ZED_CLI_REF:?ZED_CLI_REF is required}" +: "${NODE_LIB_REF:?NODE_LIB_REF is required}" + +WORKSPACE="${GITHUB_WORKSPACE:-$(pwd)}" +TEMP_ROOT="${RUNNER_TEMP:-${TMPDIR:-/tmp}/zed-pkg-test-node}" +RUN_ID="${GITHUB_SHA:-local}" +CONTEXT="$TEMP_ROOT/zed-docker-context" +REGISTRY="$TEMP_ROOT/zed-registry" +HOME_DIR="$TEMP_ROOT/zed-home" +NODE_LIB="$TEMP_ROOT/node-lib" +IMAGE="zed-pkg-test/node-e2e:$RUN_ID" + +clone_at() { + local repo="$1" + local ref="$2" + local destination="$3" + git init -q "$destination" + git -C "$destination" remote add origin "$repo" + git -C "$destination" fetch --depth 1 origin "$ref" + git -C "$destination" checkout -q --detach FETCH_HEAD + test "$(git -C "$destination" rev-parse HEAD)" = "$ref" +} + +prepare() { + rm -rf "$CONTEXT" "$REGISTRY" "$HOME_DIR" "$NODE_LIB" + mkdir -p "$CONTEXT" "$REGISTRY" "$HOME_DIR" + cd "$WORKSPACE" + + docker run --rm \ + --volume "$WORKSPACE:/work:ro" \ + --workdir /work \ + node:22-bookworm-slim \ + npm run check + + python3 - <<'PY' +import json +import tomllib +from pathlib import Path + +native = json.loads(Path("package.json").read_text()) +with Path(".zpkg.toml").open("rb") as handle: + zed = tomllib.load(handle) +package = zed["package"] +assert native["name"] == package["name"] +assert native["version"] == package["version"] +assert native["license"] == package["license"] +assert package["org"] == "zed-pkg-test" +assert zed["dependencies"] == {"zed-pkg-test/node-lib": "^1.0.0"} +PY + + clone_at https://github.com/zed-pkg/zed-interfaces.git \ + "$ZED_INTERFACES_REF" "$CONTEXT/zed-interfaces" + clone_at https://github.com/zed-pkg/zed-cli.git \ + "$ZED_CLI_REF" "$CONTEXT/zed-cli" + + docker build \ + --file "$WORKSPACE/.github/docker/Dockerfile" \ + --tag "$IMAGE" \ + "$CONTEXT" + + clone_at https://github.com/zed-pkg-test/node-lib.git \ + "$NODE_LIB_REF" "$NODE_LIB" + + docker run --rm \ + --volume "$NODE_LIB:/package:ro" \ + --workdir /package \ + node:22-bookworm-slim \ + node -e 'const {greet}=require("./src"); if(greet("fixture")!=="hello fixture from @zed-pkg-test/node-lib") process.exit(1)' + + test -z "$(git -C "$NODE_LIB" status --porcelain)" + docker run --rm \ + --volume "$NODE_LIB:/source:ro" \ + --volume "$REGISTRY:/registry" \ + --workdir /tmp \ + "$IMAGE" \ + sh -euc ' + cp -a /source /tmp/package + chmod -R u+w /tmp/package + cd /tmp/package + zed publish --registry file:///registry --skip-vcs-checks + ' + test -z "$(git -C "$NODE_LIB" status --porcelain)" + test "$(git -C "$NODE_LIB" rev-parse HEAD)" = "$NODE_LIB_REF" + if ! find "$REGISTRY" -type f -print -quit | grep -q .; then + echo "zed publish produced no registry artifact" >&2 + exit 1 + fi +} + +symlink_install() { + cd "$WORKSPACE" + rm -rf .vendor/.zed node_modules .zed + docker run --rm \ + --volume "$WORKSPACE:/work" \ + --volume "$REGISTRY:/registry:ro" \ + --volume "$HOME_DIR:/zed-home" \ + --workdir /work \ + "$IMAGE" \ + sh -euc ' + zed install \ + --registry file:///registry \ + --home /zed-home \ + --install-mode symlink + test -L .vendor/.zed/zed-pkg-test/node-lib + test -L node_modules/@zed-pkg-test/node-lib + npm start + ' +} + +missing_store() { + cd "$WORKSPACE" + if docker run --rm \ + --volume "$WORKSPACE:/work:ro" \ + --workdir /work \ + node:22-bookworm-slim \ + npm start + then + echo "expected the unmounted store-backed symlinks to fail" >&2 + exit 1 + fi +} + +copy_install() { + cd "$WORKSPACE" + docker run --rm \ + --volume "$WORKSPACE:/work" \ + --volume "$REGISTRY:/registry:ro" \ + --volume "$HOME_DIR:/zed-home" \ + --workdir /work \ + "$IMAGE" \ + sh -euc ' + zed install \ + --frozen \ + --registry file:///registry \ + --home /zed-home \ + --install-mode copy + test ! -L .vendor/.zed/zed-pkg-test/node-lib + test ! -L node_modules/@zed-pkg-test/node-lib + test -z "$(find .vendor/.zed node_modules/@zed-pkg-test -type l -print -quit)" + npm start + ' +} + +fresh_copy() { + cd "$WORKSPACE" + docker run --rm \ + --volume "$WORKSPACE:/work:ro" \ + --workdir /work \ + node:22-bookworm-slim \ + npm start +} + +phase="${1:-all}" +case "$phase" in + prepare) prepare ;; + symlink) symlink_install ;; + missing-store) missing_store ;; + copy) copy_install ;; + fresh-copy) fresh_copy ;; + all) + prepare + symlink_install + missing_store + copy_install + fresh_copy + ;; + *) + echo "unknown phase: $phase" >&2 + exit 2 + ;; +esac