Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
6 changes: 6 additions & 0 deletions components/markdown-confluence-sync/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
#### Deprecated
#### Removed

## [2.1.0] - 2025-06-10

### Added

* feat: Add `dryRun` option, enabling to run the sync process without actually sending the content to Confluence. This is useful for testing the configuration and markdown files without making changes in Confluence.

## [2.0.1] - 2025-04-15

### Changed
Expand Down
1 change: 1 addition & 0 deletions components/markdown-confluence-sync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ The namespace for the configuration of this library is `markdown-confluence-sync
| `confluence.noticeMessage` | `string` | Notice message to add at the beginning of the Confluence pages. | |
| `confluence.noticeTemplate` | `string` | Template string to use for the notice message. | |
| `confluence.dryRun` | `boolean` | Log create, update or delete requests to Confluence instead of really making them | `false` |
| `dryRun` | `boolean` | Process markdown files without sending them to `confluence-sync`. Useful to early detection of possible errors in configuration, etc. Note that, requests that would be made to Confluence won't be logged, use `confluence.dryRun` for that, which also connects to Confluence to calculate the requests to do | `false` |
| `config.readArguments` | `boolean` | Read configuration from arguments or not | `false` |
| `config.readFile` | `boolean` | Read configuration from file or not | `false` |
| `config.readEnvironment` | `boolean` | Read configuration from environment or not | `false` |
Expand Down
2 changes: 1 addition & 1 deletion components/markdown-confluence-sync/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@telefonica/markdown-confluence-sync",
"description": "Creates/updates/deletes Confluence pages based on markdown files in a directory. Supports Mermaid diagrams and per-page configuration using frontmatter metadata. Works great with Docusaurus",
"version": "2.0.1",
"version": "2.1.0",
"license": "Apache-2.0",
"author": "Telefónica Innovación Digital",
"repository": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import type {
FilesMetadataOption,
ContentPreprocessorOptionDefinition,
ContentPreprocessorOption,
MainDryRunOptionDefinition,
MainDryRunOption,
} from "./MarkdownConfluenceSync.types.js";

const MODULE_NAME = "markdown-confluence-sync";
Expand Down Expand Up @@ -78,6 +80,13 @@ const contentPreprocessorOption: ContentPreprocessorOptionDefinition = {
type: "unknown",
};

const dryRunOption: MainDryRunOptionDefinition = {
name: "dryRun",
type: "boolean",
default: false,
description: "Process markdown files without sending them to confluence-sync",
};

export const MarkdownConfluenceSync: MarkdownConfluenceSyncConstructor = class MarkdownConfluenceSync
implements MarkdownConfluenceSyncInterface
{
Expand All @@ -93,6 +102,7 @@ export const MarkdownConfluenceSync: MarkdownConfluenceSyncConstructor = class M
private _filesMetadataOption: FilesMetadataOption;
private _filesIgnoreOption: FilesIgnoreOption;
private _contentPreprocessorOption: ContentPreprocessorOption;
private _dryRunOption: MainDryRunOption;
private _cwd: string;

constructor(config: Configuration) {
Expand Down Expand Up @@ -128,6 +138,10 @@ export const MarkdownConfluenceSync: MarkdownConfluenceSyncConstructor = class M
contentPreprocessorOption as ContentPreprocessorOptionDefinition,
) as unknown as ContentPreprocessorOption;

this._dryRunOption = this._configuration.addOption(
dryRunOption as MainDryRunOptionDefinition,
);

const markdownLogger = this._logger.namespace(MARKDOWN_NAMESPACE);

const confluenceConfig =
Expand All @@ -154,9 +168,16 @@ export const MarkdownConfluenceSync: MarkdownConfluenceSyncConstructor = class M
public async sync(): Promise<void> {
await this._init();
const pages = await this._markdownDocuments.read();
await this._confluenceSync.sync(
this._markdownPagesToConfluencePages(pages),
);
const convertedPages = this._markdownPagesToConfluencePages(pages);
const dryRun = this._dryRunOption.value;
if (dryRun) {
this._logger.info(
"Dry run mode is enabled. No changes will be made to Confluence.",
);
return;
}

await this._confluenceSync.sync(convertedPages);
}

private async _init() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export type FilesMetadata = FileMetadata[];

export type ContentPreprocessor = (content: string, path: string) => string;

export type DryRun = boolean;

declare global {
//eslint-disable-next-line @typescript-eslint/no-namespace
namespace MarkdownConfluenceSync {
Expand Down Expand Up @@ -61,6 +63,9 @@ declare global {

/** Hook enabling to modify the content of files before processing them */
preprocessor?: ContentPreprocessor;

/** Process markdown files without sending them to confluence-sync */
dryRun?: DryRun;
}
}
}
Expand Down Expand Up @@ -103,6 +108,13 @@ export type ContentPreprocessorOptionDefinition =
export type ContentPreprocessorOption =
OptionInterfaceOfType<ContentPreprocessor>;

export type MainDryRunOptionDefinition = OptionDefinition<
boolean,
{ hasDefault: true }
>;

export type MainDryRunOption = OptionInterfaceOfType<boolean, { hasDefault: true }>;

/** Creates a MarkdownConfluenceSync interface */
export interface MarkdownConfluenceSyncConstructor {
/** Returns MarkdownConfluenceSync interface
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
id: foo-ignored-index
title: foo-ignored-index-title
sync_to_confluence: true
---

# Hello World
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2024 Telefónica Innovación Digital
// SPDX-License-Identifier: MIT

const path = require("node:path");

module.exports = {
confluence: {
url: "https://my-confluence.com",
spaceKey: "FOO",
},
docsDir: path.join(__dirname, "./docs"),
dryRun: true,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: 2024 Telefónica Innovación Digital
// SPDX-License-Identifier: Apache-2.0

import { ChildProcessManager } from "@telefonica/child-process-manager";
import type { ChildProcessManagerInterface } from "@telefonica/child-process-manager";

import { cleanLogs } from "../support/Logs";
import {
getFixtureFolder,
getBinaryPathFromFixtureFolder,
} from "../support/Paths";

describe("dryRun mode", () => {
let cli: ChildProcessManagerInterface;

beforeEach(() => {
process.env.MARKDOWN_CONFLUENCE_SYNC_LOG_LEVEL = "debug";
cli = new ChildProcessManager([getBinaryPathFromFixtureFolder()], {
cwd: getFixtureFolder("dry-run"),
silent: true,
});
});

afterEach(async () => {
await cli.kill();
});

describe("when dryRun option is true", () => {
it("should exit with code 1 when there are errors in markdown", async () => {
const { exitCode, logs } = await cli.run();

const allLogs = cleanLogs(logs).join("\n");

expect(allLogs).toContain(`Title is required:`);
expect(allLogs).toContain(`dry-run/docs/foo.md`);
expect(allLogs).toContain(
`Please provide it using frontmatter or filesMetadata option`,
);
expect(exitCode).toBe(1);
});

it("should not call to synchronize", async () => {
cli = new ChildProcessManager([getBinaryPathFromFixtureFolder()], {
cwd: getFixtureFolder("mock-server-with-confluence-title"),
silent: true,
env: {
MARKDOWN_CONFLUENCE_SYNC_DRY_RUN: "true",
},
});
const { logs } = await cli.run();

const allLogs = cleanLogs(logs).join("\n");

expect(allLogs).toContain(
`Dry run mode is enabled. No changes will be made to Confluence.`,
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ describe("markdownConfluenceSync", () => {
);
});

it("should not call to synchronize if dryRun is true", async () => {
// Arrange
const markdownConfluenceSync = new MarkdownConfluenceSync({
...CONFIG,
dryRun: true,
});

// Act
await markdownConfluenceSync.sync();

// Assert
expect(customConfluenceSync.sync).not.toHaveBeenCalled();
});

it("when called twice, it should send to synchronize the pages to confluence twice", async () => {
// Arrange
const markdownConfluenceSync = new MarkdownConfluenceSync(CONFIG);
Expand Down
Loading