Skip to content

Commit eee00c6

Browse files
committed
Remove temporary attachments after upload
Fix build after axios upgrade
1 parent 6b097a5 commit eee00c6

15 files changed

+29
-57
lines changed

CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
- Added capability of running Cosmere as a script library.
1515
- Added support for custom renderers.
16-
- Added `cleanupLocalAttachmentFiles` option.
16+
17+
### Changed
18+
19+
- Local copies of attachment are no longer stored, because caching is done by comparing filename and size instead
1720

1821
## [0.16.0] - 2022-07-12
1922

README.md

-6
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ which produces:
4646
"baseUrl": "<your base url including /rest/api>",
4747
"user": "<your username>",
4848
"pass": "<your password>",
49-
"cleanupLocalAttachmentFiles": false,
5049
"personalAccessToken": "<your personal access token (can be set instead of username/password)>",
5150
"cachePath": "build",
5251
"prefix": "This document is automatically generated. Please don't edit it directly!",
@@ -60,8 +59,6 @@ which produces:
6059
}
6160
```
6261

63-
If `cleanupLocalAttachmentFiles` is set to true, we disable caching attachment files locally.
64-
6562
### Continuous Integration
6663

6764
In most scenarios it is not recommended storing your credentials in the configuration file, because you will probably add it to your VCS. Instead, it is recommended to provide the following environment variables in your build pipeline (GitLab CI, GitHub Actions, Jenkins, ...):
@@ -138,7 +135,6 @@ const config = {
138135
prefix: "This document is automatically generated. Please don't edit it directly!",
139136
insecure: false,
140137
force: false,
141-
cleanupLocalAttachmentFiles: true,
142138
fileRoot: "/usr/bin/myawesomefolder",
143139
pages: [
144140
{
@@ -153,8 +149,6 @@ const config = {
153149
await cosmere(config);
154150
```
155151

156-
If `cleanupLocalAttachmentFiles` is set to true, we disable caching attachment files locally.
157-
158152
## Troubleshooting
159153

160154
### Custom certificates on Confluence instance

src/FileConfigLoader.ts

-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ export class FileConfigLoader {
110110
pages: fileConfig.pages,
111111
configPath: fileConfig.configPath,
112112
authorizationToken: authorizationToken,
113-
cleanupLocalAttachmentFiles: fileConfig.cleanupLocalAttachmentFiles,
114113
};
115114
}
116115
}

src/ObjectConfigLoader.ts

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ export class ObjectConfigLoader {
6464
configPath: config.fileRoot || process.cwd(),
6565
customRenderer: config.customRenderer,
6666
authorizationToken: authorizationToken,
67-
cleanupLocalAttachmentFiles: config.cleanupLocalAttachmentFiles,
6867
};
6968
}
7069
}

src/UpdatePage.ts

+9-26
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,7 @@ async function deleteOutOfDateAttachments(
123123
}
124124
}
125125

126-
function deleteLocalAttachmentFiles(attachments: Picture[]) {
127-
for (const attachment of attachments.filter((attachment) => fs.existsSync(attachment.remoteFileName))) {
128-
fs.unlinkSync(attachment.remoteFileName);
129-
}
130-
signale.success("Local cleanup successful");
131-
}
132-
133-
async function updateAttachments(
134-
mdWikiData: string,
135-
pageData: Page,
136-
cachePath: string,
137-
confluenceAPI: ConfluenceAPI,
138-
shouldCleanupLocalFiles: boolean,
139-
) {
126+
async function updateAttachments(mdWikiData: string, pageData: Page, cachePath: string, confluenceAPI: ConfluenceAPI) {
140127
const remoteAttachments = (await confluenceAPI.getAttachments(pageData.pageId)).results;
141128
let attachments = extractAttachmentsFromPage(pageData, mdWikiData).map((attachment) =>
142129
mapLocalToRemoteAttachments(attachment, remoteAttachments),
@@ -147,15 +134,17 @@ async function updateAttachments(
147134

148135
await deleteOutOfDateAttachments(attachments, remoteAttachments, confluenceAPI);
149136
for (const attachment of attachments.filter((attachment) => !attachment.remoteAttachmentId)) {
150-
fs.copyFileSync(attachment.originalAbsolutePath, attachment.remoteFileName);
137+
const temporaryAttachmentPath = path.join(cachePath, attachment.remoteFileName);
138+
fs.copyFileSync(attachment.originalAbsolutePath, temporaryAttachmentPath);
151139

152140
signale.await(`Uploading attachment "${attachment.remoteFileName}" for "${pageData.title}" ...`);
153-
await confluenceAPI.uploadAttachment(attachment.remoteFileName, pageData.pageId);
141+
try {
142+
await confluenceAPI.uploadAttachment(attachment.remoteFileName, pageData.pageId);
143+
} finally {
144+
fs.unlinkSync(temporaryAttachmentPath);
145+
}
154146
}
155147

156-
if (shouldCleanupLocalFiles) {
157-
deleteLocalAttachmentFiles(attachments);
158-
}
159148
mdWikiData = mdWikiData.replace(/<ri:attachment ri:filename=".+?"/g, (s: string) => s.replace(/(\.\.|\/)/g, "_"));
160149
return mdWikiData;
161150
}
@@ -218,13 +207,7 @@ export async function updatePage(confluenceAPI: ConfluenceAPI, pageData: Page, c
218207
return;
219208
}
220209

221-
mdWikiData = await updateAttachments(
222-
mdWikiData,
223-
pageData,
224-
cachePath,
225-
confluenceAPI,
226-
config.cleanupLocalAttachmentFiles,
227-
);
210+
mdWikiData = await updateAttachments(mdWikiData, pageData, cachePath, confluenceAPI);
228211
signale.await(`Fetch current page for "${pageData.title}" ...`);
229212
const confluencePage = (await confluenceAPI.currentPage(pageData.pageId)).data;
230213
if (!force && !isRemoteUpdateRequired(mdWikiData, confluencePage)) {

src/cli/MainCommand.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Config } from "../types/Config";
2-
import { FileConfigLoader } from "../FileConfigLoader";
32
import { ConfluenceAPI } from "../api/ConfluenceAPI";
43
import { updatePage } from "../UpdatePage";
4+
import { FileConfigLoader } from "../FileConfigLoader";
55

66
export default async function (configPath: string | null, force: boolean = false, insecure: boolean = false) {
77
const config: Config = await FileConfigLoader.load(configPath);

src/types/BaseConfig.ts

-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ export type BaseConfig = {
44
baseUrl: string;
55
cachePath: string;
66
prefix: string;
7-
cleanupLocalAttachmentFiles: boolean;
87
pages: Page[];
98
};

tests/ConfluenceRenderer.test.ts

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ describe("ConfluenceRenderer", () => {
1111
pages: [currentPage, { pageId: "456", title: "", file: "/tmp/other.md" }],
1212
configPath: "",
1313
authorizationToken: "",
14-
cleanupLocalAttachmentFiles: false,
1514
};
1615

1716
beforeEach(() => {

tests/FileConfigLoader.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { FileConfigLoader } from "../src/FileConfigLoader";
2+
import { BaseConfig } from "../src/types/BaseConfig";
23

34
describe("FileConfigLoader", () => {
45
it("should create bearer token from personal access token", async () => {
@@ -19,7 +20,7 @@ describe("FileConfigLoader", () => {
1920
});
2021
});
2122

22-
const irrelevantConfigFields = {
23+
const irrelevantConfigFields: BaseConfig = {
2324
baseUrl: "https://confluence.custom.host/rest/api",
2425
cachePath: "cache/",
2526
pages: [
@@ -29,6 +30,5 @@ describe("FileConfigLoader", () => {
2930
},
3031
],
3132
prefix: "This document is automatically generated. Please don't edit it directly!",
32-
cleanupLocalAttachmentFiles: false,
3333
};
3434
});

tests/ObjectConfigLoader.test.ts

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { ObjectConfigLoader } from "../src/ObjectConfigLoader";
2+
import { ObjectConfig } from "../src/types/ObjectConfig";
3+
import { BaseConfig } from "../src/types/BaseConfig";
24

35
describe("ObjectConfigLoader", () => {
4-
const objectConfigurationWithPersonalAccessToken = {
6+
const objectConfigurationWithPersonalAccessToken: ObjectConfig = {
57
baseUrl: "https://confluence.custom.host/rest/api",
68
personalAccessToken: "unbearable",
79
prefix: "This document is automatically generated. Please don't edit it directly!",
@@ -15,10 +17,9 @@ describe("ObjectConfigLoader", () => {
1517
],
1618
insecure: false,
1719
force: false,
18-
cleanupLocalAttachmentFiles: false,
1920
};
2021

21-
const objectConfigurationWithUserPass = {
22+
const objectConfigurationWithUserPass: ObjectConfig = {
2223
baseUrl: "https://confluence.custom.host/rest/api",
2324
user: "user",
2425
pass: "pass",
@@ -33,7 +34,6 @@ describe("ObjectConfigLoader", () => {
3334
],
3435
insecure: false,
3536
force: false,
36-
cleanupLocalAttachmentFiles: false,
3737
};
3838

3939
it("should create bearer token from personal access token", async () => {
@@ -52,7 +52,7 @@ describe("ObjectConfigLoader", () => {
5252
});
5353
});
5454

55-
const irrelevantConfigFields = {
55+
const irrelevantConfigFields: BaseConfig & Pick<ObjectConfig, "customRenderer"> = {
5656
baseUrl: "https://confluence.custom.host/rest/api",
5757
cachePath: "cache/",
5858
pages: [
@@ -63,6 +63,5 @@ describe("ObjectConfigLoader", () => {
6363
],
6464
prefix: "This document is automatically generated. Please don't edit it directly!",
6565
customRenderer: undefined,
66-
cleanupLocalAttachmentFiles: false,
6766
};
6867
});

tests/UpdatePage.test.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ describe("UpdatePage", () => {
1313
};
1414
const config: Config = {
1515
baseUrl: "string",
16-
cachePath: "string",
16+
cachePath: "build",
1717
prefix: "string",
1818
pages: [],
1919
configPath: "...",
2020
authorizationToken: "Bearer unbearable",
21-
cleanupLocalAttachmentFiles: false,
2221
};
2322
const confluenceApi = new ConfluenceAPI("", "Bearer unbearable", false);
2423
confluenceApi.getAttachments = jest.fn().mockResolvedValueOnce({
@@ -50,13 +49,12 @@ describe("UpdatePage", () => {
5049
const customRendererFunction = jest.fn();
5150
const config: Config = {
5251
baseUrl: "string",
53-
cachePath: "string",
52+
cachePath: "build",
5453
prefix: "string",
5554
pages: [],
5655
configPath: "...",
5756
authorizationToken: "Bearer unbearable",
5857
customRenderer: customRendererFunction,
59-
cleanupLocalAttachmentFiles: false,
6058
};
6159
const confluenceApi = new ConfluenceAPI("", "Bearer unbearable", false);
6260
confluenceApi.getAttachments = jest.fn().mockResolvedValueOnce({

tests/cli/MainCommand.test.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Config } from "../../src/types/Config";
2+
13
jest.mock("../../src/UpdatePage");
24
jest.mock("../../src/FileConfigLoader");
35
jest.mock("../../src/api/ConfluenceAPI");
@@ -26,11 +28,10 @@ describe("MainCommand", () => {
2628
file: generateRandomString(),
2729
});
2830
}
29-
const config = {
31+
const config: Config = {
3032
baseUrl: "baseUrl",
3133
cachePath: ".cache",
3234
prefix: "prefix",
33-
cleanupLocalAttachmentFiles: false,
3435
pages: randomPages,
3536
configPath: "path",
3637
authorizationToken: "token",

tests/resources/test-config-with-personal-access-token-auth.json

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"personalAccessToken": "unbearable",
44
"prefix": "This document is automatically generated. Please don't edit it directly!",
55
"cachePath": "cache/",
6-
"cleanupLocalAttachmentFiles": false,
76
"pages": [
87
{
98
"pageId": "123456789",

tests/resources/test-config-with-user-pass-auth.json

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"pass": "pass",
55
"prefix": "This document is automatically generated. Please don't edit it directly!",
66
"cachePath": "cache/",
7-
"cleanupLocalAttachmentFiles": false,
87
"pages": [
98
{
109
"pageId": "123456789",

tsconfig.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"compilerOptions": {
33
/* Basic Options */
44
// "incremental": true, /* Enable incremental compilation */
5-
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
6-
// "module": "amd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"target": "ES2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
6+
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
77
"lib": ["esnext"] /* Specify library files to be included in the compilation. */,
88
// "allowJs": true, /* Allow javascript files to be compiled. */
99
// "checkJs": true, /* Report errors in .js files. */
@@ -39,7 +39,7 @@
3939
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
4040

4141
/* Module Resolution Options */
42-
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
42+
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
4343
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
4444
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
4545
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */

0 commit comments

Comments
 (0)