joplin-plugin-backup 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,8 +2,35 @@
2
2
 
3
3
  A plugin to extend Joplin with a manual and automatic backup function.
4
4
 
5
+ <!-- markdownlint-disable MD033 -->
6
+ <!-- markdownlint-disable MD028 -->
7
+ <!-- markdownlint-disable MD007 -->
8
+
5
9
  <img src=img/main.jpg>
6
10
 
11
+ <!-- prettier-ignore-start -->
12
+ <!-- TOC depthfrom:2 orderedlist:false -->
13
+
14
+ - [Installation](#installation)
15
+ - [Automatic](#automatic)
16
+ - [Manual](#manual)
17
+ - [Usage](#usage)
18
+ - [Options](#options)
19
+ - [Keyboard Shortcuts](#keyboard-shortcuts)
20
+ - [What is backed up](#what-is-backed-up)
21
+ - [Restore](#restore)
22
+ - [Settings](#settings)
23
+ - [Notes](#notes)
24
+ - [FAQ](#faq)
25
+ - [Internal Joplin links betwen notes are lost](#internal-joplin-links-betwen-notes-are-lost)
26
+ - [Combine multiple JEX Files to one](#combine-multiple-jex-files-to-one)
27
+ - [Open a JEX Backup file](#open-a-jex-backup-file)
28
+ - [Changelog](#changelog)
29
+ - [Links](#links)
30
+
31
+ <!-- /TOC -->
32
+ <!-- prettier-ignore-end -->
33
+
7
34
  ## Installation
8
35
 
9
36
  ### Automatic
@@ -33,7 +60,7 @@ Go to `Tools > Options > Backup`
33
60
 
34
61
  | Option | Description | Default |
35
62
  | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------- |
36
- | `Backup path` | Where to save the backups to. <br>This path is exclusive for the Joplin backups, there should be no other data in it! | |
63
+ | `Backup path` | Where to save the backups to. <br>This path is exclusive for the Joplin backups, there should be no other data in it when you disable the `Create Subfolder` settings! | |
37
64
  | `Keep x backups` | How many backups should be kept | `1` |
38
65
  | `Backups interval in hours` | Create a backup every X hours | `24` |
39
66
  | `Only on change` | Creates a backup at the specified backup interval only if there was a change to a `note`, `tag`, `resource` or `notebook` | `false` |
@@ -44,6 +71,8 @@ Go to `Tools > Options > Backup`
44
71
  | `Temporary export path` | The data is first exported into this path before it is copied to the backup `Backup path`. | `` |
45
72
  | `Backup set name` | Name of the backup set if multiple backups are to be keep. [Available moment tokens](https://momentjs.com/docs/#/displaying/format/), which can be used with `{<TOKEN>}` | `{YYYYMMDDHHmm}` |
46
73
  | `Single JEX` | Create only one JEX file for all, this option is recommended to prevent the loss of internal note links or folder structure during a restore! | `true` |
74
+ | `Export format` | Selection of the export format of the notes. | `jex` |
75
+ | `Command on Backup finish` | Execute command when backup is finished. | |
47
76
  | `Create Subfolder` | Create a sub folder `JoplinBackup` in the configured `Backup path`. Deactivate only if there is no other data in the `Backup path`! | `true` |
48
77
  | `Backup plugins` | Backup the plugin folder from the Joplin profile with all installed plugin jpl files. | `true` |
49
78
 
@@ -79,7 +108,7 @@ The notes are imported via `File > Import > JEX - Joplin Export File`.
79
108
  > Individual notes cannot be restored from the JEX file!
80
109
 
81
110
  The notes are imported additionally, no check for duplicates is performed.
82
- If the folder in which the note was located already exists in you Joplin, than the folder name is extended by one (1).
111
+ If the notebook in which the note was located already exists in your Joplin, then a "(1)" will be appended to the folder name.
83
112
 
84
113
  ## FAQ
85
114
 
@@ -88,7 +117,7 @@ If the folder in which the note was located already exists in you Joplin, than t
88
117
  If several JEX files are imported and the notes have links to each other, these links will be lost.
89
118
  Therefore it is recommended to create a Single JEX Backup!
90
119
 
91
- ### Compine multiple JEX Files to one
120
+ ### Combine multiple JEX Files to one
92
121
 
93
122
  By combining the JEX files into one, the Joplin internal links will work again after the import.
94
123
 
@@ -15,6 +15,7 @@ function getTestPaths(): any {
15
15
  );
16
16
  testPath.joplinProfile = path.join(testPath.base, "joplin-desktop");
17
17
  testPath.templates = path.join(testPath.joplinProfile, "templates");
18
+ testPath.plugins = path.join(testPath.joplinProfile, "plugins");
18
19
  return testPath;
19
20
  }
20
21
 
@@ -39,6 +40,7 @@ async function createTestStructure() {
39
40
  fs.emptyDirSync(test.backupBasePath);
40
41
  fs.emptyDirSync(test.joplinProfile);
41
42
  fs.emptyDirSync(test.templates);
43
+ fs.emptyDirSync(test.plugins);
42
44
  }
43
45
 
44
46
  const testPath = getTestPaths();
@@ -573,6 +575,45 @@ describe("Backup", function () {
573
575
  });
574
576
 
575
577
  describe("Backup retention", function () {
578
+ it(`file/Folder deletion`, async () => {
579
+ const backupRetention = 2;
580
+ const set1 = path.join(testPath.backupBasePath, "202101011630");
581
+ const set2 = path.join(testPath.backupBasePath, "202101021630.7z");
582
+ const set3 = path.join(testPath.backupBasePath, "202101031630");
583
+ const set4 = path.join(testPath.backupBasePath, "202101041630.7z");
584
+
585
+ fs.emptyDirSync(set1);
586
+ fs.closeSync(fs.openSync(set2, "w"));
587
+ fs.emptyDirSync(set3);
588
+ fs.closeSync(fs.openSync(set4, "w"));
589
+
590
+ const backupInfo = [
591
+ { name: "202101011630", date: 1609515000 },
592
+ { name: "202101021630.7z", date: 1609601400 },
593
+ { name: "202101031630", date: 1609687800 },
594
+ { name: "202101041630.7z", date: 1609774200 },
595
+ ];
596
+
597
+ when(spyOnsSettingsValue)
598
+ .calledWith("backupInfo")
599
+ .mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));
600
+
601
+ expect(fs.existsSync(set1)).toBe(true);
602
+ expect(fs.existsSync(set2)).toBe(true);
603
+ expect(fs.existsSync(set3)).toBe(true);
604
+ expect(fs.existsSync(set4)).toBe(true);
605
+ await backup.deleteOldBackupSets(
606
+ testPath.backupBasePath,
607
+ backupRetention
608
+ );
609
+
610
+ expect(fs.existsSync(set1)).toBe(false);
611
+ expect(fs.existsSync(set2)).toBe(false);
612
+ expect(fs.existsSync(set3)).toBe(true);
613
+ expect(fs.existsSync(set4)).toBe(true);
614
+ expect(fs.readdirSync(testPath.backupBasePath).length).toBe(2);
615
+ });
616
+
576
617
  it(`Backups < retention`, async () => {
577
618
  const backupRetention = 3;
578
619
  const folder1 = path.join(testPath.backupBasePath, "202101011630");
@@ -585,11 +626,15 @@ describe("Backup", function () {
585
626
  { name: "202101011630", date: 1 },
586
627
  { name: "202101021630", date: 2 },
587
628
  ];
588
- /* prettier-ignore */
629
+
589
630
  when(spyOnsSettingsValue)
590
- .calledWith("backupInfo").mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));
631
+ .calledWith("backupInfo")
632
+ .mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));
591
633
 
592
- backup.deleteOldBackupSets(testPath.backupBasePath, backupRetention);
634
+ await backup.deleteOldBackupSets(
635
+ testPath.backupBasePath,
636
+ backupRetention
637
+ );
593
638
 
594
639
  const folderAnz = fs
595
640
  .readdirSync(testPath.backupBasePath, { withFileTypes: true })
@@ -616,11 +661,15 @@ describe("Backup", function () {
616
661
  { name: "202101021630", date: 2 },
617
662
  { name: "202101031630", date: 3 },
618
663
  ];
619
- /* prettier-ignore */
664
+
620
665
  when(spyOnsSettingsValue)
621
- .calledWith("backupInfo").mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));
666
+ .calledWith("backupInfo")
667
+ .mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));
622
668
 
623
- backup.deleteOldBackupSets(testPath.backupBasePath, backupRetention);
669
+ await backup.deleteOldBackupSets(
670
+ testPath.backupBasePath,
671
+ backupRetention
672
+ );
624
673
  const folderAnz = fs
625
674
  .readdirSync(testPath.backupBasePath, { withFileTypes: true })
626
675
  .filter((dirent) => dirent.isDirectory()).length;
@@ -653,9 +702,10 @@ describe("Backup", function () {
653
702
  { name: "202101041630", date: 4 },
654
703
  { name: "202101051630", date: 5 },
655
704
  ];
656
- /* prettier-ignore */
705
+
657
706
  when(spyOnsSettingsValue)
658
- .calledWith("backupInfo").mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));
707
+ .calledWith("backupInfo")
708
+ .mockImplementation(() => Promise.resolve(JSON.stringify(backupInfo)));
659
709
 
660
710
  await backup.deleteOldBackupSets(
661
711
  testPath.backupBasePath,
@@ -835,12 +885,14 @@ describe("Backup", function () {
835
885
  const userstyle = path.join(testPath.joplinProfile, "userstyle.css");
836
886
  const userchrome = path.join(testPath.joplinProfile, "userchrome.css");
837
887
  const keymap = path.join(testPath.joplinProfile, "keymap-desktop.json");
888
+ const plugin = path.join(testPath.plugins, "test-plugin.jpl");
838
889
 
839
890
  fs.writeFileSync(template, "template");
840
891
  fs.writeFileSync(settings, "settings");
841
892
  fs.writeFileSync(userstyle, "userstyle");
842
893
  fs.writeFileSync(userchrome, "userchrome");
843
894
  fs.writeFileSync(keymap, "keymap");
895
+ fs.writeFileSync(plugin, "plugin");
844
896
 
845
897
  fs.emptyDirSync(testPath.activeBackupJob);
846
898
 
@@ -870,8 +922,15 @@ describe("Backup", function () {
870
922
  "profile",
871
923
  "keymap-desktop.json"
872
924
  );
925
+ const backupPlugin = path.join(
926
+ testPath.activeBackupJob,
927
+ "profile",
928
+ "plugins",
929
+ "test-plugin.jpl"
930
+ );
873
931
 
874
932
  backup.activeBackupPath = testPath.activeBackupJob;
933
+ backup.backupPlugins = true;
875
934
  await backup.backupProfileData();
876
935
 
877
936
  expect(fs.existsSync(backupTemplate)).toBe(true);
@@ -879,6 +938,7 @@ describe("Backup", function () {
879
938
  expect(fs.existsSync(backupUserstyle)).toBe(true);
880
939
  expect(fs.existsSync(backupUserchrome)).toBe(true);
881
940
  expect(fs.existsSync(backupKeymap)).toBe(true);
941
+ expect(fs.existsSync(backupPlugin)).toBe(true);
882
942
 
883
943
  expect(backup.log.error).toHaveBeenCalledTimes(0);
884
944
  expect(backup.log.warn).toHaveBeenCalledTimes(0);
@@ -71,4 +71,79 @@ describe("Test helper", function () {
71
71
  );
72
72
  }
73
73
  });
74
+ it(`Compare versions`, async () => {
75
+ const testCases = [
76
+ {
77
+ version1: "2.9.12",
78
+ version2: "2.9.12",
79
+ expected: 0,
80
+ },
81
+ {
82
+ version1: "2.9.12",
83
+ version2: "2.9.13",
84
+ expected: -1,
85
+ },
86
+ {
87
+ version1: "2.9.13",
88
+ version2: "2.9.12",
89
+ expected: 1,
90
+ },
91
+ {
92
+ version1: "2.10.6",
93
+ version2: "2.9.12",
94
+ expected: 1,
95
+ },
96
+ {
97
+ version1: "3.10.6",
98
+ version2: "2.11.8",
99
+ expected: 1,
100
+ },
101
+ {
102
+ version1: "2.10.6",
103
+ version2: "3.11.8",
104
+ expected: -1,
105
+ },
106
+ {
107
+ version1: "2",
108
+ version2: "2.1",
109
+ expected: -1,
110
+ },
111
+ {
112
+ version1: "2.1",
113
+ version2: "2",
114
+ expected: 1,
115
+ },
116
+ {
117
+ version1: "3",
118
+ version2: "2",
119
+ expected: 1,
120
+ },
121
+ {
122
+ version1: "2",
123
+ version2: "2",
124
+ expected: 0,
125
+ },
126
+ {
127
+ version1: "3.11.8",
128
+ version2: "3.11.8-a",
129
+ expected: 0,
130
+ },
131
+ {
132
+ version1: "2",
133
+ version2: "",
134
+ expected: -2,
135
+ },
136
+ {
137
+ version1: "3.a.8",
138
+ version2: "3.11.8",
139
+ expected: -1,
140
+ },
141
+ ];
142
+
143
+ for (const testCase of testCases) {
144
+ expect(
145
+ await helper.versionCompare(testCase.version1, testCase.version2)
146
+ ).toBe(testCase.expected);
147
+ }
148
+ });
74
149
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joplin-plugin-backup",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "scripts": {
5
5
  "dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
6
6
  "prepare": "npm run dist && husky install",
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 1,
3
3
  "id": "io.github.jackgruber.backup",
4
4
  "app_min_version": "2.1.3",
5
- "version": "1.1.0",
5
+ "version": "1.2.0",
6
6
  "name": "Simple Backup",
7
7
  "description": "Plugin to create manual and automatic backups.",
8
8
  "author": "JackGruber",
@@ -16,6 +16,6 @@
16
16
  "7zip",
17
17
  "encrypted"
18
18
  ],
19
- "_publish_hash": "sha256:8d8c6a3bb92fafc587269aea58b623b05242d42c0766a05bbe25c3ba2bbdf8ee",
20
- "_publish_commit": "master:00ed52133c659e0f3ac1a55f70b776c42fca0a6d"
19
+ "_publish_hash": "sha256:5b9605100911c96c157853884f1fb8fc0e4374697f493dcbeb45fd09068e469d",
20
+ "_publish_commit": "master:1a5f98eef052081f501e9bcda2fd1f69f2dbeb04"
21
21
  }