Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop
This commit is contained in:
commit
fc4c868269
|
@ -0,0 +1,43 @@
|
||||||
|
name: Check the description in CHANGELOG.md
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-changelog:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout head
|
||||||
|
uses: actions/checkout@v4.1.1
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4.0.1
|
||||||
|
with:
|
||||||
|
node-version-file: '.node-version'
|
||||||
|
|
||||||
|
- name: Checkout base
|
||||||
|
run: |
|
||||||
|
mkdir _base
|
||||||
|
cp -r .git _base/.git
|
||||||
|
cd _base
|
||||||
|
git fetch --depth 1 origin ${{ github.base_ref }}
|
||||||
|
git checkout origin/${{ github.base_ref }} CHANGELOG.md
|
||||||
|
|
||||||
|
- name: Copy to Checker directory for CHANGELOG-base.md
|
||||||
|
run: cp _base/CHANGELOG.md scripts/changelog-checker/CHANGELOG-base.md
|
||||||
|
- name: Copy to Checker directory for CHANGELOG-head.md
|
||||||
|
run: cp CHANGELOG.md scripts/changelog-checker/CHANGELOG-head.md
|
||||||
|
- name: diff
|
||||||
|
continue-on-error: true
|
||||||
|
run: diff -u CHANGELOG-base.md CHANGELOG-head.md
|
||||||
|
working-directory: scripts/changelog-checker
|
||||||
|
|
||||||
|
- name: Setup Checker
|
||||||
|
run: npm install
|
||||||
|
working-directory: scripts/changelog-checker
|
||||||
|
- name: Run Checker
|
||||||
|
run: npm run run
|
||||||
|
working-directory: scripts/changelog-checker
|
|
@ -21,6 +21,7 @@
|
||||||
### Client
|
### Client
|
||||||
- Feat: 新しいゲームを追加
|
- Feat: 新しいゲームを追加
|
||||||
- Feat: 絵文字の詳細ダイアログを追加
|
- Feat: 絵文字の詳細ダイアログを追加
|
||||||
|
- Feat: 枠線をつけるMFM`$[border.width=1,style=solid,color=fff,radius=0 ...]`を追加
|
||||||
- Enhance: ハッシュタグ入力時に、本文の末尾の行に何も書かれていない場合は新たにスペースを追加しないように
|
- Enhance: ハッシュタグ入力時に、本文の末尾の行に何も書かれていない場合は新たにスペースを追加しないように
|
||||||
- Enhance: チャンネルノートのピン留めをノートのメニューからできるように
|
- Enhance: チャンネルノートのピン留めをノートのメニューからできるように
|
||||||
- Enhance: 管理者の場合はAPI tokenの発行画面で管理機能に関する権限を付与できるように
|
- Enhance: 管理者の場合はAPI tokenの発行画面で管理機能に関する権限を付与できるように
|
||||||
|
|
|
@ -62,6 +62,11 @@ export default function(props: MfmProps, context: SetupContext<MfmEvents>) {
|
||||||
return t.match(/^[0-9.]+s$/) ? t : null;
|
return t.match(/^[0-9.]+s$/) ? t : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validColor = (c: string | null | undefined): string | null => {
|
||||||
|
if (c == null) return null;
|
||||||
|
return c.match(/^[0-9a-f]{3,6}$/i) ? c : null;
|
||||||
|
};
|
||||||
|
|
||||||
const useAnim = defaultStore.state.advancedMfm && defaultStore.state.animatedMfm;
|
const useAnim = defaultStore.state.advancedMfm && defaultStore.state.animatedMfm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -240,17 +245,30 @@ export default function(props: MfmProps, context: SetupContext<MfmEvents>) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'fg': {
|
case 'fg': {
|
||||||
let color = token.props.args.color;
|
let color = validColor(token.props.args.color);
|
||||||
if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00';
|
color = color ?? 'f00';
|
||||||
style = `color: #${color}; overflow-wrap: anywhere;`;
|
style = `color: #${color}; overflow-wrap: anywhere;`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'bg': {
|
case 'bg': {
|
||||||
let color = token.props.args.color;
|
let color = validColor(token.props.args.color);
|
||||||
if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00';
|
color = color ?? 'f00';
|
||||||
style = `background-color: #${color}; overflow-wrap: anywhere;`;
|
style = `background-color: #${color}; overflow-wrap: anywhere;`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'border': {
|
||||||
|
let color = validColor(token.props.args.color);
|
||||||
|
color = color ? `#${color}` : 'var(--accent)';
|
||||||
|
let b_style = token.props.args.style;
|
||||||
|
if (
|
||||||
|
!['hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset']
|
||||||
|
.includes(b_style)
|
||||||
|
) b_style = 'solid';
|
||||||
|
const width = parseFloat(token.props.args.width ?? '1');
|
||||||
|
const radius = parseFloat(token.props.args.radius ?? '0');
|
||||||
|
style = `border: ${width}px ${b_style} ${color}; border-radius: ${radius}px`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'ruby': {
|
case 'ruby': {
|
||||||
if (token.children.length === 1) {
|
if (token.children.length === 1) {
|
||||||
const child = token.children[0];
|
const child = token.children[0];
|
||||||
|
|
|
@ -108,4 +108,4 @@ export const DEFAULT_SERVER_ERROR_IMAGE_URL = 'https://xn--931a.moe/assets/error
|
||||||
export const DEFAULT_NOT_FOUND_IMAGE_URL = 'https://xn--931a.moe/assets/not-found.jpg';
|
export const DEFAULT_NOT_FOUND_IMAGE_URL = 'https://xn--931a.moe/assets/not-found.jpg';
|
||||||
export const DEFAULT_INFO_IMAGE_URL = 'https://xn--931a.moe/assets/info.jpg';
|
export const DEFAULT_INFO_IMAGE_URL = 'https://xn--931a.moe/assets/info.jpg';
|
||||||
|
|
||||||
export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'font', 'blur', 'rainbow', 'sparkle', 'rotate', 'ruby', 'unixtime'];
|
export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'border', 'font', 'blur', 'rainbow', 'sparkle', 'rotate', 'ruby', 'unixtime'];
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
module.exports = {
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: ['./tsconfig.json'],
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'../../packages/shared/.eslintrc.js',
|
||||||
|
],
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
node_modules
|
||||||
|
coverage
|
||||||
|
.idea
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "changelog-checker",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"run": "vite-node src/index.ts",
|
||||||
|
"test": "vitest run",
|
||||||
|
"test:coverage": "vitest run --coverage"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/mdast": "4.0.3",
|
||||||
|
"@types/node": "20.10.7",
|
||||||
|
"@vitest/coverage-v8": "1.1.3",
|
||||||
|
"mdast-util-to-string": "4.0.0",
|
||||||
|
"remark": "15.0.1",
|
||||||
|
"remark-parse": "11.0.0",
|
||||||
|
"typescript": "5.3.3",
|
||||||
|
"unified": "11.0.4",
|
||||||
|
"vite": "5.0.11",
|
||||||
|
"vite-node": "1.1.3",
|
||||||
|
"vitest": "1.1.3"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
import { Release } from './parser.js';
|
||||||
|
|
||||||
|
export class Result {
|
||||||
|
public readonly success: boolean;
|
||||||
|
public readonly message?: string;
|
||||||
|
|
||||||
|
private constructor(success: boolean, message?: string) {
|
||||||
|
this.success = success;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ofSuccess(): Result {
|
||||||
|
return new Result(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ofFailed(message?: string): Result {
|
||||||
|
return new Result(false, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* develop -> masterまたはrelease -> masterを想定したパターン。
|
||||||
|
* base側の先頭とhead側で追加された分のリリースより1つ前のバージョンが等価であるかチェックする。
|
||||||
|
*/
|
||||||
|
export function checkNewRelease(base: Release[], head: Release[]): Result {
|
||||||
|
const releaseCountDiff = head.length - base.length;
|
||||||
|
if (releaseCountDiff <= 0) {
|
||||||
|
return Result.ofFailed('Invalid release count.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseLatest = base[0];
|
||||||
|
const headPrevious = head[releaseCountDiff];
|
||||||
|
|
||||||
|
if (baseLatest.releaseName !== headPrevious.releaseName) {
|
||||||
|
return Result.ofFailed('Contains unexpected releases.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ofSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* topic -> developまたはtopic -> masterを想定したパターン。
|
||||||
|
* head側の最新リリース配下に書き加えられているかをチェックする。
|
||||||
|
*/
|
||||||
|
export function checkNewTopic(base: Release[], head: Release[]): Result {
|
||||||
|
if (head.length !== base.length) {
|
||||||
|
return Result.ofFailed('Invalid release count.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const headLatest = head[0];
|
||||||
|
for (let relIdx = 0; relIdx < base.length; relIdx++) {
|
||||||
|
const baseItem = base[relIdx];
|
||||||
|
const headItem = head[relIdx];
|
||||||
|
if (baseItem.releaseName !== headItem.releaseName) {
|
||||||
|
// リリースの順番が変わってると成立しないのでエラーにする
|
||||||
|
return Result.ofFailed(`Release is different. base:${baseItem.releaseName}, head:${headItem.releaseName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseItem.categories.length !== headItem.categories.length) {
|
||||||
|
// カテゴリごと書き加えられたパターン
|
||||||
|
if (headLatest.releaseName !== headItem.releaseName) {
|
||||||
|
// 最新リリース以外に追記されていた場合
|
||||||
|
return Result.ofFailed(`There is an error in the update history. expected additions:${headLatest.releaseName}, actual additions:${headItem.releaseName}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// カテゴリ数の変動はないのでリスト項目の数をチェック
|
||||||
|
for (let catIdx = 0; catIdx < baseItem.categories.length; catIdx++) {
|
||||||
|
const baseCategory = baseItem.categories[catIdx];
|
||||||
|
const headCategory = headItem.categories[catIdx];
|
||||||
|
|
||||||
|
if (baseCategory.categoryName !== headCategory.categoryName) {
|
||||||
|
// カテゴリの順番が変わっていると成立しないのでエラーにする
|
||||||
|
return Result.ofFailed(`Category is different. base:${baseCategory.categoryName}, head:${headCategory.categoryName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseCategory.items.length !== headCategory.items.length) {
|
||||||
|
if (headLatest.releaseName !== headItem.releaseName) {
|
||||||
|
// 最新リリース以外に追記されていた場合
|
||||||
|
return Result.ofFailed(`There is an error in the update history. expected additions:${headLatest.releaseName}, actual additions:${headItem.releaseName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ofSuccess();
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
import * as process from 'process';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { parseChangeLog } from './parser.js';
|
||||||
|
import { checkNewRelease, checkNewTopic } from './checker.js';
|
||||||
|
|
||||||
|
function abort(message?: string) {
|
||||||
|
if (message) {
|
||||||
|
console.error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
if (!fs.existsSync('./CHANGELOG-base.md') || !fs.existsSync('./CHANGELOG-head.md')) {
|
||||||
|
console.error('CHANGELOG-base.md or CHANGELOG-head.md is missing.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = parseChangeLog('./CHANGELOG-base.md');
|
||||||
|
const head = parseChangeLog('./CHANGELOG-head.md');
|
||||||
|
|
||||||
|
const result = (base.length < head.length)
|
||||||
|
? checkNewRelease(base, head)
|
||||||
|
: checkNewTopic(base, head);
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
|
abort(result.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
|
@ -0,0 +1,62 @@
|
||||||
|
import * as fs from 'node:fs';
|
||||||
|
import { unified } from 'unified';
|
||||||
|
import remarkParse from 'remark-parse';
|
||||||
|
import { Heading, List, Node } from 'mdast';
|
||||||
|
import { toString } from 'mdast-util-to-string';
|
||||||
|
|
||||||
|
export class Release {
|
||||||
|
public readonly releaseName: string;
|
||||||
|
public readonly categories: ReleaseCategory[];
|
||||||
|
|
||||||
|
constructor(releaseName: string, categories: ReleaseCategory[] = []) {
|
||||||
|
this.releaseName = releaseName;
|
||||||
|
this.categories = [...categories];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ReleaseCategory {
|
||||||
|
public readonly categoryName: string;
|
||||||
|
public readonly items: string[];
|
||||||
|
|
||||||
|
constructor(categoryName: string, items: string[] = []) {
|
||||||
|
this.categoryName = categoryName;
|
||||||
|
this.items = [...items];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isHeading(node: Node): node is Heading {
|
||||||
|
return node.type === 'heading';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isList(node: Node): node is List {
|
||||||
|
return node.type === 'list';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseChangeLog(path: string): Release[] {
|
||||||
|
const input = fs.readFileSync(path, { encoding: 'utf8' });
|
||||||
|
const processor = unified().use(remarkParse);
|
||||||
|
|
||||||
|
const releases: Release[] = [];
|
||||||
|
const root = processor.parse(input);
|
||||||
|
|
||||||
|
let release: Release | null = null;
|
||||||
|
let category: ReleaseCategory | null = null;
|
||||||
|
for (const it of root.children) {
|
||||||
|
if (isHeading(it) && it.depth === 2) {
|
||||||
|
// リリース
|
||||||
|
release = new Release(toString(it));
|
||||||
|
releases.push(release);
|
||||||
|
} else if (isHeading(it) && it.depth === 3 && release) {
|
||||||
|
// リリース配下のカテゴリ
|
||||||
|
category = new ReleaseCategory(toString(it));
|
||||||
|
release.categories.push(category);
|
||||||
|
} else if (isList(it) && category) {
|
||||||
|
for (const listItem of it.children) {
|
||||||
|
// カテゴリ配下のリスト項目
|
||||||
|
category.items.push(toString(listItem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return releases;
|
||||||
|
}
|
|
@ -0,0 +1,414 @@
|
||||||
|
import {expect, suite, test} from "vitest";
|
||||||
|
import {Release, ReleaseCategory} from "../src/parser";
|
||||||
|
import {checkNewRelease, checkNewTopic} from "../src/checker";
|
||||||
|
|
||||||
|
suite('checkNewRelease', () => {
|
||||||
|
test('headに新しいリリースがある1', () => {
|
||||||
|
const base = [new Release('2024.12.0')]
|
||||||
|
const head = [new Release('2024.12.1'), new Release('2024.12.0')]
|
||||||
|
|
||||||
|
const result = checkNewRelease(base, head)
|
||||||
|
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('headに新しいリリースがある2', () => {
|
||||||
|
const base = [new Release('2024.12.0')]
|
||||||
|
const head = [new Release('2024.12.2'), new Release('2024.12.1'), new Release('2024.12.0')]
|
||||||
|
|
||||||
|
const result = checkNewRelease(base, head)
|
||||||
|
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test('リリースの数が同じ', () => {
|
||||||
|
const base = [new Release('2024.12.0')]
|
||||||
|
const head = [new Release('2024.12.0')]
|
||||||
|
|
||||||
|
const result = checkNewRelease(base, head)
|
||||||
|
|
||||||
|
console.log(result.message)
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('baseにあるリリースがheadにない', () => {
|
||||||
|
const base = [new Release('2024.12.0')]
|
||||||
|
const head = [new Release('2024.12.2'), new Release('2024.12.1')]
|
||||||
|
|
||||||
|
const result = checkNewRelease(base, head)
|
||||||
|
|
||||||
|
console.log(result.message)
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
suite('checkNewTopic', () => {
|
||||||
|
test('追記なし', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('最新バージョンにカテゴリを追加したときはエラーにならない', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('最新バージョンからカテゴリを削除したときはエラーにならない', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat3',
|
||||||
|
'feat4',
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('最新バージョンに追記したときはエラーにならない', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
'feat3',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('最新バージョンから削除したときはエラーにならない', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('古いバージョンにカテゴリを追加したときはエラーになる', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
new ReleaseCategory('Client', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
console.log(result.message)
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('古いバージョンからカテゴリを削除したときはエラーになる', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
console.log(result.message)
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('古いバージョンに追記したときはエラーになる', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
'feat3',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
console.log(result.message)
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('古いバージョンから削除したときはエラーになる', () => {
|
||||||
|
const base = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const head = [
|
||||||
|
new Release('2024.12.1', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
'feat2',
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
new Release('2024.12.0', [
|
||||||
|
new ReleaseCategory('Server', [
|
||||||
|
'feat1',
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = checkNewTopic(base, head)
|
||||||
|
|
||||||
|
console.log(result.message)
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"strict": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/@types"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"esnext"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"test/**/*"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import {defineConfig} from 'vite';
|
||||||
|
|
||||||
|
|
||||||
|
const config = defineConfig({});
|
||||||
|
|
||||||
|
export default config;
|
Loading…
Reference in New Issue