diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 2a4766d..620f78d 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -1,33 +1,52 @@ -# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created -# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages - name: Node.js Package on: release: - types: [created] + types: [published] + workflow_dispatch: + inputs: + release_tag: + description: "Release tag to publish, for example v1.1.1" + required: true + type: string + +permissions: + contents: read jobs: - build: + publish-npm: runs-on: ubuntu-latest + env: + RELEASE_TAG: ${{ github.event.inputs.release_tag || github.event.release.tag_name }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - name: Check out release tag + uses: actions/checkout@v4 with: - node-version: 20 - - run: npm ci - - run: npm test + ref: ${{ github.event.inputs.release_tag || github.event.release.tag_name }} - publish-npm: - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - name: Set up Node + uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 + cache: npm registry-url: https://registry.npmjs.org/ - - run: npm ci - - run: npm publish + + - name: Install dependencies + run: npm ci + + - name: Validate release tag + run: | + # The published tag is the package artifact contract; fail before npm publish if it drifts. + PACKAGE_VERSION="$(node -p "require('./package.json').version")" + if [ "v${PACKAGE_VERSION}" != "$RELEASE_TAG" ]; then + echo "::error title=Release tag mismatch::Expected v${PACKAGE_VERSION}, got ${RELEASE_TAG}." + exit 1 + fi + + - name: Verify package + run: npm run check + + - name: Publish package to npm + run: npm publish --access public env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 868c4b1..e7adf2e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ node_modules/ +.npm-cache/ +.tmp/ *.tgz .superpowers/ output/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..1553fcb --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +cache=.npm-cache diff --git a/CHANGELOG.md b/CHANGELOG.md index 603dc54..237f546 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,9 @@ All notable changes to `layout-style-css` are documented here. -This project follows semantic versioning. The `1.1.0` release is additive and keeps the existing `ly-*` public contract intact. +This project follows semantic versioning. The `1.1.1` release is additive and keeps the existing `ly-*` public contract intact. -## [1.1.0] - 2026-07-05 +## [1.1.1] - 2026-07-05 ### Added @@ -21,7 +21,8 @@ This project follows semantic versioning. The `1.1.0` release is additive and ke - Reworked the demo mobile controls into a compact drawer so the sticky header does not consume the mobile viewport. - Expanded the demo to cover app shell, wrappers, split layouts, sidebars, panes, button groups, card grids, card sizes, galleries, carousels, frames, and scroll areas. - Updated README examples to use exported CSS entrypoints and valid CDN links. -- Updated npm release metadata, package file allowlist, and release verification scripts for the `1.1.0` package. +- Updated npm release metadata, package file allowlist, and release verification scripts for the `1.1.1` package. +- Updated the npm publish workflow to publish from `release.published` events and explicit `workflow_dispatch` tags. ### Fixed @@ -29,6 +30,7 @@ This project follows semantic versioning. The `1.1.0` release is additive and ke - Fixed malformed UI Style Kit CDN link markup in the README. - Clarified responsive column utility documentation so class groups do not imply bare numeric class names. - Preserved GitHub Pages artifact generation with a Pages-root `index.html`. +- Fixed the release automation path so draft releases can be published before the npm workflow runs. ### Security diff --git a/README.md b/README.md index 4bea724..8f9580d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The versioned wiki source lives in this repository so docs can be reviewed with | [Layout styles](docs/wiki/Layout-Styles.md) | All layout personalities, including F-Pattern, Z-Pattern, Split-Screen, Mondrian, and Synthwave. | | [UI Style Kit compatibility](docs/wiki/UI-Style-Kit-Compatibility.md) | Prefix aliases and the boundary between structure and visual styling. | | [Demo and GitHub Pages](docs/wiki/Demo-And-GitHub-Pages.md) | Demo QA, Pages artifact behavior, and deployment setup. | -| [Release and publishing](docs/wiki/Release-And-Publishing.md) | v1.1.0 release checklist, npm verification, and tag guidance. | +| [Release and publishing](docs/wiki/Release-And-Publishing.md) | v1.1.1 release checklist, npm verification, and tag guidance. | | [Security and support](docs/wiki/Security-And-Support.md) | Security model, supported versions, and reporting path. | | [Contributing](docs/wiki/Contributing.md) | Local development, CSS rules, and review expectations. | | [Wiki sidebar source](docs/wiki/_Sidebar.md) | Navigation file for a GitHub Wiki mirror. | @@ -41,7 +41,7 @@ Use as a standalone layout system with all styles or just one layout personality ```bash # Install the full layout system -npm install layout-style-css@1.0.0 +npm install layout-style-css@1.1.1 ``` Then import whichever CSS entrypoints you need: @@ -54,13 +54,13 @@ import "layout-style-css/minimal-saas.css"; Pair with UI Style Kit CSS for a complete layout and visual system. Themes and layouts can mix and match UI styles. Set the vibe with color schemes that offer a range of moods, from minimal to maximal, from Bauhaus to Brutalism. ```bash -npm install layout-style-css@1.0.0 ui-style-kit-css@2.0.1 +npm install layout-style-css@1.1.1 ui-style-kit-css@2.0.1 ``` Additionally installing Interactive Surface CSS sets you up with a complete reactive layout and surface system. ```bash -npm install layout-style-css@1.0.0 ui-style-kit-css@2.0.1 interactive-surface-css@1.2.5 +npm install layout-style-css@1.1.1 ui-style-kit-css@2.0.1 interactive-surface-css@1.2.5 ``` ## Quick Start @@ -592,7 +592,7 @@ The check command builds `dist/`, runs Stylelint, runs contract tests, runs resp Before publishing: ```bash -npm view layout-style-css@1.1.0 version --json +npm view layout-style-css@1.1.1 version --json npm run release:verify npm audit --audit-level=moderate ``` @@ -602,7 +602,7 @@ Publish and verify: ```bash npm login npm publish --access public -npm view layout-style-css@1.1.0 +npm view layout-style-css@1.1.1 ``` After publish, verify these CDN URLs: @@ -612,7 +612,7 @@ https://unpkg.com/layout-style-css@1/dist/layout-style-css.min.css https://cdn.jsdelivr.net/npm/layout-style-css@1/dist/layout-style-css.min.css ``` -Tag the release as `v1.1.0` in `Foscat/layout-style-css`. +Tag the release as `v1.1.1` in `Foscat/layout-style-css`. The npm publish workflow runs when that release is published and can be recovered manually from Actions with `release_tag` set to `v1.1.1`. ## Compatibility diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md index cbecdae..e3951a4 100644 --- a/docs/wiki/Home.md +++ b/docs/wiki/Home.md @@ -1,6 +1,6 @@ # Layout Style CSS Wiki -Version 1.1.0 documents the professional library contract for `layout-style-css`: install paths, package exports, layout primitives, recipes, UI Style Kit compatibility, demo deployment, security, and release workflow. +Version 1.1.1 documents the professional library contract for `layout-style-css`: install paths, package exports, layout primitives, recipes, UI Style Kit compatibility, demo deployment, security, and release workflow. ## Start Here @@ -13,7 +13,7 @@ Version 1.1.0 documents the professional library contract for `layout-style-css` | [Layout Styles](Layout-Styles.md) | All layout personalities and when to use them. | | [UI Style Kit Compatibility](UI-Style-Kit-Compatibility.md) | Prefix aliases and ownership boundaries. | | [Demo And GitHub Pages](Demo-And-GitHub-Pages.md) | Demo QA and Pages deployment. | -| [Release And Publishing](Release-And-Publishing.md) | npm v1.1.0 verification and publish checklist. | +| [Release And Publishing](Release-And-Publishing.md) | npm v1.1.1 verification and publish checklist. | | [Security And Support](Security-And-Support.md) | Security model, supported versions, and reporting path. | | [Contributing](Contributing.md) | Contribution workflow and review expectations. | diff --git a/docs/wiki/Release-And-Publishing.md b/docs/wiki/Release-And-Publishing.md index 22bfe25..a942c87 100644 --- a/docs/wiki/Release-And-Publishing.md +++ b/docs/wiki/Release-And-Publishing.md @@ -1,12 +1,12 @@ # Release And Publishing -This page is the release checklist for `layout-style-css@1.1.0`. +This page is the release checklist for `layout-style-css@1.1.1`. ## Version Contract -- `package.json` version is `1.1.0`. -- `package-lock.json` is synchronized with `1.1.0`. -- `CHANGELOG.md` contains a `1.1.0` entry. +- `package.json` version is `1.1.1`. +- `package-lock.json` is synchronized with `1.1.1`. +- `CHANGELOG.md` contains a `1.1.1` entry. - README and wiki docs link to the current public API. ## Verification @@ -30,7 +30,7 @@ Expected result: every command exits with status `0`. `git diff --check` may pri Before publishing, confirm npm does not already have the target version: ```bash -npm view layout-style-css@1.1.0 version --json +npm view layout-style-css@1.1.1 version --json ``` Publish: @@ -43,7 +43,7 @@ npm publish --access public Verify: ```bash -npm view layout-style-css@1.1.0 +npm view layout-style-css@1.1.1 ``` ## Tag @@ -51,10 +51,12 @@ npm view layout-style-css@1.1.0 Tag the release: ```bash -git tag v1.1.0 -git push origin v1.1.0 +git tag v1.1.1 +git push origin v1.1.1 ``` +The npm publish workflow runs when the `v1.1.1` GitHub release is published. If the release event needs to be replayed, run the `Node.js Package` workflow manually from the default branch with `release_tag` set to `v1.1.1`. + ## GitHub Wiki Mirror If the repository wiki is enabled, mirror `docs/wiki/*.md` into: diff --git a/package-lock.json b/package-lock.json index ff258e0..9082b06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "layout-style-css", - "version": "1.1.0", + "version": "1.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "layout-style-css", - "version": "1.1.0", + "version": "1.1.1", "license": "MIT", "devDependencies": { "@playwright/test": "1.61.1", diff --git a/package.json b/package.json index 65fdebd..5e7d3a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "layout-style-css", - "version": "1.1.0", + "version": "1.1.1", "description": "Shell-first CSS layout primitives that complement ui-style-kit-css@2.0.1.", "type": "module", "license": "MIT", diff --git a/test/demo-smoke.test.mjs b/test/demo-smoke.test.mjs index 85c96d2..d007c55 100644 --- a/test/demo-smoke.test.mjs +++ b/test/demo-smoke.test.mjs @@ -1,4 +1,4 @@ -import { createReadStream, existsSync } from "node:fs"; +import { createReadStream, existsSync, mkdirSync } from "node:fs"; import { createServer } from "node:http"; import { extname, join, normalize, sep } from "node:path"; import { fileURLToPath } from "node:url"; @@ -7,6 +7,7 @@ import { chromium } from "@playwright/test"; const root = normalize(fileURLToPath(new URL("..", import.meta.url))).replace(/[\\/]$/, ""); const demoPath = join(root, "demo", "index.html"); +const testTempDir = join(root, ".tmp", "playwright"); const uiKitCssPath = join( root, "node_modules", @@ -15,6 +16,11 @@ const uiKitCssPath = join( "ui-style-kit.with-bridge.min.css" ); +// Keep Playwright artifacts inside the repository workspace for locked-down Windows runners. +mkdirSync(testTempDir, { recursive: true }); +process.env.TEMP = testTempDir; +process.env.TMP = testTempDir; + const mimeTypes = new Map([ [".css", "text/css; charset=utf-8"], [".html", "text/html; charset=utf-8"], diff --git a/test/layout-css-contract.test.mjs b/test/layout-css-contract.test.mjs index ff3ae25..8aaa5e4 100644 --- a/test/layout-css-contract.test.mjs +++ b/test/layout-css-contract.test.mjs @@ -7,6 +7,7 @@ import assert from "node:assert/strict"; const root = fileURLToPath(new URL("..", import.meta.url)); const dist = join(root, "dist"); const styles = join(root, "styles"); +const npmPublishWorkflowPath = join(root, ".github", "workflows", "npm-publish.yml"); const requiredFiles = [ "layout-base.css", @@ -622,7 +623,7 @@ assert(!minified.includes("@import"), "Minified bundle must be layout-only and f const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); assert.equal(packageJson.name, "layout-style-css"); -assert.equal(packageJson.version, "1.1.0"); +assert.equal(packageJson.version, "1.1.1"); assert.equal(packageJson.license, "MIT"); assert.equal(packageJson.private, undefined); assert.equal(packageJson.description.includes("ui-style-kit-css@2.0.1"), true); @@ -881,8 +882,8 @@ for (const link of readmeLinks.filter(isLocalMarkdownLink)) { const changelog = readFileSync(join(root, "CHANGELOG.md"), "utf8"); assert(changelog.includes("# Changelog"), "CHANGELOG.md should use a standard changelog heading"); assert( - changelog.includes("## [1.1.0] - 2026-07-05"), - "CHANGELOG.md should describe the 1.1.0 release candidate" + changelog.includes("## [1.1.1] - 2026-07-05"), + "CHANGELOG.md should describe the 1.1.1 release candidate" ); assert(changelog.includes("F-Pattern"), "CHANGELOG.md should mention the new F-Pattern layout"); assert(changelog.includes("Synthwave"), "CHANGELOG.md should mention the new Synthwave layout"); @@ -891,7 +892,7 @@ assert(changelog.includes("wiki"), "CHANGELOG.md should mention the new wiki doc const wikiHome = readFileSync(join(root, "docs/wiki/Home.md"), "utf8"); assert(wikiHome.includes("# Layout Style CSS Wiki"), "Wiki home should use a clear product heading"); -assert(wikiHome.includes("Version 1.1.0"), "Wiki home should identify the documented release"); +assert(wikiHome.includes("Version 1.1.1"), "Wiki home should identify the documented release"); for (const file of requiredDocumentationFiles.filter((file) => file.startsWith("docs/wiki/"))) { const content = readFileSync(join(root, file), "utf8"); assert(content.includes("# "), `${file} should include a top-level heading`); @@ -905,6 +906,33 @@ for (const file of requiredDocumentationFiles.filter((file) => file.startsWith(" } } +const npmPublishWorkflow = readFileSync(npmPublishWorkflowPath, "utf8"); +assert( + npmPublishWorkflow.includes("types: [published]") && !npmPublishWorkflow.includes("types: [created]"), + "npm publish workflow should publish from public release events, not draft release creation" +); +assert( + npmPublishWorkflow.includes("workflow_dispatch:") && + npmPublishWorkflow.includes("release_tag:") && + npmPublishWorkflow.includes('description: "Release tag to publish, for example v1.1.1"'), + "npm publish workflow should expose a manual recovery dispatch with an explicit release tag" +); +assert( + npmPublishWorkflow.includes("ref: ${{ github.event.inputs.release_tag || github.event.release.tag_name }}"), + "npm publish workflow should check out the selected release tag" +); +assert( + npmPublishWorkflow.includes('node-version: 22') && + npmPublishWorkflow.includes("npm run check") && + npmPublishWorkflow.includes("npm publish --access public"), + "npm publish workflow should verify and publish with the supported Node runtime" +); +assert( + npmPublishWorkflow.includes('if [ "v${PACKAGE_VERSION}" != "$RELEASE_TAG" ]; then') && + npmPublishWorkflow.includes("NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}"), + "npm publish workflow should verify tag/package alignment and use the standard npm token secret" +); + const expectedPackFiles = [ "CHANGELOG.md", "CONTRIBUTING.md",