Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Publish npm registry

on:
workflow_call:
inputs:
tag:
description: Existing release tag to publish
required: true
type: string
expected_sha:
description: Commit that the release tag must resolve to
required: false
default: ''
type: string
dist_tag:
description: npm distribution tag
required: false
default: latest
type: string
secrets:
NPM_TOKEN:
description: npm publication token; optional when trusted publishing is configured
required: false
workflow_dispatch:
inputs:
tag:
description: Existing release tag to publish (for example v0.1.1)
required: true
type: string
expected_sha:
description: Optional full commit SHA to verify against the release tag
required: false
default: ''
type: string
dist_tag:
description: npm distribution tag
required: true
default: latest
type: choice
options: [latest, next]

permissions:
contents: read

concurrency:
group: npm-publish-${{ inputs.tag }}
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
environment: npm
permissions:
contents: read
id-token: write
env:
RELEASE_TAG: ${{ inputs.tag }}
EXPECTED_SHA: ${{ inputs.expected_sha }}
NPM_DIST_TAG: ${{ inputs.dist_tag }}
steps:
- name: Validate release inputs
shell: bash
run: |
[[ "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]
[[ -z "$EXPECTED_SHA" || "$EXPECTED_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$NPM_DIST_TAG" == latest || "$NPM_DIST_TAG" == next ]]
- uses: actions/checkout@v7
with:
ref: refs/tags/${{ inputs.tag }}
persist-credentials: false
- name: Verify release version and commit
shell: bash
run: |
node --input-type=module -e 'import fs from "node:fs"; const p = JSON.parse(fs.readFileSync("package.json", "utf8")); if (`v${p.version}` !== process.env.RELEASE_TAG) throw Error("Tag/version mismatch");'
if [[ -n "$EXPECTED_SHA" && "$(git rev-parse HEAD)" != "$EXPECTED_SHA" ]]; then
echo 'Release tag does not identify the verified CI commit.' >&2
exit 1
fi
- uses: actions/setup-node@v7
with:
node-version: 24
registry-url: https://registry.npmjs.org
package-manager-cache: false
- run: npm install --global npm@11
- run: npm ci
- name: Download existing release assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
[[ "$(gh release view "$RELEASE_TAG" --json isDraft --jq .isDraft)" == false ]]
gh release download "$RELEASE_TAG" --pattern '*.tgz' --pattern SHA256SUMS.txt --dir .release/npm
- name: Verify release asset checksum
id: asset
run: node scripts/npm-registry.mjs prepare .release/npm
- name: Verify the exact release tarball in installed consumers
env:
RELEASE_TARBALL: ${{ steps.asset.outputs.tarball }}
run: node scripts/package-test.mjs --tarball "$RELEASE_TARBALL"
- name: Check immutable npm version
id: registry
env:
RELEASE_TARBALL: ${{ steps.asset.outputs.tarball }}
run: node scripts/npm-registry.mjs check "$RELEASE_TARBALL"
- name: Publish release tarball with provenance
if: steps.registry.outputs.exists != 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
RELEASE_TARBALL: ${{ steps.asset.outputs.tarball }}
run: npm publish "$RELEASE_TARBALL" --registry=https://registry.npmjs.org --access public --provenance --ignore-scripts --tag "$NPM_DIST_TAG"
- name: Download and verify the public npm artifact and consumers
env:
RELEASE_TARBALL: ${{ steps.asset.outputs.tarball }}
run: node scripts/npm-registry.mjs verify "$RELEASE_TARBALL" "$NPM_DIST_TAG"
116 changes: 103 additions & 13 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,73 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: '22'
cache: npm
- run: npm ci
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install test toolchains
run: |
npm install --global typescript@5.8.3
python -m pip install -r tests/requirements.txt
python -m playwright install --with-deps chromium
- name: Test Core, declarations, HTTP transport and browser behavior
shell: bash
run: |
npm test
npm run typecheck
npm run test:http
npm run check
python tests/browser.py
- name: Verify installed npm consumers and browser component
run: |
npx playwright install --with-deps chromium
npm run test:package -- --browser
- name: Stage the static site
run: |
mkdir -p _site
cp index.html README.md LICENSE THIRD_PARTY_NOTICES.md _site/
cp -R packages samples dist docs releases _site/
touch _site/.nojekyll
printf '{"commit":"%s","run":"%s"}\n' "$GITHUB_SHA" "$GITHUB_RUN_ID" > _site/build.json
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
with:
name: verified-site
path: _site/
include-hidden-files: true
- name: Create verified release archives
run: |
npm pack --ignore-scripts
tar -czf treedatagrid-browser.tar.gz -C dist .
tar -czf treedatagrid-showcase.tar.gz -C _site .
sha256sum *.tgz *.tar.gz > SHA256SUMS.txt
- uses: actions/upload-artifact@v7
with:
name: distribution
path: |
*.tgz
*.tar.gz
SHA256SUMS.txt
- name: Upload test evidence
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: verification
path: verification/
node24:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run check
- run: npm run test:package
publish:
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
needs: verify
needs: [verify, node24]
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
Expand All @@ -65,10 +92,10 @@ jobs:
name: github-pages
url: https://wieslawsoltes.github.io/TreeDataGridWeb/
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v8
with:
name: verified-site
path: _site
Expand Down Expand Up @@ -107,10 +134,11 @@ jobs:
sleep 5
done
echo 'Pages build did not finish within the polling window.'; exit 1
- uses: actions/upload-pages-artifact@v3
- uses: actions/upload-pages-artifact@v5
if: steps.config.outputs.type == 'workflow'
with:
path: _site
include-hidden-files: true
- uses: actions/deploy-pages@v4
if: steps.config.outputs.type == 'workflow'
- uses: actions/setup-python@v5
Expand All @@ -125,7 +153,69 @@ jobs:
python tests/hosted.py "$DEMO_URL"
- name: Upload hosted-demo evidence
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: hosted-demo-verification
path: verification/hosted/

release:
needs: [verify, node24]
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
tag: ${{ steps.release.outputs.tag }}
publish: ${{ steps.release.outputs.publish }}
dist_tag: ${{ steps.release.outputs.dist_tag }}
steps:
- uses: actions/checkout@v7
- uses: actions/download-artifact@v8
with:
name: distribution
- uses: actions/setup-node@v7
with:
node-version: 24
package-manager-cache: false
- name: Publish immutable versioned release
id: release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
package_version=$(node -p 'JSON.parse(require("fs").readFileSync("package.json", "utf8")).version')
release_tag="v$package_version"
release_flags=()
if [[ "$package_version" == *-* ]]; then
release_flags+=(--prerelease)
echo "dist_tag=next" >> "$GITHUB_OUTPUT"
else
echo "dist_tag=latest" >> "$GITHUB_OUTPUT"
fi
if gh release view "$release_tag" >/dev/null 2>&1; then
echo 'Existing release and its immutable assets retained.'
else
gh release create "$release_tag" --target "$GITHUB_SHA" --title "TreeDataGridWeb $package_version" --notes-file docs/release-notes.md "${release_flags[@]}" *.tgz *.tar.gz SHA256SUMS.txt
fi
echo "tag=$release_tag" >> "$GITHUB_OUTPUT"
git fetch --no-tags origin "refs/tags/$release_tag:refs/tags/$release_tag"
release_commit=$(git rev-list -n 1 "$release_tag")
if [[ "$release_commit" == "$GITHUB_SHA" ]]; then
echo 'publish=true' >> "$GITHUB_OUTPUT"
else
echo 'publish=false' >> "$GITHUB_OUTPUT"
echo 'Existing release belongs to another commit; npm publication skipped.'
fi
npm:
needs: release
if: needs.release.outputs.publish == 'true'
permissions:
contents: read
id-token: write
uses: ./.github/workflows/npm-publish.yml
with:
tag: ${{ needs.release.outputs.tag }}
expected_sha: ${{ github.sha }}
dist_tag: ${{ needs.release.outputs.dist_tag }}
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ __pycache__/
.DS_Store
!releases/*.tgz
_site/

.release/
test-results/
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## 0.1.0

- First public npm publication as `@wieslawsoltes/treedatagridweb`, containing both Core and browser packages.
- Typed subpath exports, CSS and standalone assets, installed consumer checks and verified immutable release/npm publication with provenance.

Initial delivered web implementation: DOM-independent Core, native custom-element presentation/control, the eight Core sample scenarios plus two diagnostics, TypeScript declarations, offline distributions, curated core/browser tests and recorded measurements. The port targets upstream revision `3ca47316d724e5e040ab0281a880e8df999b25fc`.

Notable validation fixes include variable-height end-of-list anchoring, shared-view sizing, stale template callback prevention on recycling, removal of a forced post-write layout read, numeric formatter caching, model-only reads without row allocation, efficient Reset index remapping, loaded-child selection lookup, and correct deselected-item payloads during collection removal.
Expand Down
Loading
Loading