From 60397b15a82b7d567246756a8a8f0858eb861bf5 Mon Sep 17 00:00:00 2001 From: FineArchs Date: Tue, 14 May 2024 17:52:37 +0900 Subject: [PATCH 1/5] create pre-release workflow --- .github/workflows/publish-nightly-next.yml | 56 ------------ ...sh-nightly-dev.yml => publish-nightly.yml} | 27 +++--- CHANGELOG.md | 12 --- package-lock.json | 75 ++++++++++++---- package.json | 5 +- scripts/check-release.mjs | 8 ++ scripts/gen-pkg-ts.mjs | 4 +- scripts/pre-release.mjs | 86 +++++++++++++++++++ unreleased/.gitkeep | 0 unreleased/past.md | 10 +++ 10 files changed, 187 insertions(+), 96 deletions(-) delete mode 100644 .github/workflows/publish-nightly-next.yml rename .github/workflows/{publish-nightly-dev.yml => publish-nightly.yml} (67%) create mode 100644 scripts/check-release.mjs create mode 100644 scripts/pre-release.mjs create mode 100644 unreleased/.gitkeep create mode 100644 unreleased/past.md diff --git a/.github/workflows/publish-nightly-next.yml b/.github/workflows/publish-nightly-next.yml deleted file mode 100644 index 62110872..00000000 --- a/.github/workflows/publish-nightly-next.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Publish nightly (next) - -on: - schedule: - - cron: '50 18 * * *' - workflow_dispatch: - -jobs: - publish: - runs-on: ubuntu-latest - env: - NPM_SECRET: ${{ secrets.NPM_SECRET }} - BRANCH: aiscript-next - TAG: next - - steps: - - name: Checkout - uses: actions/checkout@v4.1.5 - with: - ref: ${{ env.BRANCH }} - - - name: Setup Node.js - uses: actions/setup-node@v4.0.2 - with: - node-version: 20.x - - - name: Cache dependencies - uses: actions/cache@v4 - with: - path: ~/.npm - key: npm-${{ hashFiles('package-lock.json') }} - restore-keys: npm- - - - name: Install dependencies - run: npm ci - - - name: Build - run: npm run build - - - name: Set Version - run: | - TIME_STAMP=$( date +'%Y%m%d' ) - VERSION_SUFFIX=-$TAG.$TIME_STAMP - vim package.json '+/"version"' '+s/:\s*".*\zs\ze"/'$VERSION_SUFFIX/ '+wq' - - - name: Check Commits - run: | - echo 'LAST_COMMITS='$( git log --since '24 hours ago' | wc -c ) >> $GITHUB_ENV - - - name: Publish - uses: JS-DevTools/npm-publish@v3 - if: ${{ env.NPM_SECRET != '' && env.LAST_COMMITS != 0 }} - with: - token: ${{ env.NPM_SECRET }} - tag: ${{ env.TAG }} - access: public diff --git a/.github/workflows/publish-nightly-dev.yml b/.github/workflows/publish-nightly.yml similarity index 67% rename from .github/workflows/publish-nightly-dev.yml rename to .github/workflows/publish-nightly.yml index caff8cd9..40206904 100644 --- a/.github/workflows/publish-nightly-dev.yml +++ b/.github/workflows/publish-nightly.yml @@ -1,4 +1,4 @@ -name: Publish nightly (dev) +name: Publish nightly on: schedule: @@ -8,16 +8,22 @@ on: jobs: publish: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - branch: master + tag: dev + - branch: aiscript-next + tag: next env: NPM_SECRET: ${{ secrets.NPM_SECRET }} - BRANCH: master - TAG: dev steps: - - name: Checkout + - name: Checkout ${{ matrix.branch }} uses: actions/checkout@v4.1.5 with: - ref: ${{ env.BRANCH }} + ref: ${{ matrix.branch }} - name: Setup Node.js uses: actions/setup-node@v4.0.2 @@ -34,23 +40,24 @@ jobs: - name: Install dependencies run: npm ci - - name: Build - run: npm run build - - name: Set Version run: | + CURRENT_VER=$(npm view 'file:.' version) TIME_STAMP=$( date +'%Y%m%d' ) VERSION_SUFFIX=-$TAG.$TIME_STAMP - vim package.json '+/"version"' '+s/:\s*".*\zs\ze"/'$VERSION_SUFFIX/ '+wq' + echo 'NEWVERSION='$CURRENT_VER-${{ matrix.tag }}.$TIME_STAMP >> $GITHUB_ENV - name: Check Commits run: | echo 'LAST_COMMITS='$( git log --since '24 hours ago' | wc -c ) >> $GITHUB_ENV + - name: Prepare Publish + run: npm run pre-release + - name: Publish uses: JS-DevTools/npm-publish@v3 if: ${{ env.NPM_SECRET != '' && env.LAST_COMMITS != 0 }} with: token: ${{ env.NPM_SECRET }} - tag: ${{ env.TAG }} + tag: ${{ matrix.tag }} access: public diff --git a/CHANGELOG.md b/CHANGELOG.md index 65815163..bc8ae5f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,5 @@ [Read translated version (en)](./translations/en/CHANGELOG.md) -# 未リリース分 -- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正 -- シンタックスエラーなどの位置情報を修正 -- `arr.reduce`が空配列に対して初期値なしで呼び出された時、正式にエラーを出すよう -- `str.pad_start`,`str.pad_end`を追加 -- `arr.insert`,`arr.remove`を追加 -- `arr.sort`の処理を非同期的にして高速化 -- `arr.flat`,`arr.flat_map`を追加 -- `Uri:encode_full`, `Uri:encode_component`, `Uri:decode_full`, `Uri:decode_component`を追加 -- `str.starts_with`,`str.ends_with`を追加 -- `arr.splice`を追加 - # 0.18.0 - `Core:abort`でプログラムを緊急停止できるように - `index_of`の配列版を追加 diff --git a/package-lock.json b/package-lock.json index 5d153106..15b55102 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@syuilo/aiscript", - "version": "0.18.0", + "version": "0.19.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@syuilo/aiscript", - "version": "0.18.0", + "version": "0.19.0", "license": "MIT", "dependencies": { "seedrandom": "3.0.5", @@ -27,6 +27,7 @@ "eslint-plugin-import": "2.29.1", "jest": "29.7.0", "peggy": "4.0.2", + "semver": "7.6.2", "ts-jest": "29.1.2", "ts-jest-resolver": "2.0.1", "ts-node": "10.9.2", @@ -1504,6 +1505,21 @@ "node": "*" } }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@microsoft/tsdoc": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", @@ -1619,6 +1635,21 @@ } } }, + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@rushstack/rig-package": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz", @@ -7178,13 +7209,10 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -9360,6 +9388,15 @@ "requires": { "brace-expansion": "^1.1.7" } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -9462,6 +9499,17 @@ "resolve": "~1.22.1", "semver": "~7.5.4", "z-schema": "~5.0.2" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "@rushstack/rig-package": { @@ -13540,13 +13588,10 @@ "version": "3.0.5" }, "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true }, "shebang-command": { "version": "2.0.0", diff --git a/package.json b/package.json index 273c1231..7e069506 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,9 @@ "lint": "eslint . --ext .js,.jsx,.ts,.tsx", "jest": "jest --coverage --detectOpenHandles", "tsd": "tsd", - "test": "npm run jest" + "test": "npm run jest", + "pre-release": "node scripts/pre-release.mjs && npm run build", + "prepublishOnly": "node scripts/check-release.mjs" }, "devDependencies": { "@microsoft/api-extractor": "7.42.3", @@ -49,6 +51,7 @@ "eslint-plugin-import": "2.29.1", "jest": "29.7.0", "peggy": "4.0.2", + "semver": "7.6.2", "ts-jest": "29.1.2", "ts-jest-resolver": "2.0.1", "ts-node": "10.9.2", diff --git a/scripts/check-release.mjs b/scripts/check-release.mjs new file mode 100644 index 00000000..4d218aeb --- /dev/null +++ b/scripts/check-release.mjs @@ -0,0 +1,8 @@ +import { readdir } from 'node:fs/promises'; + +await readdir('./unreleased') + .then(pathes => { + if (pathes.length > 1 || (pathes.length === 1 && pathes[0] !== '.gitkeep')) throw new Error('Run "npm run pre-release" before publish.') + }, err => { + if (err.code !== 'ENOENT') throw err; + }); diff --git a/scripts/gen-pkg-ts.mjs b/scripts/gen-pkg-ts.mjs index f6d757a3..2e22d069 100644 --- a/scripts/gen-pkg-ts.mjs +++ b/scripts/gen-pkg-ts.mjs @@ -1,6 +1,6 @@ -import { writeFile } from 'node:fs/promises'; -import pkg from '../package.json' assert { type: 'json' }; +import { readFile, writeFile } from 'node:fs/promises'; +const pkg = JSON.parse((await readFile('./package.json', 'utf8'))); await writeFile('./src/pkg.ts', `/* This file is automatically generated by scripts/gen-pkg-ts.js. diff --git a/scripts/pre-release.mjs b/scripts/pre-release.mjs new file mode 100644 index 00000000..65afe0cb --- /dev/null +++ b/scripts/pre-release.mjs @@ -0,0 +1,86 @@ +import { readFile, readdir, writeFile, mkdir, rm } from 'node:fs/promises'; +import { env } from 'node:process'; +import semverValid from 'semver/functions/valid.js'; + + +function validateEnv(name, validater) { + let val = env[name]; + if (!val) throw new Error(`$${name} required`); + if (!validater(val)) throw new Error(`${val} is not valid as $${name}`); + return val; +} +/* + * Required Environment Variables + */ +const e = { + newver: validateEnv("NEWVERSION", v => semverValid(v)), +}; + + +const FILES = { + chlog: './CHANGELOG.md', + chlogs: './unreleased', + pkgjson: './package.json', +}; +const enc = { encoding: env.ENCODING ?? 'utf8' }; +const actions = {}; + +/* + * Update package.json's version field + */ +actions.updatePackageJson = { + async read() { + const json = await readFile(FILES.pkgjson, enc); + return JSON.stringify( + { ...JSON.parse(json), version: e.newver }, + null, '\t' + ); + }, + async write(json) { + return writeFile(FILES.pkgjson, json); + }, +}; + +/* + * Collect changelogs + */ +actions.collectChangeLogs = { + async read() { + const getNewLog = async () => { + const pathes = await readdir(FILES.chlogs); + const logPromises = pathes.map(path => readFile(`${FILES.chlogs}/${path}`, enc)); + const logs = await Promise.all(logPromises); + return logs.map(v => v.trim()).join('\n'); + }; + const getOldLog = async () => { + const log = await readFile(FILES.chlog, enc); + const idx = log.indexOf('#'); + return [ + log.slice(0, idx), + log.slice(idx), + ]; + }; + const [newLog, [logHead, oldLog]] = await Promise.all([ getNewLog(), getOldLog() ]); + return `${logHead}# ${e.newver}\n${newLog}\n\n${oldLog}`; + + }, + async write(logs) { + return Promise.all([ + writeFile(FILES.chlog, logs), + rm(FILES.chlogs, { + recursive: true, + force: true, + }).then(() => + mkdir(FILES.chlogs) + ).then(() => + writeFile(`${FILES.chlogs}/.gitkeep`, '')) + ]); + }, +}; + +// read all before writing +const reads = await Promise.all(Object.entries(actions).map(async ([name, { read }]) => [name, await read().catch(err => { throw new Error(`in actions.${name}.read: ${err}`) })])); + +// write after reading all +await Promise.all(reads.map(([name, read]) => actions[name].write(read).catch(err => { throw new Error(`in actions.${name}.write: ${err}`) }))); + diff --git a/unreleased/.gitkeep b/unreleased/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/unreleased/past.md b/unreleased/past.md new file mode 100644 index 00000000..52191011 --- /dev/null +++ b/unreleased/past.md @@ -0,0 +1,10 @@ +- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正 +- シンタックスエラーなどの位置情報を修正 +- `arr.reduce`が空配列に対して初期値なしで呼び出された時、正式にエラーを出すよう +- `str.pad_start`,`str.pad_end`を追加 +- `arr.insert`,`arr.remove`を追加 +- `arr.sort`の処理を非同期的にして高速化 +- `arr.flat`,`arr.flat_map`を追加 +- `Uri:encode_full`, `Uri:encode_component`, `Uri:decode_full`, `Uri:decode_component`を追加 +- `str.starts_with`,`str.ends_with`を追加 +- `arr.splice`を追加 From 661c74e45ac14e490a036287620eb0b445f8f3a3 Mon Sep 17 00:00:00 2001 From: Fine Archs Date: Tue, 14 May 2024 18:28:04 +0900 Subject: [PATCH 2/5] refactor --- scripts/pre-release.mjs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/scripts/pre-release.mjs b/scripts/pre-release.mjs index 65afe0cb..b0435ed5 100644 --- a/scripts/pre-release.mjs +++ b/scripts/pre-release.mjs @@ -3,32 +3,20 @@ import { env } from 'node:process'; import semverValid from 'semver/functions/valid.js'; -function validateEnv(name, validater) { - let val = env[name]; - if (!val) throw new Error(`$${name} required`); - if (!validater(val)) throw new Error(`${val} is not valid as $${name}`); - return val; -} -/* - * Required Environment Variables - */ -const e = { - newver: validateEnv("NEWVERSION", v => semverValid(v)), -}; - - const FILES = { chlog: './CHANGELOG.md', chlogs: './unreleased', pkgjson: './package.json', }; const enc = { encoding: env.ENCODING ?? 'utf8' }; +const newver = env.NEWVERSION; +if (newver && !semverValid(newver)) throw new Error(`Environment variable NEWVERSION is set to "${newver}"; It is not valid`); const actions = {}; /* * Update package.json's version field */ -actions.updatePackageJson = { +if (newver) actions.updatePackageJson = { async read() { const json = await readFile(FILES.pkgjson, enc); return JSON.stringify( From 60c10f0f1c52d4d46b5a258ca6fdf7f175a63ea9 Mon Sep 17 00:00:00 2001 From: Fine Archs Date: Tue, 14 May 2024 18:29:38 +0900 Subject: [PATCH 3/5] fix --- scripts/pre-release.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/pre-release.mjs b/scripts/pre-release.mjs index b0435ed5..34226a97 100644 --- a/scripts/pre-release.mjs +++ b/scripts/pre-release.mjs @@ -20,7 +20,7 @@ if (newver) actions.updatePackageJson = { async read() { const json = await readFile(FILES.pkgjson, enc); return JSON.stringify( - { ...JSON.parse(json), version: e.newver }, + { ...JSON.parse(json), version: newver }, null, '\t' ); }, @@ -49,7 +49,7 @@ actions.collectChangeLogs = { ]; }; const [newLog, [logHead, oldLog]] = await Promise.all([ getNewLog(), getOldLog() ]); - return `${logHead}# ${e.newver}\n${newLog}\n\n${oldLog}`; + return `${logHead}# ${newver}\n${newLog}\n\n${oldLog}`; }, async write(logs) { From 035ed66646fc386aca13325d6d388850fb731de2 Mon Sep 17 00:00:00 2001 From: Fine Archs Date: Thu, 16 May 2024 06:43:36 +0900 Subject: [PATCH 4/5] time order --- scripts/pre-release.mjs | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/scripts/pre-release.mjs b/scripts/pre-release.mjs index 34226a97..1dfd7dfb 100644 --- a/scripts/pre-release.mjs +++ b/scripts/pre-release.mjs @@ -1,26 +1,40 @@ import { readFile, readdir, writeFile, mkdir, rm } from 'node:fs/promises'; import { env } from 'node:process'; +import { promisify } from 'node:util'; +import child_process from 'node:child_process'; import semverValid from 'semver/functions/valid.js'; +const exec = promisify(child_process.exec); const FILES = { chlog: './CHANGELOG.md', chlogs: './unreleased', pkgjson: './package.json', }; const enc = { encoding: env.ENCODING ?? 'utf8' }; -const newver = env.NEWVERSION; -if (newver && !semverValid(newver)) throw new Error(`Environment variable NEWVERSION is set to "${newver}"; It is not valid`); +const pkgjson = JSON.parse(await readFile(FILES.pkgjson, enc)); +const newver = (() => { + const newverCandidates = [ + [env.NEWVERSION, 'Environment variable NEWVERSION'], + [pkgjson.version, "Package.json's version field"], + ]; + for (const [ver, name] of newverCandidates) { + if (ver) { + if (semverValid(ver)) return ver; + else throw new Error(`${name} is set to "${ver}"; it is not valid`); + } + } + throw new Error('No effective version setting detected.'); +})(); const actions = {}; /* * Update package.json's version field */ -if (newver) actions.updatePackageJson = { +actions.updatePackageJson = { async read() { - const json = await readFile(FILES.pkgjson, enc); return JSON.stringify( - { ...JSON.parse(json), version: newver }, + { ...pkgjson, version: newver }, null, '\t' ); }, @@ -35,8 +49,21 @@ if (newver) actions.updatePackageJson = { actions.collectChangeLogs = { async read() { const getNewLog = async () => { - const pathes = await readdir(FILES.chlogs); - const logPromises = pathes.map(path => readFile(`${FILES.chlogs}/${path}`, enc)); + const pathes = (await readdir(FILES.chlogs)).map(path => `${FILES.chlogs}/${path}`); + const pathesLastUpdate = await Promise.all( + pathes.map(async (path) => { + const gittime = Number((await exec( + `git log -1 --pretty="format:%ct" "${path}"` + )).stdout); + if (gittime) return { path, lastUpdate: gittime }; + else { + console.log(`Warning: git timestamp of "${path}" was not detected`); + return { path, lastUpdate: Infinity } + } + }) + ); + pathesLastUpdate.sort((a, b) => a.lastUpdate - b.lastUpdate); + const logPromises = pathesLastUpdate.map(({ path }) => readFile(path, enc)); const logs = await Promise.all(logPromises); return logs.map(v => v.trim()).join('\n'); }; From 9308ecb53b60ea29acbdcc09d8155f85c11cf0b2 Mon Sep 17 00:00:00 2001 From: FineArchs <133759614+FineArchs@users.noreply.github.com> Date: Thu, 16 May 2024 21:13:53 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E6=B6=88=E3=81=97=E5=BF=98=E3=82=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/publish-nightly.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/publish-nightly.yml b/.github/workflows/publish-nightly.yml index 40206904..6669ba33 100644 --- a/.github/workflows/publish-nightly.yml +++ b/.github/workflows/publish-nightly.yml @@ -44,7 +44,6 @@ jobs: run: | CURRENT_VER=$(npm view 'file:.' version) TIME_STAMP=$( date +'%Y%m%d' ) - VERSION_SUFFIX=-$TAG.$TIME_STAMP echo 'NEWVERSION='$CURRENT_VER-${{ matrix.tag }}.$TIME_STAMP >> $GITHUB_ENV - name: Check Commits