Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
JackGruber committed May 14, 2023
2 parents e4e8e6c + 69cc2fb commit 68888ee
Show file tree
Hide file tree
Showing 23 changed files with 769 additions and 184 deletions.
16 changes: 16 additions & 0 deletions .github/workflows/buildAndTest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Build and test
on: [push, pull_request]
jobs:
buildAndTest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: "16"
- name: Install dependencies
run: npm install
- name: Build
run: npm run dist
- name: Run test
run: npm test
2 changes: 0 additions & 2 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm test
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## not released

## v1.3.0 (2023-05-14)

- Add: German translation

## v1.2.2 (2023-01-06)

- Fix: `moveLogFile: ENOTDIR: not a directory` for certain backup settings
- Add: DirectoryPath selector for backup path and tmp. export path selection on Joplin >= v2.10.4

## v1.2.1 (2022-12-10)

- Fix: #47 Suppress repeating error message during automatic execution if the backup path is not accessible
Expand Down
136 changes: 79 additions & 57 deletions __test__/backup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,19 +528,23 @@ describe("Backup", function () {
backupRetention: 1,
password: null,
singleJex: true,
result: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
result: path.join(testPath.backupBasePath),
testFile: "testFile.txt",
checkFile: path.join(testPath.backupBasePath, "JoplinBackup.7z"),
checkFile: path.join(testPath.backupBasePath, "testFile.txt.7z"),
saveBackupInfoCalled: 0,
},
{
zipArchive: "yes",
backupRetention: 2,
password: null,
singleJex: true,
result: path.join(testPath.backupBasePath, "202101021630.7z"),
result: path.join(testPath.backupBasePath, "202101021630"),
testFile: "testFile.txt",
checkFile: path.join(testPath.backupBasePath, "202101021630.7z"),
checkFile: path.join(
testPath.backupBasePath,
"202101021630",
"testFile.txt.7z"
),
saveBackupInfoCalled: 1,
},
{
Expand Down Expand Up @@ -801,86 +805,104 @@ describe("Backup", function () {
expect(backup.log.transports.file.level).toBe("error");
});

it(`move logfile`, async () => {
describe("move logfile", function () {
const testCases = [
{
description: "backupBasePath",
zipArchive: "no",
password: null,
logDst: testPath.backupBasePath,
testLogFile: path.join(testPath.backupBasePath, "backup.log"),
},
{
description: "backupBasePath, password",
zipArchive: "no",
password: null,
logDst: path.join(testPath.backupBasePath, "testDir"),
testLogFile: path.join(
testPath.backupBasePath,
"testDir",
"backup.log"
),
password: "secret",
logDst: testPath.backupBasePath,
},
{
description: "backupBasePath, zip, password",
zipArchive: "yes",
password: null,
logDst: path.join(testPath.backupBasePath, "testDir"),
testLogFile: path.join(
testPath.backupBasePath,
"testDir",
"backup.log"
),
password: "secret",
logDst: testPath.backupBasePath,
},
{
description: "backupBasePath, zip one",
zipArchive: "yesone",
password: null,
logDst: path.join(testPath.backupBasePath, "Backup.7z"),
testLogFile: "backup.log",
logDst: path.join(testPath.backupBasePath, "retention.7z"),
},
{
description: "backupBasePath, zip one, password",
zipArchive: "yesone",
password: "secret",
logDst: path.join(testPath.backupBasePath, "Backup.7z"),
testLogFile: "backup.log",
logDst: path.join(testPath.backupBasePath, "retention.7z"),
},
{
description: "sub in backupBasePath",
zipArchive: "no",
password: null,
logDst: path.join(testPath.backupBasePath, "retentionfolder"),
},
{
description: "sub in backupBasePath, password",
zipArchive: "no",
password: "secret",
logDst: testPath.backupBasePath,
testLogFile: "backup.log",
logDst: path.join(testPath.backupBasePath, "retentionfolder"),
},
{
description: "sub in backupBasePath, zip",
zipArchive: "yes",
password: null,
logDst: path.join(testPath.backupBasePath, "retentionfolder"),
},
{
description: "sub in backupBasePath, password, zip",
zipArchive: "yes",
password: "secret",
logDst: path.join(testPath.backupBasePath, "retentionfolder"),
},
];

backup.logFile = path.join(testPath.base, "test.log");
for (const testCase of testCases) {
await createTestStructure();
if (testCase.zipArchive !== "yesone") {
fs.emptyDirSync(testCase.logDst);
}
if (testCase.zipArchive === "yesone") {
const dummyFile = path.join(testPath.base, "dummy");
fs.writeFileSync(dummyFile, "dummy");
await sevenZip.add(testCase.logDst, dummyFile, testCase.password);
expect(fs.existsSync(dummyFile)).toBe(true);
expect(fs.existsSync(testCase.logDst)).toBe(true);
}

fs.writeFileSync(backup.logFile, "log");

backup.zipArchive = testCase.zipArchive;
backup.password = testCase.password;

expect(fs.existsSync(backup.logFile)).toBe(true);
expect(await backup.moveLogFile(testCase.logDst)).toBe(true);
expect(fs.existsSync(backup.logFile)).toBe(false);

if (testCase.password !== null || testCase.zipArchive === "yesone") {
const fileList = await sevenZip.list(
testCase.logDst,
testCase.password
);
expect(fileList.map((f) => f.file)).toContain(testCase.testLogFile);
} else {
expect(fs.existsSync(testCase.testLogFile)).toBe(true);
}
it(`${testCase.description}`, async () => {
backup.logFile = path.join(testPath.base, "test.log");
backup.zipArchive = testCase.zipArchive;
backup.password = testCase.password;

await createTestStructure();

if (testCase.zipArchive === "yesone") {
const dummyFile = path.join(testPath.base, "dummy");
fs.writeFileSync(dummyFile, "dummy");
expect(fs.existsSync(dummyFile)).toBe(true);
await sevenZip.add(testCase.logDst, dummyFile, testCase.password);
expect(fs.existsSync(testCase.logDst)).toBe(true);
} else {
fs.emptyDirSync(testCase.logDst);
}

fs.writeFileSync(backup.logFile, "log");
expect(fs.existsSync(backup.logFile)).toBe(true);

expect(await backup.moveLogFile(testCase.logDst)).toBe(true);
expect(fs.existsSync(backup.logFile)).toBe(false);

let checkBackupLogFile = path.join(testCase.logDst, "backup.log");
if (testCase.zipArchive === "yesone") {
checkBackupLogFile = testCase.logDst;
} else if (testCase.password !== null) {
checkBackupLogFile = path.join(testCase.logDst, "backuplog.7z");
}
expect(fs.existsSync(checkBackupLogFile)).toBe(true);

if (testCase.password !== null || testCase.zipArchive === "yesone") {
const fileList = await sevenZip.list(
testCase.logDst,
testCase.password
);
expect(fileList.map((f) => f.file)).toContain("backup.log");
}
});
}
});
});
Expand Down
17 changes: 10 additions & 7 deletions api/Joplin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@ import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
import JoplinContentScripts from './JoplinContentScripts';
import JoplinClipboard from './JoplinClipboard';
import JoplinWindow from './JoplinWindow';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
* **This is a beta API**
* The API is now relatively stable and in general maintaining backward compatibility is a top priority, so you shouldn't except much breakages.
*
* Please note that the plugin API is relatively new and should be considered Beta state. Besides possible bugs, what it means is that there might be necessary breaking changes from one version to the next. Whenever such change is needed, best effort will be done to:
* If a breaking change ever becomes needed, best effort will be done to:
*
* - Maintain backward compatibility;
* - When possible, deprecate features instead of removing them;
* - Deprecate features instead of removing them, so as to give you time to fix the issue;
* - Document breaking changes in the changelog;
*
* So if you are developing a plugin, please keep an eye on the changelog as everything will be in there with information about how to update your code. There won't be any major API rewrite or architecture changes, but possibly small tweaks like function signature change, type change, etc.
*
* Eventually, the plugin API will be versioned to make this process smoother.
* So if you are developing a plugin, please keep an eye on the changelog as everything will be in there with information about how to update your code.
*/
export default class Joplin {
private data_;
Expand All @@ -33,8 +32,12 @@ export default class Joplin {
private interop_;
private settings_;
private contentScripts_;
private clipboard_;
private window_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get clipboard(): JoplinClipboard;
get window(): JoplinWindow;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
get contentScripts(): JoplinContentScripts;
Expand Down
23 changes: 23 additions & 0 deletions api/JoplinClipboard.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export default class JoplinClipboard {
private electronClipboard_;
private electronNativeImage_;
constructor(electronClipboard: any, electronNativeImage: any);
readText(): Promise<string>;
writeText(text: string): Promise<void>;
readHtml(): Promise<string>;
writeHtml(html: string): Promise<void>;
/**
* Returns the image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*/
readImage(): Promise<string>;
/**
* Takes an image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*/
writeImage(dataUrl: string): Promise<void>;
/**
* Returns the list available formats (mime types).
*
* For example [ 'text/plain', 'text/html' ]
*/
availableFormats(): Promise<string[]>;
}
38 changes: 33 additions & 5 deletions api/JoplinCommands.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,41 @@ import { Command } from './types';
*
* * [Main screen commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/MainScreen/commands)
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/commands)
* * [Editor commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.ts)
* * [Editor commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts)
*
* To view what arguments are supported, you can open any of these files
* and look at the `execute()` command.
*
* ## Executing editor commands
*
* There might be a situation where you want to invoke editor commands
* without using a {@link JoplinContentScripts | contentScript}. For this
* reason Joplin provides the built in `editor.execCommand` command.
*
* `editor.execCommand` should work with any core command in both the
* [CodeMirror](https://codemirror.net/doc/manual.html#execCommand) and
* [TinyMCE](https://www.tiny.cloud/docs/api/tinymce/tinymce.editorcommands/#execcommand) editors,
* as well as most functions calls directly on a CodeMirror editor object (extensions).
*
* * [CodeMirror commands](https://codemirror.net/doc/manual.html#commands)
* * [TinyMCE core editor commands](https://www.tiny.cloud/docs/advanced/editor-command-identifiers/#coreeditorcommands)
*
* `editor.execCommand` supports adding arguments for the commands.
*
* ```typescript
* await joplin.commands.execute('editor.execCommand', {
* name: 'madeUpCommand', // CodeMirror and TinyMCE
* args: [], // CodeMirror and TinyMCE
* ui: false, // TinyMCE only
* value: '', // TinyMCE only
* });
* ```
*
* [View the example using the CodeMirror editor](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/codemirror_content_script/src/index.ts)
*
*/
export default class JoplinCommands {
/**
/**
* <span class="platform-desktop">desktop</span> Executes the given
* command.
*
Expand All @@ -40,8 +68,8 @@ export default class JoplinCommands {
* await joplin.commands.execute('newFolder', "SOME_FOLDER_ID");
* ```
*/
execute(commandName: string, ...args: any[]): Promise<any | void>;
/**
execute(commandName: string, ...args: any[]): Promise<any | void>;
/**
* <span class="platform-desktop">desktop</span> Registers a new command.
*
* ```typescript
Expand All @@ -57,5 +85,5 @@ export default class JoplinCommands {
* });
* ```
*/
register(command: Command): Promise<void>;
register(command: Command): Promise<void>;
}
3 changes: 3 additions & 0 deletions api/JoplinData.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ModelType } from '../../../BaseModel';
import { Path } from './types';
/**
* This module provides access to the Joplin data API: https://joplinapp.org/api/references/rest_api/
Expand Down Expand Up @@ -44,4 +45,6 @@ export default class JoplinData {
post(path: Path, query?: any, body?: any, files?: any[]): Promise<any>;
put(path: Path, query?: any, body?: any, files?: any[]): Promise<any>;
delete(path: Path, query?: any): Promise<any>;
itemType(itemId: string): Promise<ModelType>;
resourcePath(resourceId: string): Promise<string>;
}
4 changes: 2 additions & 2 deletions api/JoplinFilters.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
* so for now disable filters.
*/
export default class JoplinFilters {
on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>;
on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>;
}
4 changes: 2 additions & 2 deletions api/JoplinInterop.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ import { ExportModule, ImportModule } from './types';
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/api/references/rest_api/
*/
export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>;
registerImportModule(module: ImportModule): Promise<void>;
registerExportModule(module: ExportModule): Promise<void>;
registerImportModule(module: ImportModule): Promise<void>;
}
2 changes: 1 addition & 1 deletion api/JoplinSettings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export interface ChangeEvent {
*/
keys: string[];
}
export declare type ChangeHandler = (event: ChangeEvent)=> void;
export declare type ChangeHandler = (event: ChangeEvent) => void;
/**
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
*
Expand Down
Loading

0 comments on commit 68888ee

Please sign in to comment.