diff --git a/packages/fx-core/src/component/generator/officeAddin/generator.ts b/packages/fx-core/src/component/generator/officeAddin/generator.ts index 12cde9e913..476d72db42 100644 --- a/packages/fx-core/src/component/generator/officeAddin/generator.ts +++ b/packages/fx-core/src/component/generator/officeAddin/generator.ts @@ -18,6 +18,7 @@ import { ok, } from "@microsoft/teamsfx-api"; import * as childProcess from "child_process"; +import fse from "fs-extra"; import { toLower } from "lodash"; import { OfficeAddinManifest } from "office-addin-manifest"; import { convertProject } from "office-addin-project"; @@ -256,6 +257,39 @@ export class OfficeAddinGeneratorNew extends DefaultTemplateGenerator { ): Promise> { const res = await OfficeAddinGenerator.doScaffolding(context, inputs, destinationPath); if (res.isErr()) return err(res.error); + await this.fixIconPath(destinationPath); return ok({}); } + + /** + * this is a work around for MOS API bug that will return invalid package if the icon path is not root folder of appPackage + * so this function will move the two icon files to root folder of appPackage and update the manifest.json + */ + async fixIconPath(projectPath: string): Promise { + const outlineOldPath = join(projectPath, "appPackage", "assets", "outline.png"); + const colorOldPath = join(projectPath, "appPackage", "assets", "color.png"); + const outlineNewPath = join(projectPath, "appPackage", "outline.png"); + const colorNewPath = join(projectPath, "appPackage", "color.png"); + const manifestPath = join(projectPath, "appPackage", "manifest.json"); + if (!(await fse.pathExists(manifestPath))) return; + const manifest = await fse.readJson(manifestPath); + let change = false; + if (manifest.icons.outline === "assets/outline.png") { + if ((await fse.pathExists(outlineOldPath)) && !(await fse.pathExists(outlineNewPath))) { + await fse.move(outlineOldPath, outlineNewPath); + manifest.icons.outline = "outline.png"; + change = true; + } + } + if (manifest.icons.color === "assets/color.png") { + if ((await fse.pathExists(colorOldPath)) && !(await fse.pathExists(colorNewPath))) { + await fse.move(colorOldPath, colorNewPath); + manifest.icons.color = "color.png"; + change = true; + } + } + if (change) { + await fse.writeJson(manifestPath, manifest, { spaces: 4 }); + } + } } diff --git a/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts b/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts index 123c70a016..0ebaa85580 100644 --- a/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts +++ b/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts @@ -1030,6 +1030,7 @@ describe("OfficeAddinGeneratorNew", () => { projectPath: "./", }; sandbox.stub(OfficeAddinGenerator, "doScaffolding").resolves(ok(undefined)); + sandbox.stub(generator, "fixIconPath").resolves(); const res = await generator.post(context, inputs, "./"); chai.assert.isTrue(res.isOk()); }); @@ -1044,4 +1045,85 @@ describe("OfficeAddinGeneratorNew", () => { chai.assert.isTrue(res.isErr()); }); }); + describe("fixIconPath()", () => { + const sandbox = sinon.createSandbox(); + afterEach(() => { + sandbox.restore(); + }); + it("manifest not found", async () => { + sandbox.stub(fse, "pathExists").resolves(false); + const move = sandbox.stub(fse, "move").resolves(); + await generator.fixIconPath("./"); + chai.assert.isTrue(move.notCalled); + }); + it("happy", async () => { + sandbox.stub(fse, "pathExists").callsFake(async (path) => { + if (path.endsWith("manifest.json")) { + return true; + } else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) { + return true; + } else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) { + return true; + } else if (path.endsWith("color.png")) { + return false; + } else if (path.endsWith("outline.png")) { + return false; + } + }); + sandbox + .stub(fse, "readJson") + .resolves({ icons: { outline: "assets/outline.png", color: "assets/color.png" } }); + const move = sandbox.stub(fse, "move").resolves(); + const writeJson = sandbox.stub(fse, "writeJson").resolves(); + await generator.fixIconPath("./"); + chai.assert.isTrue(move.calledTwice); + chai.assert.isTrue(writeJson.calledOnce); + }); + it("no need to move", async () => { + sandbox.stub(fse, "pathExists").callsFake(async (path) => { + if (path.endsWith("manifest.json")) { + return true; + } else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) { + return true; + } else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) { + return true; + } else if (path.endsWith("color.png")) { + return false; + } else if (path.endsWith("outline.png")) { + return false; + } + }); + sandbox + .stub(fse, "readJson") + .resolves({ icons: { outline: "outline.png", color: "color.png" } }); + const move = sandbox.stub(fse, "move").resolves(); + const writeJson = sandbox.stub(fse, "writeJson").resolves(); + await generator.fixIconPath("./"); + chai.assert.isTrue(move.notCalled); + chai.assert.isTrue(writeJson.notCalled); + }); + it("no need to move", async () => { + sandbox.stub(fse, "pathExists").callsFake(async (path) => { + if (path.endsWith("manifest.json")) { + return true; + } else if (path.endsWith("assets/outline.png") || path.endsWith("assets\\outline.png")) { + return false; + } else if (path.endsWith("assets/color.png") || path.endsWith("assets\\color.png")) { + return false; + } else if (path.endsWith("color.png")) { + return false; + } else if (path.endsWith("outline.png")) { + return false; + } + }); + sandbox + .stub(fse, "readJson") + .resolves({ icons: { outline: "assets/outline.png", color: "assets/color.png" } }); + const move = sandbox.stub(fse, "move").resolves(); + const writeJson = sandbox.stub(fse, "writeJson").resolves(); + await generator.fixIconPath("./"); + chai.assert.isTrue(move.notCalled); + chai.assert.isTrue(writeJson.notCalled); + }); + }); });