Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/plugin-scaffold.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ linchpin plugin scaffold acme --path ~/GitHub/acme --dry-run

| Flag | Default | Meaning |
| --- | --- | --- |
| `--name` | title-cased slug | Plugin Name and README title |
| `--description` | generated one-liner | Plugin header and README one-liner |
| `--php` | `8.3` | Requires PHP |
| `--name` | title-cased slug | Plugin Name, README title, and the `readme.txt` name |
| `--description` | generated one-liner | Plugin header, README one-liner, and the `readme.txt` short description |
| `--php` | `8.3` | Requires PHP, in the header and in `readme.txt` when it declares one |
| `--channel` | `private` | `private`, `wporg`, or `self-hosted` |
| `--with-blocks` | off | Nested `blocks/` workspace and an example block |
| `--path` | `./<slug>` | Destination |
Expand Down
14 changes: 14 additions & 0 deletions src/core/plugin-scaffold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,20 @@ function applyDisplayIdentity(
readme = readme.replace(/^(# .+\n\n).+(\n)/, `$1${description}$2`);
writeFileSync(readmePath, readme);

// Plugin Check fails a readme.txt whose Requires PHP differs from the header,
// and warns on a mismatched plugin name. The short description follows the
// header block, and is absent when the next line is already a section.
const readmeTxtPath = join(dest, 'readme.txt');
if (existsSync(readmeTxtPath)) {
let readmeTxt = readFileSync(readmeTxtPath, 'utf8');
readmeTxt = readmeTxt.replace(/^=== .+ ===$/m, `=== ${name} ===`);
readmeTxt = readmeTxt.replace(/^(=== .+ ===\n(?:.+\n)*\n)(?!==).+(\n)/, `$1${description}$2`);
if (php !== '8.3') {
readmeTxt = readmeTxt.replace(/(Requires PHP:\s*)8\.3/, (_match, label: string) => `${label}${php}`);
}
writeFileSync(readmeTxtPath, readmeTxt);
}

const composerPath = join(dest, 'composer.json');
const composer = JSON.parse(readFileSync(composerPath, 'utf8')) as {
description?: string;
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/plugin-scaffold/overlays/wporg/readme.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
=== Plugin Scaffold ===
Requires PHP: 8.3
Stable tag: 0.1.0

The Linchpin WordPress plugin standard.

== Description ==

The Linchpin WordPress plugin standard.
9 changes: 9 additions & 0 deletions test/fixtures/plugin-scaffold/readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
=== Plugin Scaffold ===
Contributors: linchpin_agency
Tested up to: 7.1

The Linchpin WordPress plugin standard.

== Description ==

Replace this description.
22 changes: 19 additions & 3 deletions test/plugin-scaffold.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ test('renders acme from the fixture', () => {
);
assert.doesNotMatch(readme.replaceAll(BANNER, ''), /plugin-scaffold/);

const readmeTxt = fs.readFileSync(path.join(dest, 'readme.txt'), 'utf8');
assert.match(readmeTxt, /^=== Acme ===$/m);
assert.match(readmeTxt, /^A test plugin\.$/m);
assert.match(readmeTxt, /^== Description ==$/m);
assert.doesNotMatch(readmeTxt, /Stable tag:/);

const leftovers = lib.leftoverIdentity(dest);
assert.deepEqual(leftovers, []);
});
Expand All @@ -139,12 +145,19 @@ test('with-blocks and wporg overlays', () => {
FIXTURE,
'--with-blocks',
'--channel=wporg',
'--php',
'8.4',
]);

assert.equal(result.code, 0, result.stderr);
assert.equal(fs.existsSync(path.join(dest, 'includes/Controller/Blocks.php')), true);
assert.equal(fs.existsSync(path.join(dest, 'blocks/src/example/block.json')), true);
assert.equal(fs.existsSync(path.join(dest, 'readme.txt')), true);

const readmeTxt = fs.readFileSync(path.join(dest, 'readme.txt'), 'utf8');
assert.match(readmeTxt, /^=== Acme ===$/m);
assert.match(readmeTxt, /^Stable tag: 0\.1\.0$/m);
assert.match(readmeTxt, /^Requires PHP: 8\.4$/m);
assert.match(readmeTxt, /^A WordPress plugin generated from the Linchpin plugin standard\.$/m);

const pkg = JSON.parse(fs.readFileSync(path.join(dest, 'package.json'), 'utf8'));
assert.equal(pkg.scripts['build:all'], 'npm run build && npm run build --prefix blocks');
Expand All @@ -153,7 +166,7 @@ test('with-blocks and wporg overlays', () => {
assert.doesNotMatch(main, /Update URI:/);
});

test('self-hosted adds Update URI and does not add readme.txt', () => {
test('self-hosted adds Update URI and keeps the private readme.txt', () => {
const dest = path.join(tempDir(), 'acme');
const result = runCli(process.cwd(), [
'plugin',
Expand All @@ -169,7 +182,10 @@ test('self-hosted adds Update URI and does not add readme.txt', () => {
assert.equal(result.code, 0, result.stderr);
const main = fs.readFileSync(path.join(dest, 'acme.php'), 'utf8');
assert.match(main, /Update URI:\s+https:\/\/api\.linchpin\.com\/updates\/acme/);
assert.equal(fs.existsSync(path.join(dest, 'readme.txt')), false);

const readmeTxt = fs.readFileSync(path.join(dest, 'readme.txt'), 'utf8');
assert.match(readmeTxt, /^=== Acme ===$/m);
assert.doesNotMatch(readmeTxt, /Stable tag:/);
});

test('refuses a non-empty destination without --force', () => {
Expand Down
Loading