diff --git a/.github/workflows/ci-spec.yml b/.github/workflows/ci-spec.yml index 53a50ef56c..566d5b9b82 100644 --- a/.github/workflows/ci-spec.yml +++ b/.github/workflows/ci-spec.yml @@ -12,6 +12,11 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: +# Path within the published site recording the commit the baseline was rendered +# from, both as provenance and so a run can tell the copy is still current. +env: + BASELINE_STAMP: upstream/baseline-sha + jobs: ensure-wasm-latest: if: ${{ github.repository == 'WebAssembly/spec' }} @@ -22,13 +27,84 @@ jobs: - name: Diff wasm-latest run: cd specification && bash diff-wasm-latest.sh + # Forks (i.e. proposal repos) also render the spec at the commit where they + # last diverged from their parent repo, so the proposal can be compared + # against an unmodified baseline. That baseline is published under /upstream. + resolve-baseline: + runs-on: ubuntu-latest + outputs: + variants: ${{ steps.resolve.outputs.variants }} + # The commit the baseline is rendered from, empty when there is none. A + # baseline absent from variants is one already published under /upstream. + base-sha: ${{ steps.resolve.outputs.base-sha }} + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + # merge-base needs the full history + fetch-depth: 0 + - name: Resolve upstream baseline + id: resolve + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPOSITORY: ${{ github.repository }} + run: | + set -euo pipefail + # Written once on whichever path exits below, so these defaults stand + # unless the checks further down replace them. + variants='["head"]' + base='' + write_outputs() { + echo "variants=$variants" >> "$GITHUB_OUTPUT" + echo "base-sha=$base" >> "$GITHUB_OUTPUT" + } + trap write_outputs EXIT + if [ "$REPOSITORY" = "WebAssembly/spec" ]; then + echo "Canonical repo, no upstream baseline." + exit 0 + fi + # A copy already on the site is left in place unless a newer baseline + # is rendered below. + published=$(gh api "repos/$REPOSITORY/contents/$BASELINE_STAMP?ref=gh-pages" \ + --jq .content 2>/dev/null | base64 -d | tr -d '[:space:]') || published='' + parent=$(gh api "repos/$REPOSITORY" --jq '.parent.full_name // ""' 2>/dev/null) || parent='' + if [ -z "$parent" ]; then + echo "::warning::Could not determine the parent repo, not rendering an upstream copy." + exit 0 + fi + if ! git fetch --no-tags --quiet "https://github.com/$parent.git" main; then + echo "::warning::Could not fetch $parent, not rendering an upstream copy." + exit 0 + fi + if ! merge_base=$(git merge-base HEAD FETCH_HEAD); then + echo "::warning::No common ancestor with $parent, no upstream copy." + exit 0 + fi + if [ "$merge_base" = "$(git rev-parse HEAD)" ]; then + echo "::notice::No divergence from $parent, no upstream copy." + exit 0 + fi + base=$merge_base + if [ "$base" = "$published" ]; then + echo "::notice::Baseline $base is already published, keeping that copy." + exit 0 + fi + echo "Upstream baseline: $base (from $parent)" + variants='["head","upstream"]' + build-core-spec: runs-on: ubuntu-latest + needs: resolve-baseline + strategy: + fail-fast: false + matrix: + variant: ${{ fromJSON(needs.resolve-baseline.outputs.variants) }} steps: - name: Checkout repo uses: actions/checkout@v4 with: submodules: "recursive" + ref: ${{ matrix.variant == 'upstream' && needs.resolve-baseline.outputs.base-sha || '' }} - name: Setup OCaml uses: ocaml/setup-ocaml@v3 with: @@ -54,14 +130,21 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: core-rendered + name: core-rendered-${{ matrix.variant }} path: document/core/_build/html build-js-api-spec: runs-on: ubuntu-latest + needs: resolve-baseline + strategy: + fail-fast: false + matrix: + variant: ${{ fromJSON(needs.resolve-baseline.outputs.variants) }} steps: - name: Checkout repo uses: actions/checkout@v4 + with: + ref: ${{ matrix.variant == 'upstream' && needs.resolve-baseline.outputs.base-sha || '' }} - name: Setup Bikeshed run: pip install bikeshed && bikeshed update - name: Run Bikeshed @@ -69,14 +152,21 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: js-api-rendered + name: js-api-rendered-${{ matrix.variant }} path: document/js-api/index.html build-web-api-spec: runs-on: ubuntu-latest + needs: resolve-baseline + strategy: + fail-fast: false + matrix: + variant: ${{ fromJSON(needs.resolve-baseline.outputs.variants) }} steps: - name: Checkout repo uses: actions/checkout@v4 + with: + ref: ${{ matrix.variant == 'upstream' && needs.resolve-baseline.outputs.base-sha || '' }} - name: Setup Bikeshed run: pip install bikeshed && bikeshed update - name: Run Bikeshed @@ -84,16 +174,22 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: web-api-rendered + name: web-api-rendered-${{ matrix.variant }} path: document/web-api/index.html build-code-metadata-spec: runs-on: ubuntu-latest + needs: resolve-baseline + strategy: + fail-fast: false + matrix: + variant: ${{ fromJSON(needs.resolve-baseline.outputs.variants) }} steps: - name: Checkout repo uses: actions/checkout@v4 with: submodules: "recursive" + ref: ${{ matrix.variant == 'upstream' && needs.resolve-baseline.outputs.base-sha || '' }} - name: Setup TexLive run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - name: Setup Sphinx @@ -103,16 +199,22 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: code-metadata-rendered + name: code-metadata-rendered-${{ matrix.variant }} path: document/metadata/code/_build/html build-legacy-exceptions-core-spec: runs-on: ubuntu-latest + needs: resolve-baseline + strategy: + fail-fast: false + matrix: + variant: ${{ fromJSON(needs.resolve-baseline.outputs.variants) }} steps: - name: Checkout repo uses: actions/checkout@v4 with: submodules: "recursive" + ref: ${{ matrix.variant == 'upstream' && needs.resolve-baseline.outputs.base-sha || '' }} - name: Setup TexLive run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended - name: Setup Sphinx @@ -122,14 +224,21 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: legacy-exceptions-core-rendered + name: legacy-exceptions-core-rendered-${{ matrix.variant }} path: document/legacy/exceptions/core/_build/html build-legacy-exceptions-js-api-spec: runs-on: ubuntu-latest + needs: resolve-baseline + strategy: + fail-fast: false + matrix: + variant: ${{ fromJSON(needs.resolve-baseline.outputs.variants) }} steps: - name: Checkout repo uses: actions/checkout@v4 + with: + ref: ${{ matrix.variant == 'upstream' && needs.resolve-baseline.outputs.base-sha || '' }} - name: Setup Bikeshed run: pip install bikeshed && bikeshed update - name: Run Bikeshed @@ -137,24 +246,32 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: legacy-exceptions-js-api-rendered + name: legacy-exceptions-js-api-rendered-${{ matrix.variant }} path: document/legacy/exceptions/js-api/index.html build-spec-versions: runs-on: ubuntu-latest + needs: resolve-baseline + strategy: + fail-fast: false + matrix: + variant: ${{ fromJSON(needs.resolve-baseline.outputs.variants) }} steps: - name: Checkout repo uses: actions/checkout@v4 + with: + ref: ${{ matrix.variant == 'upstream' && needs.resolve-baseline.outputs.base-sha || '' }} - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: versions-rendered + name: versions-rendered-${{ matrix.variant }} path: document/versions/ publish-spec: runs-on: ubuntu-latest needs: - ensure-wasm-latest + - resolve-baseline - build-core-spec - build-js-api-spec - build-web-api-spec @@ -165,43 +282,76 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v4 + with: + # The baseline's index.html is read out of the history below + fetch-depth: 0 - name: Create output directory run: mkdir _output && cp document/index.html _output/index.html - name: Download core spec artifact uses: actions/download-artifact@v4 with: - name: core-rendered + name: core-rendered-head path: _output/core - name: Download JS API spec artifact uses: actions/download-artifact@v4 with: - name: js-api-rendered + name: js-api-rendered-head path: _output/js-api - name: Download Web API spec artifact uses: actions/download-artifact@v4 with: - name: web-api-rendered + name: web-api-rendered-head path: _output/web-api - name: Download code metadata spec artifact uses: actions/download-artifact@v4 with: - name: code-metadata-rendered + name: code-metadata-rendered-head path: _output/metadata/code - name: Download legacy exceptions core spec artifact uses: actions/download-artifact@v4 with: - name: legacy-exceptions-core-rendered + name: legacy-exceptions-core-rendered-head path: _output/legacy/exceptions/core - name: Download legacy exceptions JS API spec artifact uses: actions/download-artifact@v4 with: - name: legacy-exceptions-js-api-rendered + name: legacy-exceptions-js-api-rendered-head path: _output/legacy/exceptions/js-api - name: Download spec versions artifacts uses: actions/download-artifact@v4 with: - name: versions-rendered + name: versions-rendered-head path: _output/versions + - name: Download upstream baseline artifacts + if: contains(fromJSON(needs.resolve-baseline.outputs.variants), 'upstream') + uses: actions/download-artifact@v4 + with: + pattern: '*-rendered-upstream' + path: _upstream + - name: Assemble upstream baseline copy + if: contains(fromJSON(needs.resolve-baseline.outputs.variants), 'upstream') + env: + BASE_SHA: ${{ needs.resolve-baseline.outputs.base-sha }} + run: | + set -euo pipefail + mkdir -p _output/upstream/metadata _output/upstream/legacy/exceptions + git show "$BASE_SHA:document/index.html" > _output/upstream/index.html + mv _upstream/core-rendered-upstream _output/upstream/core + mv _upstream/js-api-rendered-upstream _output/upstream/js-api + mv _upstream/web-api-rendered-upstream _output/upstream/web-api + mv _upstream/code-metadata-rendered-upstream _output/upstream/metadata/code + mv _upstream/legacy-exceptions-core-rendered-upstream _output/upstream/legacy/exceptions/core + mv _upstream/legacy-exceptions-js-api-rendered-upstream _output/upstream/legacy/exceptions/js-api + mv _upstream/versions-rendered-upstream _output/upstream/versions + echo "$BASE_SHA" > "_output/$BASELINE_STAMP" + - name: Keep the upstream baseline copy already published + if: needs.resolve-baseline.outputs.base-sha != '' && !contains(fromJSON(needs.resolve-baseline.outputs.variants), 'upstream') + run: | + set -euo pipefail + # Publishing replaces the whole site, so the copy has to be carried + # over explicitly rather than just left in place. + git fetch --no-tags --depth 1 origin gh-pages + git archive FETCH_HEAD upstream | tar -x -C _output - name: Publish to GitHub Pages if: github.ref == 'refs/heads/main' uses: peaceiris/actions-gh-pages@v4