3
1

kintone plugin-uploader の暫定エラー対応

Last updated at Posted at 2024-05-12

kintone のプラグイン管理画面の構成が変わって、plugin-uploader でエラーが発生したので、とりあえず暫定対策したメモ書き

plugin-uploader で、本対策済みのようです。

概要

※plugin-uploader のバージョンアップで、本対策されます。

npm install @kintone/plugin-uploader@latest
or
npm install -g @kintone/plugin-uploader@latest

以下はメモ書きで、古い情報です。

2024/05/12 の kintone アップデートで、プラグイン管理画面の構成が変わって、plugin-uploader でエラーが発生。
※「エラーが発生しました kintone管理者権限のあるユーザーで実行してください」
クラス名等がかわっているので、とりあえず暫定対応した。

kintone 画面刷新の一環で、プラグイン管理画面が変わったと思われます。
プラグイン管理画面のクラス名は、自動生成されたものだと思われるので、今後のアップデートのタイミングで変更される可能性がある。
本対策としては、プラグインアップロードの REST API 対応が必要ですね。

error.log
field-format  [master ≡] > npm run upload-prod

> field-format@0.1.0 upload-prod
> kintone-plugin-uploader dist/field-format-plugin8.zip --watch --waiting-dialog-ms 3000

Open https://xxxxxxx.cybozu.com/login?saml=off
Trying to log in...
Navigate to https://xxxxxxx.cybozu.com/k/admin/system/plugin/
エラーが発生しました kintone管理者権限のあるユーザーで実行してください
  • プラグイン管理画面
    2024-05-12_18h46_01.png

  • プラグインアップロードダイアログ
    2024-05-12_18h46_53.png

plugin-uploader 暫定対応

plugin-uploader がインストールされているパスを探して、エラー部分を修正

C:\Program Files (x86)\Nodist\bin\node_modules@kintone\plugin-uploader\dist\index.js

.index.js
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = void 0;
const chalk_1 = __importDefault(require("chalk"));
const fs_1 = __importDefault(require("fs"));
const puppeteer_1 = __importDefault(require("puppeteer"));
const messages_1 = require("./messages");
const TIMEOUT_MS = 10000;
const UPLOAD_TIMEOUT_MS = 60000;
const launchBrowser = (proxy, ignoreDefaultArgs) => {
    const args = proxy ? [`--proxy-server=${proxy}`] : [];
    return puppeteer_1.default.launch({ args, ignoreDefaultArgs, headless: "new" });
};
const readyForUpload = (browser, baseUrl, userName, password, lang, basicAuth) => __awaiter(void 0, void 0, void 0, function* () {
    const m = (0, messages_1.getBoundMessage)(lang);
    const page = yield browser.newPage();
    const loginUrl = `${baseUrl}/login?saml=off`;
    if (basicAuth) {
        yield page.authenticate(basicAuth);
    }
    console.log(`Open ${loginUrl}`);
    yield page.goto(loginUrl);
    try {
        yield page.waitForSelector(".form-username-slash", { timeout: TIMEOUT_MS });
    }
    catch (e) {
        throw chalk_1.default.red(m("Error_cannotOpenLogin"));
    }
    console.log("Trying to log in...");
    yield page.type(".form-username-slash > input.form-text", userName);
    yield page.type(".form-password-slash > input.form-text", password);
    yield page.click(".login-button");
    try {
        yield page.waitForNavigation({
            timeout: TIMEOUT_MS,
            waitUntil: "domcontentloaded",
        });
    }
    catch (e) {
        throw chalk_1.default.red(m("Error_failedLogin"));
    }
    const pluginUrl = `${baseUrl}/k/admin/system/plugin/`;
    console.log(`Navigate to ${pluginUrl}`);
    yield page.goto(pluginUrl);
    try {
        yield page.waitForSelector("#root button.sc-bZHSRq.fHDQvG", {
            timeout: TIMEOUT_MS,
        });
    }
    catch (e) {
        throw chalk_1.default.red(m("Error_adminPrivilege"));
    }
    return page;
});
const upload = (page, pluginPath, lang) => __awaiter(void 0, void 0, void 0, function* () {
    const m = (0, messages_1.getBoundMessage)(lang);
    console.log(`Trying to upload ${pluginPath}`);

    yield page.evaluate(() => {
        const button1 = document.querySelector('#root button.sc-bZHSRq.fHDQvG');
        if (button1) {
            button1.click();
        }
        else {
            throw new Error('button.sc-bZHSRq.fHDQvG is not found');
        }
    });

    const file = yield page.$('input[type="file"]');
    if (file == null) {
        throw new Error('input[type="file"] is not found');
    }
    yield file.uploadFile(pluginPath);
    // HACK: `page.click` does not work as expected, so we use `page.evaluate` instead.
    // ref: https://github.com/puppeteer/puppeteer/pull/7097#issuecomment-850348366
    yield page.evaluate(() => {
        const button = document.querySelector('button.sc-ifyrAs.RhNPH');
        if (button) {
            button.click();
        }
        else {
            throw new Error('button.sc-ifyrAs.RhNPH is not found');
        }
    });
    yield page.waitForSelector(".sc-hABBmJ.fnsoHW", {
        hidden: true,
        timeout: UPLOAD_TIMEOUT_MS,
    });
    console.log(`${pluginPath} ${m("Uploaded")}`);
});
const run = (baseUrl, userName, password, pluginPath, options) => __awaiter(void 0, void 0, void 0, function* () {
    let browser = yield launchBrowser(options.proxyServer, options.puppeteerIgnoreDefaultArgs);
    let page;
    const { lang, basicAuth } = options;
    const m = (0, messages_1.getBoundMessage)(lang);
    try {
        page = yield readyForUpload(browser, baseUrl, userName, password, lang, basicAuth);
        yield upload(page, pluginPath, lang);
        if (options.watch) {
            let uploading = false;
            fs_1.default.watch(pluginPath, () => __awaiter(void 0, void 0, void 0, function* () {
                if (uploading) {
                    return;
                }
                try {
                    uploading = true;
                    yield upload(page, pluginPath, lang);
                }
                catch (e) {
                    console.log(e);
                    console.log(m("Error_retry"));
                    yield browser.close();
                    browser = yield launchBrowser(options.proxyServer);
                    page = yield readyForUpload(browser, baseUrl, userName, password, lang, basicAuth);
                    yield upload(page, pluginPath, lang);
                }
                finally {
                    uploading = false;
                }
            }));
        }
        else {
            yield browser.close();
        }
    }
    catch (e) {
        console.error(m("Error"), e);
        yield browser.close();
    }
});
exports.run = run;
//# sourceMappingURL=index.js.map
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1