Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Register unpublish cli command to the console #4995

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
53 changes: 53 additions & 0 deletions lib/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,59 @@ class Post {
});
}

unpublish(data, replace, callback) {
if (!callback && typeof replace === 'function') {
callback = replace;
replace = false;
}

if (data.layout === 'post') data.layout = 'draft';

const ctx = this.context;
const { config } = ctx;
const postDir = join(ctx.source_dir, '_posts');
const slug = slugize(data.slug.toString(), { transform: config.filename_case });
data.slug = slug;
const regex = new RegExp(`^${escapeRegExp(slug)}(?:[^\\/\\\\]+)`);
let src = '';
const result = {};

data.layout = (data.layout || config.default_layout).toLowerCase();

// Find the original post
return listDir(postDir).then(list => {
const item = list.find(item => regex.test(item));
if (!item) throw new Error(`Post "${slug}" does not exist.`);

// Read the post content
src = join(postDir, item);
return readFile(src);
}).then(content => {
// Create draft
Object.assign(data, yfmParse(content));
data.content = data._content;
data._content = undefined;

return this.create(data, replace);
}).then(post => {
result.path = post.path;
result.content = post.content;
return unlink(src);
}).then(() => { // Remove the original post file
if (!config.post_asset_folder) return;

// Copy assets
const assetSrc = removeExtname(src);
const assetDest = removeExtname(result.path);

return exists(assetSrc).then(exist => {
if (!exist) return;

return copyDir(assetSrc, assetDest).then(() => rmdir(assetSrc));
});
}).thenReturn(result).asCallback(callback);
}

publish(data, replace, callback) {
if (!callback && typeof replace === 'function') {
callback = replace;
Expand Down
8 changes: 8 additions & 0 deletions lib/plugins/console/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ module.exports = function(ctx) {
]
}, require('./publish'));

console.register('unpublish', 'Moves a published post from _posts to _drafts folder.', {
usage: '[layout] <filename>',
arguments: [
{name: 'layout', desc: 'Post layout. Use post, page, draft or whatever you want.'},
{name: 'filename', desc: 'Post filename. "hello-world" for example.'}
]
}, require('./publish'));
renbaoshuo marked this conversation as resolved.
Show resolved Hide resolved

console.register('render', 'Render files with renderer plugins.', {
init: true,
desc: 'Render files with renderer plugins (e.g. Markdown) and save them at the specified path.',
Expand Down
20 changes: 20 additions & 0 deletions lib/plugins/console/unpublish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

const tildify = require('tildify');
const { magenta } = require('picocolors');

function unPublishConsole(args) {
// Display help message if user didn't input any arguments
if (!args._.length) {
return this.call('help', {_: ['unpublish']});
}

return this.post.unpublish({
slug: args._.pop(),
layout: args._.length ? args._[0] : this.config.default_layout
}, args.r || args.replace).then(post => {
this.log.info('Unpublished: %s', magenta(tildify(post.path)));
});
}

module.exports = unPublishConsole;
1 change: 1 addition & 0 deletions test/scripts/console/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Console', () => {
require('./migrate');
require('./new');
require('./publish');
require('./unpublish');
require('./render');
require('./list');
require('./list_post');
Expand Down
139 changes: 139 additions & 0 deletions test/scripts/console/unpublish.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
'use strict';

const { exists, mkdirs, readFile, rmdir, unlink } = require('hexo-fs');
const moment = require('moment');
const { join } = require('path');
const Promise = require('bluebird');
const { useFakeTimers, spy } = require('sinon');

describe('unpublish', () => {
const Hexo = require('../../../lib/hexo');
const hexo = new Hexo(join(__dirname, 'unpublish_test'), {silent: true});
const unpublish = require('../../../lib/plugins/console/unpublish').bind(hexo);
const post = hexo.post;
const now = Date.now();
let clock;

before(async () => {
clock = useFakeTimers(now);

await mkdirs(hexo.base_dir);
await hexo.init();
await hexo.scaffold.set('post', [
'---',
'title: {{ title }}',
'date: {{ date }}',
'tags:',
'---'
].join('\n'));
await hexo.scaffold.set('draft', [
'---',
'title: {{ title }}',
'tags:',
'---'
].join('\n'));
});

after(() => {
clock.restore();
return rmdir(hexo.base_dir);
});

beforeEach(() => post.create({
title: 'Hello World',
layout: 'post',
date: moment(now).format('YYYY-MM-DD HH:mm:ss')
}));

it('slug', async () => {
const postPath = join(hexo.source_dir, '_posts', 'Hello-World.md');
const path = join(hexo.source_dir, '_drafts', 'Hello-World.md');

const content = [
'---',
'title: Hello World',
'tags:',
'---'
].join('\n') + '\n';

await unpublish({
_: ['Hello-World']
});

const exist = await exists(postPath);
const data = await readFile(path);

exist.should.be.false;
data.should.eql(content);

await unlink(path);
});

it('no args', async () => {
const hexo = new Hexo(join(__dirname, 'unpublish_test'), {silent: true});
hexo.call = spy();
const unpublish = require('../../../lib/plugins/console/unpublish').bind(hexo);

await unpublish({_: []});

hexo.call.calledOnce.should.be.true;
hexo.call.args[0][0].should.eql('help');
hexo.call.args[0][1]._[0].should.eql('unpublish');
});

it('layout', async () => {
const path = join(hexo.source_dir, '_posts', 'Hello-World.md');
const date = moment(now);

const content = [
'---',
'title: Hello World',
'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
'tags:',
'---'
].join('\n') + '\n';

await unpublish({
_: ['photo', 'Hello-World']
});
const data = await readFile(path);
data.should.eql(content);

await unlink(path);
});

it('rename if target existed', async () => {
const path = join(hexo.source_dir, '_posts', 'Hello-World.md');

await post.create({
title: 'Hello World'
});
await unpublish({
_: ['Hello-World']
});

const exist = await exists(path);
exist.should.be.true;

await Promise.all([
unlink(path),
unlink(join(hexo.source_dir, '_posts', 'Hello-World.md'))
]);
});

it('replace existing target', async () => {
const path = join(hexo.source_dir, '_posts', 'Hello-World.md');

await post.create({
title: 'Hello World'
});
await unpublish({
_: ['Hello-World'],
replace: true
});
const exist = await exists(join(hexo.source_dir, '_drafts', 'Hello-World-1.md'));
exist.should.be.false;

await unlink(path);
});
});