feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type {
IPlugin,
IHooks,
IPromptsHookParams,
} from "rush-init-project-plugin";
import { readFileSync } from 'fs';
import path from 'path';
import JSON5 from '../../autoinstallers/plugins/node_modules/json5'
const rushJson = JSON5.parse(
readFileSync(
path.resolve(__dirname, '../../../rush.json')
).toString('utf-8')
);
export default class SelectTeamPlugin implements IPlugin {
apply(hooks: IHooks): void {
hooks.prompts.tap("SelectTeamPlugin", (prompts: IPromptsHookParams) => {
// 只留下以team-为前缀的
const teamNamePrefix = /^team-/;
const choices = rushJson.allowedProjectTags.filter(
teamName => teamNamePrefix.test(teamName)
).map(
teamName => teamName.replace(teamNamePrefix, '')
);
// unshift一个问题使得用户选择完模版后展示该问题。
prompts.promptQueue.unshift({
type: "list",
name: "team",
message: "Select your team",
choices,
default: 0, // 默认选择choices[0]
});
const projectFolderPrompt = prompts.promptQueue.find(
item => item.name === 'projectFolder'
);
projectFolderPrompt.default = (answers) => {
// 文件夹名去除scope如 @coze-arch/foo -> foo
const folderDir = answers.packageName.split('/').slice(-1)[0];
return `packages/${answers.team}/${folderDir}`
}
});
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IPlugin, IHooks, IPromptsHookParams } from 'rush-init-project-plugin';
// FIXME:
// 按照 https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
// 一文的指引,无法正确 resolve 到对应模块,暂时没找到解决方案,故此处先用相对路径引用
// 未来需要调整为正常的 node_modules 引用方式
import { createLog } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin';
import { exec } from './utils';
export default class SetDefaultAuthorPlugin implements IPlugin {
private readonly logger = createLog({
prefix: SetDefaultAuthorPlugin.name
});
apply(hooks: IHooks): void {
hooks.prompts.tap(SetDefaultAuthorPlugin.name, async (prompts: IPromptsHookParams) => {
const prompAuthorEmail = prompts.promptQueue.find((r) => r.name === 'authorName');
if (prompAuthorEmail) {
const userEmail = String(await exec(this.logger, 'git', ['config', '--get', 'user.email']));
Object.assign(prompAuthorEmail, {
default() {
return userEmail;
},
validate(author: string) {
return /@bytedance\.com$/.test(author);
}
});
hooks.answers.tap("authorPrefix", (answers) => {
answers.authorPrefix = userEmail.split('@')?.[0] ?? '';
});
}
});
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IHooks, IPlugin, IPromptsHookParams } from 'rush-init-project-plugin';
import { parseCommandLineArguments } from './utils/parse-args';
export default class FornaxPlugin implements IPlugin {
apply(hooks: IHooks): void {
hooks.answers.tap('FornaxPlugin', (answers) => {
if(answers.template === 'fornax-child-app') {
if(answers.packageName.startsWith('@flow-devops/fornax-')) {
answers.childAppName = answers.packageName.replace('@flow-devops/fornax-','');
} else {
throw new Error('The initialization of field childAppName failed because the packageName is invalid. Please use "@flow-devops/fornax-xxx."');
}
}
})
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IPlugin, IHooks, ITemplatesHook, IPromptsHookParams } from 'rush-init-project-plugin';
// FIXME:
// 按照 https://github.com/bytemate/rush-plugins/blob/main/rush-plugins/rush-init-project-plugin/docs/init_project_configuration.md
// 一文的指引,无法正确 resolve 到对应模块,暂时没找到解决方案,故此处先用相对路径引用
// 未来需要调整为正常的 node_modules 引用方式
import { getTemplatesFolder, getTemplateNameList } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin/lib/logic/templateFolder';
import { parseCommandLineArguments } from './utils/parse-args';
export default class ShowChatAreaTemplatePlugin implements IPlugin {
apply(hooks: IHooks): void {
const args = parseCommandLineArguments();
const answer = JSON.parse(args.answer ?? '{}');
const isShowChatAreaTemplate = answer['showChatAreaTemplate'];
hooks.templates.tap("ShowChatAreaTemplatePlugin", (templates: ITemplatesHook) => {
const templateFolder: string = getTemplatesFolder();
const templateNameList = getTemplateNameList(templateFolder)
const filteredNormalTemplateNameList = templateNameList.filter(item => !item.templateFolder?.includes('chat-'));
templates.templates.push(...(isShowChatAreaTemplate ? templateNameList : filteredNormalTemplateNameList ));
});
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IConfig } from '../../autoinstallers/plugins/node_modules/rush-init-project-plugin';
import ShowChatAreaTemplatePlugin from './ShowChatAreaTemplatePlugin';
import SetFornaxChildAppPlugin from './SetFornaxChildAppPlugin';
const config: IConfig = {
plugins: [new ShowChatAreaTemplatePlugin(), new SetFornaxChildAppPlugin()]
};
export default config;

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { ILogger } from 'rush-init-project-plugin';
// eslint-disable-next-line @infra/no-deep-relative-import
import { spawnSync } from 'child_process';
const exec = (logger: ILogger, cmd: string, args: string[]): string | undefined => {
try {
if (!cmd) {
return undefined;
}
logger?.verbose(`Exec: ${cmd}`);
const { stdout } = spawnSync(cmd, args);
const result = stdout.toString();
logger?.verbose(`Cmd res: ${result}`);
return result.trim();
} catch (err) {
logger?.error(String(err));
throw err;
}
};
export { exec };

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import process from 'process';
// parseArgs.ts
export function parseCommandLineArguments() {
const args = process.argv.slice(2);
const result: Record<string, string> = {};
// 循环遍历所有参数
for (let i = 0; i < args.length; i++) {
// 检查当前参数是否是一个选项(以 "--" 开头)
if (args[i].startsWith('--')) {
const key = args[i].substring(2); // 移除 "--" 前缀
// 检查下一个参数是否存在,且不是另一个选项
if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
result[key] = args[i + 1]; // 将下一个参数作为当前选项的值
i++; // 跳过下一个参数,因为它已经被处理为当前选项的值
} else {
result[key] = ''; // 如果没有值,只设置选项的键
}
}
}
return result;
}