Skip to content
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

Merged
merged 60 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
50cc317
refactor crypto module
tasshi-me Oct 24, 2024
6fdc82e
add command guide in docs
tasshi-me Oct 24, 2024
51c43fb
use cli-kintone logger instead of console
tasshi-me Oct 24, 2024
ae959ae
refactor manifest module
tasshi-me Oct 24, 2024
50eccd2
replace callbacks with async await
tasshi-me Oct 24, 2024
5ec52a6
add description for watch option
tasshi-me Oct 24, 2024
78569d4
extract pluginZip, contentsZip, and manifest modules
tasshi-me Oct 25, 2024
20c9f66
use ContentsZip class
tasshi-me Oct 25, 2024
e12c6c4
refactor plugin-zip
tasshi-me Oct 25, 2024
7ee49ad
wip
tasshi-me Oct 25, 2024
349c9ac
wip
tasshi-me Oct 25, 2024
802d3a9
add trailing line break to ppk file
tasshi-me Oct 25, 2024
f00fe1d
replace callback with async await
tasshi-me Oct 25, 2024
97837a8
refactor contents-zip
tasshi-me Oct 25, 2024
32cafad
add ManifestStaticInterface
tasshi-me Oct 25, 2024
a5de6fb
refactor manifest module
tasshi-me Oct 25, 2024
c8147c9
support manifest v2
tasshi-me Oct 25, 2024
ade24d1
rename cli() to run()
tasshi-me Oct 25, 2024
5b5345e
fix manifest parsing process
tasshi-me Oct 25, 2024
72e56b2
add tests for manifest v2
tasshi-me Oct 25, 2024
b9a1a4e
deprecate packPluginFromManifest
tasshi-me Oct 25, 2024
e0506b5
fix cli entrypoint
tasshi-me Oct 25, 2024
fea78f4
fix internal dir structure of invalid-maxFileSize-contents.zip
tasshi-me Oct 26, 2024
e92bea2
manifest.json must be in root dir of zip file now
tasshi-me Oct 26, 2024
486e111
add Driver module to abstract fs and zip file
tasshi-me Oct 26, 2024
f0e5b62
use DriverInterface
tasshi-me Oct 26, 2024
e658a11
replace ZipFile module with ZipFileDriver
tasshi-me Oct 26, 2024
298dfb6
add plugin inspect command
tasshi-me Oct 26, 2024
77f9dcd
define manifest v1 json object type
tasshi-me Oct 26, 2024
ece62b1
refactor tests
tasshi-me Oct 26, 2024
96692f4
create plugin core module
tasshi-me Oct 26, 2024
58f7263
small refactors
tasshi-me Oct 26, 2024
7093fa8
delete rezip()
tasshi-me Oct 26, 2024
b0b4e3c
use consumers instead of stream-buffers
tasshi-me Oct 26, 2024
7f5fc5e
add verify metho to PublicKey class
tasshi-me Oct 27, 2024
bb5afcd
refactor contents module
tasshi-me Oct 27, 2024
2519bce
refactor manifest validator
tasshi-me Oct 27, 2024
6d9a6ce
add doc for plugin info command
tasshi-me Oct 27, 2024
c2656b6
refactor plugin and contents
tasshi-me Oct 27, 2024
dc681dd
remove execa from deps
tasshi-me Oct 27, 2024
d4881a8
delete mkdirp from deps
tasshi-me Oct 27, 2024
2544616
use cli-kintone logger instead of debug package
tasshi-me Oct 27, 2024
86f7dde
reorder plugin commands
tasshi-me Oct 27, 2024
7529e19
improve error handling on cli
tasshi-me Oct 27, 2024
1a9cd24
update TS target to ES2018
tasshi-me Oct 27, 2024
bb847d3
refactor cli
tasshi-me Oct 28, 2024
8080a6b
Merge remote-tracking branch 'origin/main' into feat/plugin-packer-2
tasshi-me Oct 28, 2024
50a3e72
delete files generated by tests
tasshi-me Oct 28, 2024
96c0995
add JSDoc
tasshi-me Oct 28, 2024
3312a0f
add `setStability()` helper function
tasshi-me Oct 28, 2024
99a80b7
reorder run process
tasshi-me Nov 1, 2024
68254c1
fix typo in a comment
tasshi-me Nov 1, 2024
67bffa2
rename cli to pack
tasshi-me Nov 1, 2024
95110a4
rename create methods to generate or build
tasshi-me Nov 2, 2024
aff6ce3
stop exporting experimental function
tasshi-me Nov 2, 2024
1b18965
refactor plugin module
tasshi-me Nov 2, 2024
aacf5bf
add comment to private constructors
tasshi-me Nov 2, 2024
36b94a4
Merge remote-tracking branch 'origin/main' into feat/plugin-packer-2
tasshi-me Nov 2, 2024
b17869d
add TODO comments for future refactoring
tasshi-me Nov 5, 2024
e2078e1
Merge remote-tracking branch 'origin/main' into feat/plugin-packer-2
tasshi-me Nov 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions license-manager.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ const OVERRIDE_LICENSES_TEXT = {
// License text is written in README.md
licenseText: "See https://github.com/rzcoder/node-rsa#license",
},
"stream-buffers": {
licensePageUrl:
"https://raw.githubusercontent.com/samcday/node-stream-buffer/refs/heads/main/UNLICENSE",
},
};

module.exports = config;
6 changes: 0 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -112,13 +110,9 @@
"chokidar": "^4.0.1",
"csv-parse": "^4.16.3",
"csv-stringify": "5.6.5",
"debug": "^4.3.7",
Copy link
Member Author

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に置き換えた。

"execa": "^9.4.1",
Copy link
Member Author

Choose a reason for hiding this comment

The 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",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fs.promises.mkdir(data, {recursive: true}) に置き換え

"node-rsa": "^1.1.1",
"stream-buffers": "^3.0.3",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stream-buffersは Node.js 標準の Utility Consumers に置き換えが案内されていたので置き換えた。
https://www.npmjs.com/package/stream-buffers

"yargs": "^17.7.2",
"yauzl": "^3.1.3",
"yazl": "^3.1.0"
Expand Down
268 changes: 67 additions & 201 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

25 changes: 15 additions & 10 deletions src/cli/plugin/index.ts
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",
);
53 changes: 53 additions & 0 deletions src/cli/plugin/info.ts
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";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

infoコマンドはプラグインファイルの情報を表示するコマンド。

設計で本当に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",
);
49 changes: 30 additions & 19 deletions src/cli/plugin/pack.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type yargs from "yargs";
import type { CommandModule } from "yargs";
import cli from "../../plugin/packer/cli";
import { emitExperimentalWarning } from "../../utils/stability";
import { run } from "../../plugin/packer/";
import { logger } from "../../utils/log";
import { RunError } from "../../record/error";
import { setStability } from "../stability";

const command = "pack";

const describe = "[Experimental] Packaging plugin project to a zip file";
const describe = "Packaging plugin project to a zip file";

const builder = (args: yargs.Argv) =>
args
Expand Down Expand Up @@ -38,22 +40,31 @@ type Args = yargs.Arguments<
>;

const handler = async (args: Args) => {
emitExperimentalWarning("This feature is under early development");
const flags = {
ppk: args["private-key"],
out: args.output,
watch: args.watch,
};
if (process.env.NODE_ENV === "test") {
console.log(JSON.stringify({ pluginDir: args.input, flags: flags }));
} else {
await cli(args.input, flags);
try {
const flags = {
ppk: args["private-key"],
output: args.output,
watch: args.watch,
};
if (process.env.NODE_ENV === "test") {
console.log(JSON.stringify({ pluginDir: args.input, flags: flags }));
} else {
await run(args.input, flags);
}
} catch (error) {
logger.error(new RunError(error));
// eslint-disable-next-line n/no-process-exit
process.exit(1);
}
};

export const packCommand: CommandModule<{}, Args> = {
command,
describe,
builder,
handler,
};
export const packCommand: CommandModule<{}, Args> = setStability(
{
command,
describe,
builder,
handler,
},
"experimental",
"This feature is under early development",
);
69 changes: 69 additions & 0 deletions src/cli/stability.ts
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 = {}>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/kintone/cli-kintone/pull/915/files#r1815855917 の対応

setStability(cmd, stability, msg) 関数を追加した。
ヘルプメッセージにStabilityが表示され、実行時に警告が出るようになる。


どこかの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;
};
Binary file not shown.
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"]
}
}
71 changes: 71 additions & 0 deletions src/plugin/core/contents/__tests__/index.test.ts
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',
);
});
});
});
Loading
Loading