diff --git a/README.md b/README.md index d182d5e..99176c9 100644 --- a/README.md +++ b/README.md @@ -13,21 +13,21 @@ ## :information_source: Table of contents - [Deven Documentation Skeleton](#deven-documentation-skeleton) - - [:information\_source: Table of contents](#information_source-table-of-contents) + - [:information_source: Table of contents](#information_source-table-of-contents) - [:star: Introduction](#star-introduction) - [Goals](#goals) - - [:file\_folder: Documentation Structure](#file_folder-documentation-structure) + - [:file_folder: Documentation Structure](#file_folder-documentation-structure) - [Requirements](#requirements) - [Installation](#installation) - [:rocket: How to use it](#rocket-how-to-use-it) - [1. Install](#1-install) - [2. Check](#2-check) - [3. Update](#3-update) -- [:white\_check\_mark: How to test](#white_check_mark-how-to-test) +- [:white_check_mark: How to test](#white_check_mark-how-to-test) - [:v: Contribute](#v-contribute) - [:bug: Bugs and Issues](#bug-bugs-and-issues) -- [:page\_facing\_up: License](#page_facing_up-license) -- [:green\_heart: Code of conduct](#green_heart-code-of-conduct) +- [:page_facing_up: License](#page_facing_up-license) +- [:green_heart: Code of conduct](#green_heart-code-of-conduct) # :star: Introduction diff --git a/src/__tests__/command.spec.ts b/src/__tests__/command.spec.ts index 102ea0d..aeca7be 100644 --- a/src/__tests__/command.spec.ts +++ b/src/__tests__/command.spec.ts @@ -3,13 +3,11 @@ import * as fs from "fs-extra"; import { BaseCommand } from "../commands/command"; import mockFs from "mock-fs"; import { - mockProcessExit, mockProcessStdout, mockProcessStderr, mockConsoleLog, } from "jest-mock-process"; -let mockExit: jest.SpyInstance; let mockStdout: jest.SpyInstance; let mockStderr: jest.SpyInstance; let mockLog: jest.SpyInstance; @@ -18,14 +16,12 @@ let command: BaseCommand; describe("deven-cli", () => { afterEach(() => { mockFs.restore(); - mockExit.mockRestore(); mockStdout.mockRestore(); mockStderr.mockRestore(); mockLog.mockRestore(); jest.clearAllMocks(); }); beforeEach(() => { - mockExit = mockProcessExit(); mockStdout = mockProcessStdout(); mockStderr = mockProcessStderr(); mockLog = mockConsoleLog(); @@ -61,7 +57,7 @@ describe("deven-cli", () => { }); it("throws an error for docsPath if no documentation directory is set", async () => { expect(() => command.docsPath).toThrowError( - "#documentationDirectory has not been set yet. Please ensure that it has been set before trying to access it." + "documentationDirectory has not been set yet. Please ensure that it has been set before trying to access it." ); }); it("provides the right outdated doc path (/doc)", async () => { diff --git a/src/__tests__/update.spec.ts b/src/__tests__/update.spec.ts index f62bbdc..3c24cc7 100644 --- a/src/__tests__/update.spec.ts +++ b/src/__tests__/update.spec.ts @@ -4,7 +4,6 @@ import { Update } from "../commands"; import { logger } from "../Logger"; import mockFs from "mock-fs"; import { - mockProcessExit, mockProcessStdout, mockProcessStderr, mockConsoleLog, @@ -13,7 +12,6 @@ import { messages } from "../shared/messages"; import { ConfigFile } from "../interfaces"; import enquirer from "enquirer"; -let mockExit: jest.SpyInstance; let mockStdout: jest.SpyInstance; let mockStderr: jest.SpyInstance; let mockLog: jest.SpyInstance; @@ -29,7 +27,6 @@ let update: Update; describe("deven-cli", () => { afterEach(() => { mockFs.restore(); - mockExit.mockRestore(); mockStdout.mockRestore(); mockStderr.mockRestore(); mockLog.mockRestore(); @@ -38,7 +35,6 @@ describe("deven-cli", () => { jest.clearAllMocks(); }); beforeEach(() => { - mockExit = mockProcessExit(); mockStdout = mockProcessStdout(); mockStderr = mockProcessStderr(); mockLog = mockConsoleLog(); @@ -124,8 +120,33 @@ describe("deven-cli", () => { }); describe("updateOutdatedDirectoryName", () => { - it("does nothing if no outdated directory exists", async () => { - await update.updateOutdatedDirectoryName(); + it("does nothing if the documenation directory has been successfully read from the config", async () => { + update.documentationDirectory = "test"; + const result = await update.updateOutdatedDirectoryName(); + expect(result).toBeTruthy(); + }); + it("asks for the current documentation directory if none is in the config and no outdated doc directory exists", async () => { + const oldConfig = { ...mockConfig }; + // @ts-expect-error -- purposefully testing bad data + delete oldConfig.documentationDirectory; + fs.writeFileSync(update.configFilePath, JSON.stringify(oldConfig)); + enquirer.prompt = jest.fn().mockResolvedValue({ directory: "test" }); + fs.mkdirSync("fake_test_folder/test"); + const result = await update.updateOutdatedDirectoryName(); + expect(result).toBeTruthy(); + }); + it("throws and error if the documentation directory provided that should be written to the config does not exist", async () => { + const oldConfig = { ...mockConfig }; + // @ts-expect-error -- purposefully testing bad data + delete oldConfig.documentationDirectory; + fs.writeFileSync(update.configFilePath, JSON.stringify(oldConfig)); + enquirer.prompt = jest.fn().mockResolvedValue({ directory: "test" }); + const error = jest.spyOn(logger, "error"); + const result = await update.updateOutdatedDirectoryName(); + expect(error).toHaveBeenCalledWith( + messages.update.documentationDirectoryNotExists("test") + ); + expect(result).toBeFalsy(); }); it("throws an error if no directory is provided", async () => { const oldConfig = { ...mockConfig }; diff --git a/src/commands/command.ts b/src/commands/command.ts index b00d80e..98879b9 100644 --- a/src/commands/command.ts +++ b/src/commands/command.ts @@ -1,5 +1,6 @@ import * as path from "path"; import * as fs from "fs-extra"; +import { messages } from "../shared/messages"; export type BaseCliParams = { basePath: string | undefined; @@ -34,9 +35,7 @@ export class BaseCommand { get docsPath(): string { if (this.documentationDirectory === null) { - throw new Error( - "#documentationDirectory has not been set yet. Please ensure that it has been set before trying to access it." - ); + throw new Error(messages.error.documentationDirectoryNotSet); } return path.join(this.#basePath, this.documentationDirectory); @@ -118,7 +117,7 @@ export class BaseCommand { async run(): Promise { if (!this.steps) { - throw new Error("Command subclass must specify steps"); + throw new Error(messages.error.stepsNotSet); } for (const step of this.steps) { diff --git a/src/commands/update.ts b/src/commands/update.ts index a2f0676..8040d6a 100644 --- a/src/commands/update.ts +++ b/src/commands/update.ts @@ -77,44 +77,58 @@ export class Update extends BaseCommand { } public async updateOutdatedDirectoryName(): Promise { - if (!this.existsOutdatedDocFolder()) { + if (this.documentationDirectory) { return true; } - if (this.documentationDirectory === null) { - const documentationDirectory: { directory: string } = await prompt({ - type: "input", - initial: "docs", - name: "directory", - message: messages.update.useNewDocumentationDirectory, - }); + const promptMessage = this.existsOutdatedDocFolder() + ? messages.update.useNewDocumentationDirectory + : messages.update.provideExistingDocumenationDirectory; - if ( - documentationDirectory === undefined || - documentationDirectory.directory === "" - ) { - logger.error(messages.update.noDocumentationDirectoryProvided); + const documentationDirectory: { directory: string } = await prompt({ + type: "input", + initial: "docs", + name: "directory", + message: promptMessage, + }); + + if ( + documentationDirectory === undefined || + documentationDirectory.directory === "" + ) { + logger.error(messages.update.noDocumentationDirectoryProvided); + return false; + } + + this.documentationDirectory = documentationDirectory.directory; + + if (!this.existsOutdatedDocFolder()) { + if (!this.existsDocsFolder()) { + logger.error( + messages.update.documentationDirectoryNotExists( + this.documentationDirectory + ) + ); return false; } + return true; + } - this.documentationDirectory = documentationDirectory.directory; - - if (this.outdatedDocPath === this.docsPath) { - logger.info(messages.update.keepDocDirectory); - } else { - if (this.existsDocsFolder()) { - logger.error( - messages.update.documentationDirectoryExists( - this.documentationDirectory - ) - ); - return false; - } - fs.renameSync(this.outdatedDocPath, this.docsPath); - logger.info( - messages.update.renamedOutdatedDocFolder(this.documentationDirectory) + if (this.outdatedDocPath === this.docsPath) { + logger.info(messages.update.keepDocDirectory); + } else { + if (this.existsDocsFolder()) { + logger.error( + messages.update.documentationDirectoryExists( + this.documentationDirectory + ) ); + return false; } + fs.renameSync(this.outdatedDocPath, this.docsPath); + logger.info( + messages.update.renamedOutdatedDocFolder(this.documentationDirectory) + ); } return true; diff --git a/src/shared/__tests__/messages.spec.ts b/src/shared/__tests__/messages.spec.ts index 81a3bf7..974ffbc 100644 --- a/src/shared/__tests__/messages.spec.ts +++ b/src/shared/__tests__/messages.spec.ts @@ -6,6 +6,16 @@ const stripAnsi = (s: string): string => ); describe("messages", () => { + it("error: documentationDirectoryNotSet", async () => { + expect(stripAnsi(messages.error.documentationDirectoryNotSet)).toBe( + "documentationDirectory has not been set yet. Please ensure that it has been set before trying to access it." + ); + }); + it("error: stepsNotSet", async () => { + expect(stripAnsi(messages.error.stepsNotSet)).toBe( + "Command subclass must specify steps" + ); + }); it("selectDocumentationDirectory", async () => { expect(messages.install.selectDocumentationDirectory).toContain( "Please enter the name of the documentation directory that should be created." @@ -148,6 +158,13 @@ describe("messages", () => { "The config file hasn't been found." ); }); + it("provideExistingDocumenationDirectory", async () => { + expect( + stripAnsi(messages.update.provideExistingDocumenationDirectory) + ).toContain( + `The name of the documentation directory is missing in the config file and it's not the directory the files where installed at initially ("doc").` + ); + }); it("useNewDocumentationDirectory", async () => { expect(stripAnsi(messages.update.useNewDocumentationDirectory)).toContain( 'The current documentation directory is "doc". The new suggestion for this directory is "docs", so GitHub can auto-detect files like the Code of Conduct, but you can also switch to any other directory.' @@ -160,6 +177,13 @@ describe("messages", () => { 'Please, run the "update" command again and provide a name for the documentation directory.' ); }); + it("documentationDirectoryNotExists", async () => { + expect( + stripAnsi(messages.update.documentationDirectoryNotExists("test").message) + ).toBe( + `The selected directory "test" doesn't exist. Please, run the "update" command again and provide the name of your current documentation directory.` + ); + }); it("documentationDirectoryExists", async () => { expect( stripAnsi(messages.update.documentationDirectoryExists("test").message) diff --git a/src/shared/messages.ts b/src/shared/messages.ts index cf3c56a..976af12 100644 --- a/src/shared/messages.ts +++ b/src/shared/messages.ts @@ -6,6 +6,11 @@ export type Message = { }; export const messages = { + error: { + documentationDirectoryNotSet: + "documentationDirectory has not been set yet. Please ensure that it has been set before trying to access it.", + stepsNotSet: "Command subclass must specify steps", + }, install: { selectDocumentationDirectory: 'Please enter the name of the documentation directory that should be created.\nIf the directory already exists, name clashes will have to be resolved manually.\nIf possible, the default of "docs" should be used, so GitHub can auto-detect files like the Code of Conduct.\nDocumentation directory:', @@ -193,12 +198,22 @@ export const messages = { }, useNewDocumentationDirectory: 'The current documentation directory is "doc". The new suggestion for this directory is "docs", so GitHub can auto-detect files like the Code of Conduct, but you can also switch to any other directory.\nIf the directory already exists, name clashes will have to be resolved manually.\nDocumentation directory:', + provideExistingDocumenationDirectory: + 'The name of the documentation directory is missing in the config file and it\'s not the directory the files where installed at initially ("doc").\nPlease provide the name of the current documentation directory:', noDocumentationDirectoryProvided: { prefix: "[update]", message: `Please, run the "update" command again and ${chalk.bold( "provide a name for the documentation directory" )}.`, }, + documentationDirectoryNotExists: (directory: string) => { + return { + prefix: "[update]", + message: `The selected directory "${directory}" doesn't exist. Please, run the "update" command again and ${chalk.bold( + "provide the name of your current documentation directory" + )}.`, + }; + }, documentationDirectoryExists: (directory: string) => { return { prefix: "[update]",