mirror of
https://github.com/laurent22/joplin.git
synced 2026-11-12 11:36:08 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cca6d46ad3 | ||
|
|
db12dd7f2b | ||
|
|
b545a8ad42 | ||
|
|
953e3f7cd4 | ||
|
|
16749c0587 |
No files matched your search
@@ -1,12 +1,14 @@
|
||||
name: Publish sub-packages
|
||||
name: Publish npm packages
|
||||
|
||||
# The tag is created and pushed by `yarn publishAll`. Publishing uses npm trusted publishing, so no
|
||||
# token is needed, but each package must have this workflow registered as a trusted publisher on
|
||||
# The sub-packages tag is pushed by `yarn publishAll`, and the cli tag by `yarn releaseCli`. Either way,
|
||||
# any library or CLI app version not yet on npm is published. Publishing uses npm trusted publishing, so
|
||||
# no token is needed, but each package must have this workflow registered as a trusted publisher on
|
||||
# npmjs.com.
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'sub-packages-v*'
|
||||
- 'cli-v*'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -21,7 +23,7 @@ concurrency:
|
||||
jobs:
|
||||
Publish:
|
||||
if: github.repository == 'laurent22/joplin'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
|
||||
@@ -76,3 +76,10 @@ runs:
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.14'
|
||||
|
||||
# Building the default plugins from source takes several minutes on Windows. Must be restored
|
||||
# before "yarn install", which builds them.
|
||||
- uses: actions/cache@v6
|
||||
with:
|
||||
path: packages/default-plugins/build-cache
|
||||
key: default-plugins-${{ runner.os }}-${{ hashFiles('packages/default-plugins/pluginRepositories.json', 'packages/default-plugins/plugin-patches/**', 'packages/default-plugins/buildDefaultPlugins.ts') }}
|
||||
@@ -19,7 +19,8 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laurent22/joplin"
|
||||
"url": "git+https://github.com/laurent22/joplin.git",
|
||||
"directory": "packages/app-cli"
|
||||
},
|
||||
"copyright": {
|
||||
"title": "Joplin CLI",
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
built-plugins/
|
||||
plugin-sources/*
|
||||
plugin-sources/*
|
||||
build-cache/
|
||||
@@ -1,9 +1,10 @@
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { copy, exists, remove, readdir, mkdtemp } from 'fs-extra';
|
||||
import { copy, exists, remove, readdir, mkdtemp, readFile } from 'fs-extra';
|
||||
import { join, resolve, basename } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { createHash } from 'crypto';
|
||||
import { chdir, cwd } from 'process';
|
||||
import { execCommand } from '@joplin/utils';
|
||||
import { glob } from 'glob';
|
||||
@@ -16,8 +17,22 @@ interface Options {
|
||||
outputParentDir: string|null;
|
||||
beforeInstall: (buildDir: string, pluginName: string)=> Promise<void>;
|
||||
beforePatch: ()=> Promise<void>;
|
||||
useBuildCache: boolean;
|
||||
}
|
||||
|
||||
// Increment to invalidate cached builds, for example after changing how plugins are built
|
||||
const buildCacheVersion = 1;
|
||||
const buildCacheDir = process.env.JOPLIN_DEFAULT_PLUGINS_CACHE_DIR || join(__dirname, 'build-cache');
|
||||
|
||||
const getBuildCachePath = async (pluginId: string, repositoryData: RepositoryData) => {
|
||||
const patchFile = getPathToPatchFileFor(pluginId);
|
||||
const patch = await exists(patchFile) ? await readFile(patchFile, 'utf8') : '';
|
||||
const hash = createHash('sha256')
|
||||
.update(JSON.stringify([buildCacheVersion, pluginId, repositoryData.cloneUrl, repositoryData.commit, patch]))
|
||||
.digest('hex');
|
||||
return join(buildCacheDir, `${pluginId}-${hash.substring(0, 16)}.jpl`);
|
||||
};
|
||||
|
||||
const buildDefaultPlugins = async (options: Options) => {
|
||||
const pluginRepositoryData = await readRepositoryJson(join(__dirname, 'pluginRepositories.json'));
|
||||
|
||||
@@ -26,7 +41,23 @@ const buildDefaultPlugins = async (options: Options) => {
|
||||
const outputPath = options.outputParentDir && join(options.outputParentDir, `${pluginId}.jpl`);
|
||||
|
||||
if (repositoryData.type === BuiltInPluginType.Built) {
|
||||
await buildPlugin(pluginId, repositoryData, outputPath, options);
|
||||
const cachePath = options.useBuildCache && outputPath ? await getBuildCachePath(pluginId, repositoryData) : null;
|
||||
if (cachePath && await exists(cachePath)) {
|
||||
logStatus('Using cached build of', pluginId, 'from', cachePath);
|
||||
await copy(cachePath, outputPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
const sourceHasLocalChanges = await buildPlugin(pluginId, repositoryData, outputPath, options);
|
||||
|
||||
if (cachePath) {
|
||||
if (sourceHasLocalChanges) {
|
||||
logStatus('Not caching build of', pluginId, ': its source checkout has local changes');
|
||||
} else {
|
||||
await copy(outputPath, cachePath);
|
||||
logStatus('Saved build of', pluginId, 'to', cachePath);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!outputPath) {
|
||||
console.warn('Skipping NPM plugin,', pluginId, ': missing output path.');
|
||||
@@ -80,6 +111,9 @@ const buildPlugin = async (pluginId: string, repositoryData: RepositoryData, out
|
||||
throw new Error(`Unable to checkout commit ${expectedCommitHash}`);
|
||||
}
|
||||
|
||||
// Local changes are included in the build but not in the build cache key
|
||||
const sourceHasLocalChanges = (await execCommand(['git', 'status', '--porcelain'], { showStdout: false })).trim() !== '';
|
||||
|
||||
logStatus('Copying repository files...');
|
||||
await copy(pluginDir, buildDir, {
|
||||
filter: fileName => {
|
||||
@@ -122,6 +156,8 @@ const buildPlugin = async (pluginId: string, repositoryData: RepositoryData, out
|
||||
} else {
|
||||
console.warn('No output directory specified. Not copying built .jpl files.');
|
||||
}
|
||||
|
||||
return sourceHasLocalChanges;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.log('Build directory', buildDir);
|
||||
|
||||
@@ -5,6 +5,7 @@ const buildAll = (outputDirectory: string) => {
|
||||
outputParentDir: outputDirectory,
|
||||
beforeInstall: async () => { },
|
||||
beforePatch: async () => { },
|
||||
useBuildCache: true,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ const editPatch = async (targetPluginId: string, outputParentDir: string|null) =
|
||||
|
||||
await buildDefaultPlugins({
|
||||
outputParentDir: outputParentDir,
|
||||
useBuildCache: false,
|
||||
beforePatch: async () => {
|
||||
// To make updating just the patch possible, a commit is created just before applying
|
||||
// the patch.
|
||||
|
||||
@@ -64,6 +64,5 @@
|
||||
"license": "MIT",
|
||||
"prettier": {
|
||||
"tabWidth": 4
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,5 @@
|
||||
"devDependencies": {
|
||||
"standard": "17.1.2",
|
||||
"tap": "16.3.10"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,5 @@
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jeremys/uslug/raw/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
]
|
||||
}
|
||||
@@ -45,6 +45,5 @@
|
||||
"@types/jest": "29.5.14",
|
||||
"jest": "29.7.0",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -113,6 +113,5 @@
|
||||
"uuid": "11.1.1",
|
||||
"word-wrap": "1.2.5",
|
||||
"xml2js": "0.4.23"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,5 @@
|
||||
"devDependencies": {
|
||||
"wasm-pack": "0.13.1",
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,5 @@
|
||||
"typescript": "5.9.3",
|
||||
"webpack": "5.97.1",
|
||||
"webpack-cli": "4.10.0"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,5 @@
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,5 @@
|
||||
"markdown-it-sup": "2.0.0",
|
||||
"markdown-it-toc-done-right": "4.2.0",
|
||||
"md5": "2.3.0"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,5 @@
|
||||
"style-to-js": "1.1.21",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,29 @@
|
||||
import { execCommand } from '@joplin/utils';
|
||||
import { rootDir, completeReleaseWithChangelog } from './tool-utils';
|
||||
import { versionPatch } from '@joplin/utils/version';
|
||||
import { versionAll } from './releaseSubPackages';
|
||||
|
||||
const appDir = `${rootDir}/packages/app-cli`;
|
||||
const changelogPath = `${rootDir}/readme/about/changelog/cli.md`;
|
||||
|
||||
// Start with node Tools/release-cli.js --changelog-from cli-v1.0.126
|
||||
// to specify from where the changelog should be created
|
||||
//
|
||||
// Pushing the tag triggers the publish-sub-packages workflow, which publishes the libraries, then the app.
|
||||
async function main() {
|
||||
process.chdir(appDir);
|
||||
process.chdir(rootDir);
|
||||
|
||||
await execCommand('git pull');
|
||||
|
||||
await versionAll();
|
||||
|
||||
process.chdir(appDir);
|
||||
const newVersion = await versionPatch();
|
||||
console.info(`Building ${newVersion}...`);
|
||||
console.info(`New version: ${newVersion}`);
|
||||
const newTag = `cli-${newVersion}`;
|
||||
|
||||
await execCommand('touch app/main.js');
|
||||
await execCommand('yarn build');
|
||||
await execCommand('cp ../../README.md build/');
|
||||
|
||||
process.chdir(`${appDir}/build`);
|
||||
|
||||
await execCommand('npm publish');
|
||||
process.chdir(rootDir);
|
||||
await execCommand('yarn install --mode=update-lockfile');
|
||||
|
||||
await completeReleaseWithChangelog(changelogPath, newVersion, newTag, 'CLI', false);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,25 @@ const publishPackage = async (dir: string, rootLicensePath: string, dryRun: bool
|
||||
}
|
||||
};
|
||||
|
||||
const versionAll = async () => {
|
||||
// The CLI app is a private package because it is published from its build directory
|
||||
const publishCliApp = async (rootDir: string, dryRun: boolean) => {
|
||||
const buildDir = join(rootDir, 'packages', 'app-cli', 'build');
|
||||
await execCommand(['yarn', 'workspace', 'joplin', 'build']);
|
||||
await copy(join(rootDir, 'README.md'), join(buildDir, 'README.md'));
|
||||
await publishPackage(buildDir, join(rootDir, 'LICENSE'), dryRun);
|
||||
};
|
||||
|
||||
const publishIfNeeded = async (manifest: PackageJson, publish: ()=> Promise<void>) => {
|
||||
const id = `${manifest.name}@${manifest.version}`;
|
||||
if (await isPublished(manifest)) {
|
||||
console.info(`Skipping ${id}: already published`);
|
||||
return;
|
||||
}
|
||||
console.info(`Publishing ${id}...`);
|
||||
await publish();
|
||||
};
|
||||
|
||||
export const versionAll = async () => {
|
||||
const packages = await loadPublicPackages(await getRootDir());
|
||||
const bumped = bumpVersions(packages.map(p => p.manifest));
|
||||
for (const [index, { dir, manifest }] of packages.entries()) {
|
||||
@@ -127,19 +145,17 @@ const versionAll = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Packages are published one at a time, dependencies first, so that a failure leaves the registry in a
|
||||
// consistent state. Already published versions are skipped, so the command can be re-run after a failure.
|
||||
// Packages are published one at a time, dependencies first and the CLI app last, so that a failure leaves
|
||||
// the registry in a consistent state. Already published versions are skipped, so the command can be
|
||||
// re-run after a failure, and the CLI app is only published when its version has been bumped.
|
||||
const publishAll = async (dryRun: boolean) => {
|
||||
const rootDir = await getRootDir();
|
||||
for (const { dir, manifest } of sortByDependencies(await loadPublicPackages(rootDir))) {
|
||||
const id = `${manifest.name}@${manifest.version}`;
|
||||
if (await isPublished(manifest)) {
|
||||
console.info(`Skipping ${id}: already published`);
|
||||
continue;
|
||||
}
|
||||
console.info(`Publishing ${id}...`);
|
||||
await publishPackage(dir, join(rootDir, 'LICENSE'), dryRun);
|
||||
await publishIfNeeded(manifest, () => publishPackage(dir, join(rootDir, 'LICENSE'), dryRun));
|
||||
}
|
||||
|
||||
const cliManifest: PackageJson = JSON.parse(await readFile(join(rootDir, 'packages', 'app-cli', 'package.json'), 'utf8'));
|
||||
await publishIfNeeded(cliManifest, () => publishCliApp(rootDir, dryRun));
|
||||
};
|
||||
|
||||
if (require.main === module) {
|
||||
@@ -147,7 +163,7 @@ if (require.main === module) {
|
||||
try {
|
||||
await yargs(hideBin(process.argv))
|
||||
.command('version', 'Bumps the patch version of all public packages', {}, () => versionAll())
|
||||
.command('publish', 'Publishes all public packages whose version is not on the registry yet', yargs => {
|
||||
.command('publish', 'Publishes all public packages and the CLI app whose version is not on the registry yet', yargs => {
|
||||
return yargs.option('dry-run', {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
|
||||
@@ -41,6 +41,5 @@
|
||||
"build-iife": "rollup -c config/rollup.config.iife.js",
|
||||
"build-test": "browserify test/turndown-plugin-gfm-test.js --outfile test/turndown-plugin-gfm-test.browser.js",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,5 @@
|
||||
"build-test": "browserify test/turndown-test.js --outfile test/turndown-test.browser.js",
|
||||
"build": "npm run build-cjs",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
@@ -113,6 +113,5 @@
|
||||
"jest": "29.7.0",
|
||||
"ts-jest": "29.4.12",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"gitHead": "898d2999f93fbedf0ce5f6626feb63e1a732ce0a"
|
||||
}
|
||||
}
|
||||
+8
-22
@@ -30,32 +30,18 @@ It must be built and released manually using XCode.
|
||||
|
||||
## CLI application
|
||||
|
||||
Unlike the mobile or desktop application, the CLI app doesn't bundle its dependencies and is always installed from source. For that reason, all its `@joplin` dependencies must be deployed publicly first. This is done using:
|
||||
Unlike the mobile or desktop application, the CLI app doesn't bundle its dependencies and is always installed from source. For that reason, all its `@joplin` dependencies, such as `@joplin/lib`, `@joplin/tools`, etc., must be published to npm with it.
|
||||
|
||||
yarn publishAll
|
||||
|
||||
This is going to bump the version of all the Joplin libraries, such as `@joplin/lib`, `@joplin/tools`, etc., then commit and push a `sub-packages-v*` tag. The tag triggers the `publish-sub-packages.yml` workflow, which builds and publishes the libraries to npm using [trusted publishing](https://docs.npmjs.com/trusted-publishers). Wait for that workflow to complete before releasing the CLI app.
|
||||
|
||||
Each library must have `laurent22/joplin` and `publish-sub-packages.yml` registered as a trusted publisher on npmjs.com, with "Allow npm publish" enabled. When adding a new library, it must be published once manually before this can be configured.
|
||||
|
||||
Then in `app-cli/package.json`, all `@joplin` dependencies and devdependencies must be set to the last major/minor version. For example:
|
||||
|
||||
```json
|
||||
"dependencies": {
|
||||
"@joplin/lib": "1.8",
|
||||
"@joplin/renderer": "1.8",
|
||||
"...": "..."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@joplin/tools": "1.8",
|
||||
"...": "..."
|
||||
}
|
||||
```
|
||||
|
||||
Finally, to release the actual app, run:
|
||||
To release the app, run:
|
||||
|
||||
yarn releaseCli
|
||||
|
||||
This is going to bump the version of the app and of all the Joplin libraries, then generate the changelog. Once the changelog has been checked, run the printed commands to commit and push a `cli-v*` tag. The tag triggers the `publish-sub-packages.yml` workflow, which builds and publishes the libraries, then the app, to npm using [trusted publishing](https://docs.npmjs.com/trusted-publishers).
|
||||
|
||||
To publish only the libraries, run `yarn publishAll` instead. It bumps their versions, then commits and pushes a `sub-packages-v*` tag, which triggers the same workflow.
|
||||
|
||||
The `joplin` package and each library must have `laurent22/joplin` and `publish-sub-packages.yml` registered as a trusted publisher on npmjs.com, with "Allow npm publish" enabled. When adding a new library, it must be published once manually before this can be configured.
|
||||
|
||||
## Joplin Server
|
||||
|
||||
Run:
|
||||
|
||||
Reference in new issue
Block a user