-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: plugin pack command for 2 #916
Changes from all commits
50cc317
6fdc82e
51c43fb
ae959ae
50eccd2
5ec52a6
78569d4
20c9f66
e12c6c4
7ee49ad
349c9ac
802d3a9
f00fe1d
97837a8
32cafad
a5de6fb
c8147c9
ade24d1
5b5345e
72e56b2
b9a1a4e
e0506b5
fea78f4
e92bea2
486e111
f0e5b62
e658a11
298dfb6
77f9dcd
ece62b1
96692f4
58f7263
7093fa8
b0b4e3c
7f5fc5e
bb5afcd
2519bce
6d9a6ce
c2656b6
dc681dd
d4881a8
2544616
86f7dde
7529e19
1a9cd24
bb847d3
8080a6b
50a3e72
96c0995
3312a0f
99a80b7
68254c1
67bffa2
95110a4
aff6ce3
1b18965
aacf5bf
36b94a4
b17869d
e2078e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,12 +76,10 @@ | |
"@cybozu/eslint-config": "^24.0.0-beta.0", | ||
"@cybozu/license-manager": "^1.2.1", | ||
"@octokit/rest": "^20.1.1", | ||
"@types/debug": "^4.1.12", | ||
"@types/jest": "^29.5.14", | ||
"@types/node": "^18.19.64", | ||
"@types/node-rsa": "^1.1.4", | ||
"@types/rollup-plugin-auto-external": "^2.0.5", | ||
"@types/stream-buffers": "^3.0.7", | ||
"@types/yargs": "^17.0.33", | ||
"@types/yauzl": "^2.10.3", | ||
"@types/yazl": "^2.4.5", | ||
|
@@ -112,13 +110,9 @@ | |
"chokidar": "^4.0.1", | ||
"csv-parse": "^4.16.3", | ||
"csv-stringify": "5.6.5", | ||
"debug": "^4.3.7", | ||
"execa": "^9.4.1", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 使用していたテストを消した。 |
||
"https-proxy-agent": "^7.0.5", | ||
"iconv-lite": "^0.6.3", | ||
"mkdirp": "^3.0.1", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"node-rsa": "^1.1.1", | ||
"stream-buffers": "^3.0.3", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"yargs": "^17.7.2", | ||
"yauzl": "^3.1.3", | ||
"yazl": "^3.1.0" | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,27 @@ | ||
import type { CommandModule } from "yargs"; | ||
import type yargs from "yargs"; | ||
import { packCommand } from "./pack"; | ||
import { emitExperimentalWarning } from "../../utils/stability"; | ||
import { infoCommand } from "./info"; | ||
import { setStability } from "../stability"; | ||
|
||
const command = "plugin"; | ||
|
||
const describe = "[Experimental] Commands for kintone plugin"; | ||
const describe = "Commands for kintone plugin"; | ||
|
||
const builder = (args: yargs.Argv) => args.command(packCommand).demandCommand(); | ||
const builder = (args: yargs.Argv) => | ||
args.command(infoCommand).command(packCommand).demandCommand(); | ||
|
||
const handler = () => { | ||
emitExperimentalWarning("This feature is under early development"); | ||
/** noop **/ | ||
}; | ||
|
||
export const pluginCommand: CommandModule = { | ||
command, | ||
describe, | ||
builder, | ||
handler, | ||
}; | ||
export const pluginCommand: CommandModule = setStability( | ||
{ | ||
command, | ||
describe, | ||
builder, | ||
handler, | ||
}, | ||
"experimental", | ||
"This feature is under early development", | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import type yargs from "yargs"; | ||
import type { CommandModule } from "yargs"; | ||
import type { OutputFormat } from "../../plugin/info/"; | ||
import { run } from "../../plugin/info/"; | ||
import { logger } from "../../utils/log"; | ||
import { RunError } from "../../record/error"; | ||
import { setStability } from "../stability"; | ||
|
||
const command = "info"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
設計で本当にpack以外のコマンドが実装しやすくなっているかの検証も兼ねて実装 |
||
|
||
const describe = "Show information from plugin file"; | ||
|
||
const outputFormats: OutputFormat[] = ["plain", "json"]; | ||
|
||
const builder = (args: yargs.Argv) => | ||
args | ||
.option("input", { | ||
describe: "The input plugin zip", | ||
type: "string", | ||
demandOption: true, | ||
requiresArg: true, | ||
}) | ||
.option("format", { | ||
describe: "Format", | ||
default: "plain" satisfies OutputFormat as OutputFormat, | ||
choices: outputFormats, | ||
requiresArg: true, | ||
}); | ||
|
||
type Args = yargs.Arguments< | ||
ReturnType<typeof builder> extends yargs.Argv<infer U> ? U : never | ||
>; | ||
|
||
const handler = async (args: Args) => { | ||
try { | ||
await run(args.input, args.format); | ||
} catch (error) { | ||
logger.error(new RunError(error)); | ||
// eslint-disable-next-line n/no-process-exit | ||
process.exit(1); | ||
} | ||
}; | ||
|
||
export const infoCommand: CommandModule<{}, Args> = setStability( | ||
{ | ||
command, | ||
describe, | ||
builder, | ||
handler, | ||
}, | ||
"experimental", | ||
"This feature is under early development", | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import type { ArgumentsCamelCase, CommandModule } from "yargs"; | ||
import { | ||
emitDeprecationWarning, | ||
emitExperimentalWarning, | ||
} from "../utils/stability"; | ||
|
||
/** | ||
* Set stability index to a command. | ||
* - Show stability on help message | ||
* - Emit warning on execution | ||
* @param cmd Command module | ||
* @param stability "experimental" or "deprecated" | ||
* @param message additional information | ||
*/ | ||
export const setStability = <T = {}, U = {}>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://github.com/kintone/cli-kintone/pull/915/files#r1815855917 の対応
どこかのflagsにstabilityの情報を集約して、それに連動して表示が変わるようにしたかったが、yargsの仕組み上難しそうだった。 コマンドの生成を全てラップするヘルパー関数を置けば実現できるが、既存のレコード系のコマンドにも影響が出るので今回は個別のコマンドをラップする方式にした。 |
||
cmd: CommandModule<T, U>, | ||
stability: "experimental" | "deprecated", | ||
message: string, | ||
): CommandModule<T, U> => { | ||
const { describe, handler, ...restCmd } = cmd; | ||
const newDescribe = buildDescriptionWithStability( | ||
describe, | ||
message, | ||
stability, | ||
); | ||
|
||
const newHandler = async (args: ArgumentsCamelCase<U>) => { | ||
switch (stability) { | ||
case "experimental": | ||
emitExperimentalWarning(message); | ||
break; | ||
case "deprecated": | ||
emitDeprecationWarning(message); | ||
break; | ||
} | ||
await handler(args); | ||
}; | ||
|
||
return { | ||
...restCmd, | ||
describe: newDescribe, | ||
handler: newHandler, | ||
}; | ||
}; | ||
|
||
const buildDescriptionWithStability = ( | ||
description: string | false | undefined, | ||
message: string, | ||
stability: "experimental" | "deprecated", | ||
): string => { | ||
const labels = { | ||
experimental: "Experimental", | ||
deprecated: "Deprecated", | ||
}; | ||
const label = labels[stability]; | ||
const msgLines = message.split("\n"); | ||
|
||
let output = ""; | ||
if (description) { | ||
output += description + "\n\n"; | ||
} | ||
|
||
output += `[${label}: ${msgLines[0]}]`; | ||
if (msgLines.length > 1) { | ||
output += `${"\n" + msgLines.slice(1)}`; | ||
} | ||
|
||
return output; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{ | ||
"$schema": "https://example.com/plugin-manifest-schema.json", | ||
"manifest_version": 2, | ||
"version": 1, | ||
"type": "APP", | ||
"name": { | ||
"en": "sample extension" | ||
}, | ||
"description": { | ||
"en": "This is sample extension." | ||
}, | ||
"icon": "image/icon.png", | ||
"components": [ | ||
{ | ||
"type": "APP_INDEX_HEADER_SPACE", | ||
"js": ["js/customize.js", "https://example.com/js/customize.js"], | ||
"css": ["https://example.com/css/customize.css", "css/customize.css"], | ||
"html": "html/customize.html" | ||
} | ||
], | ||
"config": { | ||
"html": "html/config.html", | ||
"js": ["https://example.com/js/config.js", "js/config.js"], | ||
"css": ["css/config.css", "https://example.com/css/config.css"], | ||
"required_params": ["Param1", "Param2"] | ||
}, | ||
"allowed_hosts": ["https://example.com"], | ||
"permissions": { | ||
"js_api": [ | ||
"rest_api:execute", | ||
"kintone.app.getId", | ||
"kintone.plugin.app.getConfig" | ||
], | ||
"rest_api": ["app_record:read", "/k/v1/record.json:put"] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import path from "path"; | ||
import { ManifestFactory } from "../../manifest"; | ||
import { ContentsZip } from "../index"; | ||
import { LocalFSDriver } from "../../driver"; | ||
import fs from "fs"; | ||
|
||
const fixturesDir = path.join(__dirname, "fixtures"); | ||
|
||
describe("ContentsZip", () => { | ||
describe("should be able to create ContentsZip from a plugin directory", () => { | ||
it("manifest v1", async () => { | ||
const pluginDir = path.join(fixturesDir, "plugin-manifest-v1"); | ||
|
||
const manifestJSONPath = path.join(pluginDir, "manifest.json"); | ||
const manifest = await ManifestFactory.loadJsonFile(manifestJSONPath); | ||
|
||
const contentsZip = await ContentsZip.buildFromManifest( | ||
manifest, | ||
new LocalFSDriver(pluginDir), | ||
); | ||
const files = await contentsZip.fileList(); | ||
expect(files).toStrictEqual(["manifest.json", "image/icon.png"]); | ||
expect(contentsZip).toBeInstanceOf(ContentsZip); | ||
expect(contentsZip.buffer).toBeInstanceOf(Buffer); | ||
}); | ||
|
||
it("manifest v2", async () => { | ||
const pluginDir = path.join(fixturesDir, "plugin-manifest-v2"); | ||
|
||
const manifestJSONPath = path.join(pluginDir, "manifest.json"); | ||
const manifest = await ManifestFactory.loadJsonFile(manifestJSONPath); | ||
|
||
const contentsZip = await ContentsZip.buildFromManifest( | ||
manifest, | ||
new LocalFSDriver(pluginDir), | ||
); | ||
|
||
const expectedFiles = [ | ||
"manifest.json", | ||
"image/icon.png", | ||
"js/customize.js", | ||
"css/customize.css", | ||
"html/customize.html", | ||
"html/config.html", | ||
"js/config.js", | ||
"css/config.css", | ||
]; | ||
const files = await contentsZip.fileList(); | ||
expect(files).toStrictEqual(expectedFiles); | ||
expect(contentsZip).toBeInstanceOf(ContentsZip); | ||
expect(contentsZip.buffer).toBeInstanceOf(Buffer); | ||
}); | ||
}); | ||
|
||
describe("invalid contents.zip", () => { | ||
const invalidMaxFileSizeContentsZipPath = path.join( | ||
__dirname, | ||
"fixtures", | ||
"invalid-maxFileSize", | ||
"invalid-maxFileSize-contents.zip", | ||
); | ||
|
||
// TODO: This test must be in contents-zip module | ||
it("throws an error if the contents.zip is invalid", async () => { | ||
const buffer = fs.readFileSync(invalidMaxFileSizeContentsZipPath); | ||
await expect(ContentsZip.fromBuffer(buffer)).rejects.toThrow( | ||
'"/icon" file size should be <= 20MB', | ||
); | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debug
はcli-kintoneのlogger.debug|trace
に置き換えた。