diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ddcf35..88e47a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,61 +1,72 @@ -name: CI +name: Teradata web design system CI on: - push: - branches: - - main pull_request: - branches: '*' + branches: [main, beta] -permissions: - actions: read - contents: read +env: + NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} jobs: - quality: + lint: runs-on: ubuntu-latest + steps: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - run: npm ci + - run: npm run format:check -- --base=${{ github.event.pull_request.base.sha }} + - run: npx nx affected --target=scsslint --base=${{ github.event.pull_request.base.sha }} + - run: npx nx affected --target=lint --base=${{ github.event.pull_request.base.sha }} - # Connect your workspace on nx.app and uncomment this to enable task distribution. - # The "--stop-agents-after" is optional, but allows idle agents to shut down once the "e2e-ci" targets have been requested - # - run: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="e2e-ci" + test: + runs-on: ubuntu-latest - # Cache node_modules - - uses: actions/setup-node@v3 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Use Node.js 20 + uses: actions/setup-node@v4 with: node-version: 20 - cache: 'npm' + cache: npm - run: npm ci - - uses: nrwl/nx-set-shas@v4 - - # Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud - # - run: npx nx-cloud record -- echo Hello World - - run: npx nx affected -t lint test build e2e-ci + - run: npx nx affected --target=test --base=${{ github.event.pull_request.base.sha }} - publish: + e2e: runs-on: ubuntu-latest - permissions: - packages: write - contents: write - if: ${{ github.ref == 'refs/heads/main' }} - needs: [quality] + steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Use Node.js 20 - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20 - cache: 'npm' + cache: npm - run: npm ci - - uses: nrwl/nx-set-shas@v4 + - run: NODE_OPTIONS=--max_old_space_size=4096 npx nx affected --target=e2e --base=${{ github.event.pull_request.base.sha }} + + build: + runs-on: ubuntu-latest - - run: npm run semantic-release - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GH }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - run: npm ci + - run: npx nx affected --target=build --base=${{ github.event.pull_request.base.sha }} + - run: npx nx affected --target=build-scss --base=${{ github.event.pull_request.base.sha }} diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index cfb75b2..3b9e308 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v4 # Set up Node - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1a7ac58 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: Release + +on: + push: + branches: [main, beta] + +jobs: + release: + name: Release + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - name: Install dependencies + run: npm ci + - name: Release + env: + GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GH }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npx semantic-release@23.0.8 diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..e9ee3cb --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true \ No newline at end of file diff --git a/.releaserc b/.releaserc new file mode 100644 index 0000000..8697f62 --- /dev/null +++ b/.releaserc @@ -0,0 +1,35 @@ +{ + "plugins": [ + ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }], + ["@semantic-release/release-notes-generator"], + ["@semantic-release/changelog",{ + "changelogFile": "docs/CHANGELOG.md" + }], + ["@semantic-release/npm", { + "npmPublish": false, + "tarballDir": "dist/libs" + }], + ["@semantic-release/exec", { + "prepareCmd": "npm run release:prepare", + "publishCmd": "./scripts/npm-publish ${nextRelease.channel}" + }], + ["@semantic-release/git", { + "message": "ci(release): ${nextRelease.version} [skip ci]", + "assets": [ + "docs/CHANGELOG.md", + "package.json", + "package-lock.json" + ] + }], + ["@semantic-release/github", { + "assets": ["dist/libs/*.tgz"] + }] + ], + "branches": [{ + "name": "beta", + "prerelease": true, + "channel": "next" + },{ + "name": "main" + }] +} \ No newline at end of file diff --git a/libs/react-components/package.json b/libs/react-components/package.json index 716bb02..52edb67 100644 --- a/libs/react-components/package.json +++ b/libs/react-components/package.json @@ -1,6 +1,6 @@ { "name": "@teradata-web/react-components", - "version": "1.0.0", + "version": "0.0.0-TERADATA-WEB", "main": "./index.js", "types": "./index.d.ts", "exports": { diff --git a/package-lock.json b/package-lock.json index 99d7f04..fe15bea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "@teradata/web-design-system", + "name": "@teradata-web", "version": "0.0.0-development", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@teradata/web-design-system", + "name": "@teradata-web", "version": "0.0.0-development", "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index bb9f566..d9ac476 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "license": "MIT", "scripts": { "semantic-release": "semantic-release --branches main", - "build-storybook": "nx run react-components:build-storybook" + "build-storybook": "nx run react-components:build-storybook", + "format:check": "nx format" }, "dependencies": { "react": "18.3.1", diff --git a/scripts/npm-publish b/scripts/npm-publish new file mode 100755 index 0000000..6efa218 --- /dev/null +++ b/scripts/npm-publish @@ -0,0 +1,20 @@ +#!/bin/bash +scope=@terdata-web +tag=latest + +[[ $1 = 'next' ]] && tag=next || tag=latest + +echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >.npmrc + +for package in ./dist/libs/* +do + if [ -d ${package} ] + then + npm publish ${package} --access=public --tag=$tag --ignore-scripts; + fi +done + +rm .npmrc + +echo "Published successfully [scope: $scope]. Use 'npm install [package-name]' in the project you want to use it." +exit 0 \ No newline at end of file diff --git a/scripts/version-placeholder.js b/scripts/version-placeholder.js new file mode 100644 index 0000000..9fdbee7 --- /dev/null +++ b/scripts/version-placeholder.js @@ -0,0 +1,77 @@ +const platform = require('os').platform; +const readFileSync = require('fs').readFileSync; +const writeFileSync = require('fs').writeFileSync; +const spawnSync = require('child_process').spawnSync; +const packageJson = require('../package.json'); +const args = process.argv.slice(2); + +const placeholders = [ + ['0.0.0-TERADATA-WEB', packageJson.version], + ['0.0.0-TSLIB', packageJson.dependencies['tslib']], +]; +console.log('Replacing placeholders: ', placeholders); + +/** RegExps that match version placeholders inside of a file. */ +const placeholderRegexes = placeholders.map( + (placeholder) => new RegExp(placeholder[0], 'g') +); +/** + * Walks through every file in a directory and replaces the version placeholders + */ +function replaceVersionPlaceholders(packageDir = 'dist') { + // Resolve files that contain version placeholders using Grep or Findstr since those are + // extremely fast and also have a very simple usage. + const files = findFilesWithPlaceholders(packageDir); + + // Walk through every file that contains version placeholders and replace those with the current + // version of the root package.json file. + + files.forEach((filePath) => { + const fileContent = placeholderRegexes.reduce( + (accumulator, currentValue, currentIndex) => + accumulator.replace(currentValue, placeholders[currentIndex][1]), + readFileSync(filePath, 'utf-8') + ); + + console.log(`Replacing placeholder in ${filePath}`); + + writeFileSync(filePath, fileContent); + }); +} + +/** Finds all files in the specified package dir where version placeholders are included. */ +function findFilesWithPlaceholders(packageDir) { + const findCommand = buildPlaceholderFindCommand(packageDir); + + console.log(`Finding files in ${packageDir}`); + + return spawnSync(findCommand.binary, findCommand.args) + .stdout.toString() + .split(/[\n\r]/) + .filter(String); +} + +/** Builds the command that will be executed to find all files containing version placeholders. */ +function buildPlaceholderFindCommand(packageDir) { + if (platform() === 'win32') { + return { + binary: 'findstr', + args: [ + '/msi', + placeholders.map((item) => item[0]).join(' '), + `${packageDir}\\*`, + ], + }; + } else { + return { + binary: 'grep', + args: [ + '-ril', + placeholders.map((item) => item[0]).join(`\\|`), + packageDir, + ], + }; + } +} + +replaceVersionPlaceholders(args[0]);