diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d4636ef4..0f5b6902 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -67,6 +67,13 @@ test-unit: test-integration: <<: *common-refs + # for debug + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + expire_in: "1 day" + when: "on_failure" + paths: + - ./generated stage: test script: - yarn --immutable diff --git a/deploy-stg.sh b/deploy-stg.sh index a3b0b833..47cf2b0d 100644 --- a/deploy-stg.sh +++ b/deploy-stg.sh @@ -6,17 +6,15 @@ timestamp=$(date +%s) dev_branch=$(git rev-parse --abbrev-ref HEAD) # replace possible "/" with "-" +# Because of a docker, as it uses git tag for tagging the image so if there's a / symbol +# docker thinks that it's actually a path. but not part of the tag name. dev_branch_sanitized=${dev_branch/\//-} stg_branch="stg-v0.0.${timestamp}-${dev_branch_sanitized}" -git checkout -b "$stg_branch" -git push origin "$stg_branch" +git push origin HEAD:"$stg_branch" # wait a bit before deleting branch, so gitlab triggers pipeline sleep 10 git push origin --delete "$stg_branch" - -# get back to initial branch -git checkout "$dev_branch" diff --git a/src/bot/parse/parsePullRequestBotCommandLine.spec.ts b/src/bot/parse/parsePullRequestBotCommandLine.spec.ts index f68d3520..e2940e3c 100644 --- a/src/bot/parse/parsePullRequestBotCommandLine.spec.ts +++ b/src/bot/parse/parsePullRequestBotCommandLine.spec.ts @@ -20,7 +20,7 @@ const dataProvider: DataProvider[] = [ { suitName: "unrelated to bot comment returns nothing (ignores)", commandLine: "something from comments", - expectedResponse: new SkipEvent(), + expectedResponse: new SkipEvent("Not a command"), }, { suitName: "check wrong set -v, validation should trigger error", @@ -86,7 +86,7 @@ const dataProvider: DataProvider[] = [ suitName: "bench-bot, no args when not allowed, should return error", commandLine: "bot bench", expectedResponse: new Error( - `Missing arguments for command "bench". Refer to [help docs](http://cmd-bot.docs.com/) for more details.`, + `Missing arguments for command "bench". Refer to [help docs](http://cmd-bot.docs.com/) and/or [source code](https://github.com/paritytech/command-bot-scripts).`, ), }, @@ -106,8 +106,12 @@ const dataProvider: DataProvider[] = [ /* Ignore cases */ - { suitName: "empty command line returns nothing (ignores)", commandLine: "", expectedResponse: new SkipEvent() }, - { suitName: "no subcommand - ignore", commandLine: "bot ", expectedResponse: new SkipEvent() }, + { + suitName: "empty command line returns nothing (ignores)", + commandLine: "", + expectedResponse: new SkipEvent("Not a command"), + }, + { suitName: "no subcommand - ignore", commandLine: "bot ", expectedResponse: new SkipEvent("Not a command") }, { suitName: "ignored command", commandLine: "bot merge", expectedResponse: new SkipEvent("Ignored command: merge") }, { suitName: "ignored command 2", @@ -122,21 +126,21 @@ const dataProvider: DataProvider[] = [ suitName: "nonexistent command, should return proper error", commandLine: "bot nope 123123", expectedResponse: new Error( - 'Could not find matching configuration for command "nope"; Available ones are bench, fmt, sample, try-runtime. Refer to [help docs](http://cmd-bot.docs.com/) for more details.', + 'Unknown command "nope"; Available ones are bench, fmt, sample, try-runtime. Refer to [help docs](http://cmd-bot.docs.com/) and/or [source code](https://github.com/paritytech/command-bot-scripts).', ), }, { suitName: "not provided command, returns proper error", commandLine: "bot $", expectedResponse: new Error( - 'Could not find matching configuration for command "$"; Available ones are bench, fmt, sample, try-runtime. Refer to [help docs](http://cmd-bot.docs.com/) for more details.', + 'Unknown command "$"; Available ones are bench, fmt, sample, try-runtime. Refer to [help docs](http://cmd-bot.docs.com/) and/or [source code](https://github.com/paritytech/command-bot-scripts).', ), }, { suitName: "non existed config must return error with explanation", commandLine: "bot xz", expectedResponse: new Error( - `Could not find matching configuration for command "xz"; Available ones are bench, fmt, sample, try-runtime. Refer to [help docs](http://cmd-bot.docs.com/) for more details.`, + `Unknown command "xz"; Available ones are bench, fmt, sample, try-runtime. Refer to [help docs](http://cmd-bot.docs.com/) and/or [source code](https://github.com/paritytech/command-bot-scripts).`, ), }, ]; diff --git a/src/bot/parse/parsePullRequestBotCommandLine.ts b/src/bot/parse/parsePullRequestBotCommandLine.ts index f19eeb70..3897b87c 100644 --- a/src/bot/parse/parsePullRequestBotCommandLine.ts +++ b/src/bot/parse/parsePullRequestBotCommandLine.ts @@ -9,6 +9,7 @@ import { getDocsUrl, PIPELINE_SCRIPTS_REF, } from "src/command-configs/fetchCommandsConfiguration"; +import { config } from "src/config"; import { LoggerContext } from "src/logger"; import { validateSingleShellCommand } from "src/shell"; @@ -20,7 +21,7 @@ export const parsePullRequestBotCommandLine = async ( // Add trailing whitespace so that bot can be differentiated from /cmd-[?] if (!commandLine.startsWith(`${botPullRequestCommentMention} `)) { - return new SkipEvent(); + return new SkipEvent("Not a command"); } // remove "bot " @@ -75,13 +76,13 @@ export const parsePullRequestBotCommandLine = async ( const { commandConfigs, commitHash } = await fetchCommandsConfiguration(ctx, variables[PIPELINE_SCRIPTS_REF]); const configuration = commandConfigs[subcommand]?.command?.configuration; - const helpStr = `Refer to [help docs](${getDocsUrl(commitHash)}) for more details.`; + const helpStr = `Refer to [help docs](${getDocsUrl(commitHash)}) and/or [source code](${ + config.pipelineScripts.repository + }).`; if (typeof configuration === "undefined" || !Object.keys(configuration).length) { return new Error( - `Could not find matching configuration for command "${subcommand}"; Available ones are ${Object.keys( - commandConfigs, - ).join(", ")}. ${helpStr}`, + `Unknown command "${subcommand}"; Available ones are ${Object.keys(commandConfigs).join(", ")}. ${helpStr}`, ); } diff --git a/src/bot/setupEvent.ts b/src/bot/setupEvent.ts index 77266bec..7a5bbb9a 100644 --- a/src/bot/setupEvent.ts +++ b/src/bot/setupEvent.ts @@ -47,8 +47,8 @@ export const setupEvent = ( : await createComment(ctx, octokit, sharedCommentParams); } else if (result instanceof SkipEvent && !!result.reason.trim()) { eventLogger.debug( - event.payload, - `Skip command "${event.payload.comment.body}" with reason: "${result.reason}"`, + { command: event.payload.comment.body, payload: event.payload }, + `Skip command with reason: "${result.reason}"`, ); } else if (result instanceof FinishedEvent) { eventLogger.info({ result }, "Finished command"); diff --git a/src/command-configs/renderHelpPage.pug b/src/command-configs/renderHelpPage.pug index 7693cbf5..1cb6758c 100644 --- a/src/command-configs/renderHelpPage.pug +++ b/src/command-configs/renderHelpPage.pug @@ -56,19 +56,17 @@ html div.preset h5.mb-sm(id="link-"+presetName) #{presetName} p #{ preset.description } - table.ms-table - thead - tr - th - | Command - th - | $ - if preset.args + if preset.args + table.ms-table + thead + tr + th + | Command + th + | $ each arg, argKey in preset.args th.center | [#{arg.label}] - - if preset.args tr td #{commandName} td @@ -80,8 +78,6 @@ html div.mb-sm #{one} if arg.type_rule div #{arg.type_rule} - else - p no arguments p Example:  code @@ -92,7 +88,10 @@ html if arg.type_one_of | #{arg.type_one_of[0]} if arg.type_rule - i custom_string + if arg.example + i #{arg.example} + else + i #{arg.type_rule} |   else p Example:  diff --git a/src/command-configs/renderHelpPage.ts b/src/command-configs/renderHelpPage.ts index 359e1222..e1f57a96 100644 --- a/src/command-configs/renderHelpPage.ts +++ b/src/command-configs/renderHelpPage.ts @@ -15,16 +15,40 @@ export function renderHelpPage(params: { const tmplPath = path.join(__dirname, "renderHelpPage.pug"); const { commandConfigs, scriptsRevision, headBranch, config } = params; - commandConfigs.help = mockStaticConfig("Generates help page & provides a link"); - commandConfigs.clean = mockStaticConfig("Clears bot comments in PR"); - const repoLink = new URL(path.join(config.pipelineScripts.repository, "tree", headBranch)).toString(); const commandStart = botPullRequestCommentMention; - /* TODO: depends on headBranch, if overridden: add `-v PIPELINE_SCRIPTS_REF=branch` to all command examples - same for PATCH_repo=xxx - TODO: Simplify the PIPELINE_SCRIPTS_REF to something more rememberable */ - return pug.renderFile(tmplPath, { config, repoLink, commandConfigs, scriptsRevision, headBranch, commandStart }); + const preparedConfigs = prepareConfigs(commandConfigs); + + // TODO: depends on headBranch, if overridden: add `-v PIPELINE_SCRIPTS_REF=branch` to all command examples same for PATCH_repo=xxx + // TODO: Simplify the PIPELINE_SCRIPTS_REF to something more rememberable */ + return pug.renderFile(tmplPath, { + config, + repoLink, + commandConfigs: preparedConfigs, + scriptsRevision, + headBranch, + commandStart, + }); +} + +function prepareConfigs(cmdConfigs: CommandConfigs): CommandConfigs { + const newCmdConfigs: CommandConfigs = {}; + + // these commands are added here, as they are defined inside of bot + newCmdConfigs.help = mockStaticConfig("Generates help page & provides a link"); + newCmdConfigs.clean = mockStaticConfig("Clears bot comments in PR"); + + // clean up excluded + for (const cmdName in cmdConfigs) { + const isExcluded = cmdConfigs[cmdName].command.excluded === true; + + if (!isExcluded) { + newCmdConfigs[cmdName] = cmdConfigs[cmdName]; + } + } + + return newCmdConfigs; } // append local (or "hardcoded") commands into documentation diff --git a/src/schema/schema.cmd.json b/src/schema/schema.cmd.json index 6bc849c9..df076d04 100644 --- a/src/schema/schema.cmd.json +++ b/src/schema/schema.cmd.json @@ -6,6 +6,9 @@ "command": { "type": "object", "properties": { + "excluded": { + "type": "boolean" + }, "description": { "type": "string" }, @@ -88,6 +91,9 @@ }, "type_rule": { "type": "string" + }, + "example": { + "type": "string" } }, "anyOf": [ @@ -98,14 +104,14 @@ "required": ["label", "type_many_of"] }, { - "required": ["label", "type_rule"] + "required": ["label", "type_rule", "example"] } ] } } } }, - "required": ["args", "description"] + "required": ["description"] } } } diff --git a/src/test/github-ignore-comands.spec.ts b/src/test/github-ignore-comands.spec.ts index becbfb82..c5d98320 100644 --- a/src/test/github-ignore-comands.spec.ts +++ b/src/test/github-ignore-comands.spec.ts @@ -34,7 +34,7 @@ describe.each(commandsDataProvider)( const skipTriggeredPromise = new Promise((resolve, reject) => { bot.stdout?.on("data", (dataBuffer: Buffer) => { const data = dataBuffer.toString(); - if (data.includes(`Skip command "${commandLine}"`)) { + if (data.includes(`Skip command with reason: "Ignored command:`) && data.includes(eventId)) { resolve("Skipped"); } else if (data.includes("handler finished") && data.includes(eventId)) { reject('Expected to see "Skip command" output first'); diff --git a/src/test/github-non-pipeline-cases.spec.ts b/src/test/github-non-pipeline-cases.spec.ts index f884c043..bdac93d1 100644 --- a/src/test/github-non-pipeline-cases.spec.ts +++ b/src/test/github-non-pipeline-cases.spec.ts @@ -43,7 +43,7 @@ const commandsDataProvider: CommandDataProviderItem[] = [ commandLine: "bot hrlp", // intentional typo expected: { startMessage: - '@somedev123 Could not find matching configuration for command "hrlp"; Available ones are bench, fmt, sample, try-runtime, help, clean. Refer to [help docs](http://localhost:3000/static/docs/', + '@somedev123 Unknown command "hrlp"; Available ones are bench-all, bench-vm, bench, fmt, merge, rebase, sample, try-runtime. Refer to [help docs](http://localhost:3000/static/docs/', }, }, { diff --git a/src/test/setup/bot.ts b/src/test/setup/bot.ts index 740001d8..1eb438a7 100644 --- a/src/test/setup/bot.ts +++ b/src/test/setup/bot.ts @@ -20,6 +20,7 @@ export const getPingPort = (): number | null => pingPort; export async function launchBot(gitHubUrl: string, gitLabUrl: string, gitDaemons: GitDaemons): Promise { rmSync(path.join(process.cwd(), "data", "access_db"), { recursive: true, force: true }); rmSync(path.join(process.cwd(), "data", "db"), { recursive: true, force: true }); + rmSync(path.join(process.cwd(), "generated"), { recursive: true, force: true }); [webhookPort, pingPort] = await findFreePorts(2); const botEnv = getBotEnv(gitHubUrl, gitLabUrl, gitDaemons.gitHub.url, gitDaemons.gitLab.url); @@ -49,7 +50,7 @@ export async function launchBot(gitHubUrl: string, gitLabUrl: string, gitDaemons return false; } }, - 500, + 1000, 50, `bot did not start to listen on ping port: ${ensureDefined(pingPort)}`, ).then(resolve, reject); diff --git a/src/test/setup/integration.setupAfterEnv.ts b/src/test/setup/integration.setupAfterEnv.ts index a555eb43..35f032e7 100644 --- a/src/test/setup/integration.setupAfterEnv.ts +++ b/src/test/setup/integration.setupAfterEnv.ts @@ -1,4 +1,5 @@ import { afterAll, beforeAll } from "@jest/globals"; +import { delay } from "opstooling-js"; import { getBotInstance, launchBot } from "./bot"; import { startGitDaemons, stopGitDaemons } from "./gitDaemons"; @@ -17,6 +18,8 @@ beforeAll(async () => { await launchBot(mockServers.gitHub.url, mockServers.gitLab.url, gitDaemons); console.log("Bot launched"); + + await delay(1000); }); afterAll(async () => { @@ -30,4 +33,6 @@ afterAll(async () => { await stopMockServers(); console.log("MockServers stopped"); + + await delay(1000); });