mirror of
https://github.com/laurent22/joplin.git
synced 2026-06-18 20:16:34 +02:00
This commit is contained in:
@@ -1269,6 +1269,9 @@ packages/generator-joplin/generators/app/templates/api/index.js
|
||||
packages/generator-joplin/generators/app/templates/api/noteListType.js
|
||||
packages/generator-joplin/generators/app/templates/api/types.js
|
||||
packages/generator-joplin/generators/app/templates/api_index.js
|
||||
packages/generator-joplin/generators/app/templates/script/publish/steps/verifyBuild.js
|
||||
packages/generator-joplin/generators/app/templates/script/publish/steps/verifyGitState.js
|
||||
packages/generator-joplin/generators/app/templates/script/publish/utils/logger.js
|
||||
packages/generator-joplin/generators/app/templates/src/index.js
|
||||
packages/generator-joplin/tools/updateCategories.js
|
||||
packages/htmlpack/index.test.js
|
||||
|
||||
@@ -1295,6 +1295,9 @@ packages/generator-joplin/generators/app/templates/api/index.js
|
||||
packages/generator-joplin/generators/app/templates/api/noteListType.js
|
||||
packages/generator-joplin/generators/app/templates/api/types.js
|
||||
packages/generator-joplin/generators/app/templates/api_index.js
|
||||
packages/generator-joplin/generators/app/templates/script/publish/steps/verifyBuild.js
|
||||
packages/generator-joplin/generators/app/templates/script/publish/steps/verifyGitState.js
|
||||
packages/generator-joplin/generators/app/templates/script/publish/utils/logger.js
|
||||
packages/generator-joplin/generators/app/templates/src/index.js
|
||||
packages/generator-joplin/tools/updateCategories.js
|
||||
packages/htmlpack/index.test.js
|
||||
|
||||
@@ -176,6 +176,11 @@ module.exports = class extends Generator {
|
||||
this.templatePath('api'),
|
||||
this.destinationPath('api'),
|
||||
);
|
||||
|
||||
this.fs.copy(
|
||||
this.templatePath('script'),
|
||||
this.destinationPath('script'),
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"glob": "^8.0.3",
|
||||
"semver": "^7.5.4",
|
||||
"@types/semver": "^7.5.4",
|
||||
"tar": "^6.1.11",
|
||||
"ts-loader": "^9.3.1",
|
||||
"typescript": "^4.8.2",
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
import { readFile } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import { valid } from 'semver';
|
||||
import logger from '../utils/logger';
|
||||
|
||||
const distCommand = 'npm run dist';
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
interface Manifest {
|
||||
version?: string;
|
||||
repository_url?: string;
|
||||
}
|
||||
|
||||
interface PackageJson {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
const verifyBuild = async () => {
|
||||
const metadata = await validateMetadata();
|
||||
await build();
|
||||
return metadata;
|
||||
};
|
||||
|
||||
const validateMetadata = async () => {
|
||||
logger.info('Validating metadata...');
|
||||
|
||||
// process.cwd() is the plugin root dir when run via `npm run publish`
|
||||
const manifestPath = join(process.cwd(), 'src/manifest.json');
|
||||
const packageJsonPath = join(process.cwd(), 'package.json');
|
||||
|
||||
let manifest: Manifest;
|
||||
let packageJson: PackageJson;
|
||||
try {
|
||||
manifest = JSON.parse(await readFile(manifestPath, 'utf8'));
|
||||
packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
error.message = `manifest.json or package.json contains invalid JSON: ${error.message}`;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
const { version } = manifest;
|
||||
const { name } = packageJson;
|
||||
const repositoryUrl = manifest.repository_url;
|
||||
|
||||
if (!name || !name.startsWith('joplin-plugin-')) {
|
||||
throw new Error('Plugin name must start with \'joplin-plugin-\' in package.json');
|
||||
}
|
||||
|
||||
if (!version || !valid(version)) {
|
||||
throw new Error(`Invalid plugin version: '${version}'. Must follow semver format.`);
|
||||
}
|
||||
|
||||
const cleanUrl = typeof repositoryUrl === 'string'
|
||||
? repositoryUrl.trim().replace(/\.git$/, '').replace(/\/$/, '')
|
||||
: '';
|
||||
const githubPattern = /^https:\/\/github\.com\/[^/]+\/[^/]+$/;
|
||||
|
||||
if (!cleanUrl || !githubPattern.test(cleanUrl)) {
|
||||
throw new Error('Repository URL is missing or malformed in manifest.json. Valid format: https://github.com/username/repo');
|
||||
}
|
||||
|
||||
logger.success(`Metadata validated: ${name}@${version}`);
|
||||
return { name, version, repositoryUrl: cleanUrl };
|
||||
};
|
||||
|
||||
const build = async () => {
|
||||
try {
|
||||
logger.info(`Running '${distCommand}'...`);
|
||||
await execAsync(distCommand, { cwd: process.cwd() });
|
||||
logger.success('Build verified!');
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
error.message = `Build failed. Fix the errors above before publishing: ${error.message}`;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export default verifyBuild;
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import logger from '../utils/logger';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
// Verifies if the user has pushed the local code which he is going to publish on github or not
|
||||
const verifyGitState = async () => {
|
||||
|
||||
const runGit = async (command: string, errorMessage: string) => {
|
||||
try {
|
||||
const { stdout } = await execAsync(command, { encoding: 'utf8', cwd: process.cwd() });
|
||||
return stdout.trim();
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
error.message = `${errorMessage}: ${error.message}`;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Checks if the current folder is a git repository or not
|
||||
await runGit('git rev-parse --is-inside-work-tree', 'The current directory is not a git repository or git is not installed.');
|
||||
|
||||
// Checks if there is any uncommitted changes
|
||||
const status = await runGit('git status --porcelain', 'Failed to check git status. Ensure git is installed and configured.');
|
||||
if (status !== '') {
|
||||
throw new Error('You have uncommitted changes. Please commit or stash them before publishing.');
|
||||
}
|
||||
logger.success('Working tree is clean.');
|
||||
|
||||
// Gets the current latest local commit hash
|
||||
const commitHash = await runGit('git rev-parse HEAD', 'Could not get commit hash. Ensure you are in a valid Git repository with at least one commit.');
|
||||
if (commitHash.length !== 40) {
|
||||
throw new Error('Failed to extract a valid commit hash. Ensure that git is properly initialized and you have made at least one local commit (git commit) before publishing.');
|
||||
}
|
||||
logger.success(`Commit hash extracted: ${commitHash}`);
|
||||
|
||||
// check if the local project is linked to github
|
||||
await runGit('git remote get-url origin', 'No remote named \'origin\' found. Make sure your plugin repository is hosted on GitHub.');
|
||||
|
||||
const currentBranch = await runGit('git rev-parse --abbrev-ref HEAD', 'Failed to retrieve current branch name. Ensure git is configured correctly.');
|
||||
if (currentBranch === 'HEAD') {
|
||||
throw new Error('You are in a detached HEAD state. Checkout a branch (e.g. git checkout main) and push before publishing.');
|
||||
}
|
||||
|
||||
const remoteHeadLine = await runGit(`git ls-remote origin ${currentBranch}`, 'Could not retrieve remote HEAD. Make sure you have pushed your changes and have an internet connection.');
|
||||
if (!remoteHeadLine) {
|
||||
throw new Error('Remote HEAD is empty. Make sure you have pushed your changes.');
|
||||
}
|
||||
|
||||
const parts = remoteHeadLine.split('\n')[0].split(/\s+/);
|
||||
if (parts.length < 2) {
|
||||
throw new Error(`Unexpected git ls-remote output: "${remoteHeadLine}". Make sure your git remote and branch are configured correctly.`);
|
||||
}
|
||||
|
||||
const remoteHash = parts[0];
|
||||
if (remoteHash.length !== 40) {
|
||||
throw new Error('Failed to extract a valid remote commit hash.');
|
||||
}
|
||||
|
||||
if (remoteHash !== commitHash) {
|
||||
throw new Error('Your local commit has not been pushed to GitHub. Run git push then try publishing again.');
|
||||
}
|
||||
logger.success('Local commit is synced with remote.');
|
||||
|
||||
return commitHash;
|
||||
};
|
||||
|
||||
export default verifyGitState;
|
||||
@@ -0,0 +1,11 @@
|
||||
/* eslint-disable no-console */
|
||||
import { green, yellow, red } from 'chalk';
|
||||
|
||||
const logger = {
|
||||
info: (msg: string) => console.log(msg),
|
||||
success: (msg: string) => console.log(green(msg)),
|
||||
warn: (msg: string) => console.log(yellow(msg)),
|
||||
error: (msg: string) => console.log(red(msg)),
|
||||
};
|
||||
|
||||
export default logger;
|
||||
Reference in New Issue
Block a user