mirror of
https://github.com/foambubble/foam.git
synced 2026-01-11 15:08:01 -05:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d1ec88717 | ||
|
|
6b1407303e | ||
|
|
528213a0f8 | ||
|
|
ff89948a70 | ||
|
|
734982996a | ||
|
|
265ab19e31 | ||
|
|
80a799dff9 | ||
|
|
3ef95628f5 | ||
|
|
626f64aec0 | ||
|
|
e36c285764 | ||
|
|
20ca92f451 | ||
|
|
4557150378 |
@@ -12,7 +12,9 @@
|
||||
"@oclif/config": "^1",
|
||||
"@oclif/plugin-help": "^3",
|
||||
"chalk": "^4.1.0",
|
||||
"@types/inquirer": "^6.5.0",
|
||||
"foam-core": "^0.2.0",
|
||||
"inquirer": "^7.3.2",
|
||||
"ora": "^4.0.4",
|
||||
"tslib": "^1"
|
||||
},
|
||||
@@ -63,7 +65,6 @@
|
||||
"scripts": {
|
||||
"cli": "./bin/run",
|
||||
"postpack": "rm -f oclif.manifest.json",
|
||||
"posttest": "eslint . --ext .ts --config .eslintrc",
|
||||
"prepack": "rm -rf lib && tsc -b && oclif-dev manifest && oclif-dev readme",
|
||||
"test": "jest",
|
||||
"version": "oclif-dev readme && git add README.md"
|
||||
|
||||
168
packages/foam-cli/src/commands/init.ts
Normal file
168
packages/foam-cli/src/commands/init.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
/*eslint-disable no-unused-vars*/
|
||||
|
||||
import { Command, flags } from '@oclif/command';
|
||||
import * as inquirer from 'inquirer';
|
||||
import * as ora from 'ora';
|
||||
|
||||
// @todo implement this class, currently it does nothing but collect inputs
|
||||
export default class Init extends Command {
|
||||
static description = 'Initialize a new Foam workspace from template';
|
||||
|
||||
// @todo better examples
|
||||
static examples = [`$ foam init`];
|
||||
|
||||
// @todo validate inputs
|
||||
static flags = {
|
||||
help: flags.help({ char: 'h' }),
|
||||
name: flags.string({
|
||||
char: 'n',
|
||||
description: 'workspace name',
|
||||
}),
|
||||
|
||||
scm: flags.string({
|
||||
char: 's',
|
||||
description: 'source control (github, git, local)'
|
||||
}),
|
||||
|
||||
template: flags.string({
|
||||
char: 't',
|
||||
description: 'template'
|
||||
}),
|
||||
|
||||
gitHubUser: flags.string({
|
||||
char: 'u',
|
||||
description: 'github username'
|
||||
}),
|
||||
|
||||
gitHubPassword: flags.string({
|
||||
description: 'github password'
|
||||
}),
|
||||
|
||||
// @todo make flag
|
||||
githubPages: flags.string({
|
||||
char: 'p',
|
||||
description: 'enable github pages'
|
||||
}),
|
||||
|
||||
repoOwner: flags.string({
|
||||
char: 'p',
|
||||
description: 'github repo owner'
|
||||
}),
|
||||
|
||||
visibility: flags.string({
|
||||
char: 'v',
|
||||
description: 'github repo visibility (public/private)'
|
||||
}),
|
||||
};
|
||||
|
||||
async run() {
|
||||
const { flags } = this.parse(Init);
|
||||
|
||||
const name =
|
||||
flags.name ||
|
||||
(await inquirer.prompt({
|
||||
name: 'name',
|
||||
message: 'Give your workspace a name',
|
||||
type: 'input',
|
||||
default: 'foam',
|
||||
})).name;
|
||||
|
||||
const template =
|
||||
flags.template ||
|
||||
(await inquirer.prompt({
|
||||
name: 'template',
|
||||
message: 'Choose from one of the available templates',
|
||||
type: 'list',
|
||||
choices: [
|
||||
{ name: 'Default (foam-template)' },
|
||||
{ name: 'Gatsby + GitHub Actions (foam-template-gatsby)' },
|
||||
{ name: '11ty + Netlify (foam-template-eleventy)' },
|
||||
{ name: 'MLH Fellowship Workspace (foam-template-mlh)' },
|
||||
],
|
||||
})).template;
|
||||
|
||||
const scm = (await inquirer.prompt([
|
||||
{
|
||||
name: 'scm',
|
||||
message: 'How do you want to store your workspace?',
|
||||
type: 'list',
|
||||
default: 'GitHub',
|
||||
choices: [
|
||||
{ name: 'GitHub' },
|
||||
{ name: 'Local git repository' },
|
||||
{ name: 'Local directory (no source control)' },
|
||||
],
|
||||
},
|
||||
])).scm;
|
||||
|
||||
if (scm === 'GitHub') {
|
||||
const userName =
|
||||
flags.gitHubUser ||
|
||||
(await inquirer.prompt({
|
||||
name: 'username',
|
||||
message: 'GitHub username',
|
||||
type: 'input'
|
||||
})).username;
|
||||
|
||||
const password =
|
||||
flags.gitHubPassword ||
|
||||
(await inquirer.prompt({
|
||||
name: 'password',
|
||||
message: 'GitHub password',
|
||||
type: 'password'
|
||||
})).password;
|
||||
|
||||
const owner =
|
||||
flags.repoOwner ||
|
||||
(await inquirer.prompt({
|
||||
name: 'owner',
|
||||
message: 'GitHub repository owner',
|
||||
type: 'input',
|
||||
default: userName
|
||||
})).owner;
|
||||
|
||||
const visibility =
|
||||
flags.visibility ||
|
||||
(await inquirer.prompt({
|
||||
name: 'visibility',
|
||||
message: 'Should the repository be public or private?',
|
||||
type: 'list',
|
||||
choices: [
|
||||
{ name: 'Public' },
|
||||
{ name: 'Private' }
|
||||
],
|
||||
})).visibility.toLowerCase();
|
||||
|
||||
const pages =
|
||||
flags.githubPages ||
|
||||
((await inquirer.prompt({
|
||||
name: 'pages',
|
||||
message: 'Publish automatically to GitHub pages?',
|
||||
type: 'list',
|
||||
choices: [
|
||||
{ name: 'Yes' },
|
||||
{ name: 'No' }
|
||||
],
|
||||
})).pages === 'Yes');
|
||||
|
||||
|
||||
const sure = (await inquirer.prompt({
|
||||
name: 'sure',
|
||||
type: 'confirm',
|
||||
message: `Create a new ${visibility} Foam in https://github.com/${owner}/${name}?`
|
||||
})).sure;
|
||||
|
||||
if (sure) {
|
||||
const spinner = ora().start();
|
||||
await new Promise(resolve => {
|
||||
setTimeout(() => resolve(), 1000);
|
||||
});
|
||||
spinner.succeed();
|
||||
spinner.succeed('Foam workspace created!');
|
||||
spinner.succeed('Run "code foam" to open your new workspace');
|
||||
}
|
||||
} else {
|
||||
console.log(`Created a private Foam workspace in ./${name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ Successfully generated link references and heading!
|
||||
return writeFileToDisk(note.path, file);
|
||||
}
|
||||
|
||||
return null;
|
||||
return Promise.resolve(null);
|
||||
})
|
||||
|
||||
await Promise.all(fileWritePromises);
|
||||
|
||||
@@ -49,7 +49,7 @@ Successfully generated link references and heading!
|
||||
if (kebabCasedFileName) {
|
||||
return renameFile(note.path, kebabCasedFileName);
|
||||
}
|
||||
return null;
|
||||
return Promise.resolve(null);
|
||||
})
|
||||
|
||||
await Promise.all(fileRename);
|
||||
@@ -80,7 +80,7 @@ Successfully generated link references and heading!
|
||||
return writeFileToDisk(note.path, file);
|
||||
}
|
||||
|
||||
return null;
|
||||
return Promise.resolve(null);
|
||||
}))
|
||||
|
||||
await Promise.all(fileWritePromises);
|
||||
|
||||
63
packages/foam-cli/src/commands/publish.ts
Normal file
63
packages/foam-cli/src/commands/publish.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {Command, flags} from '@oclif/command'
|
||||
import { execSync } from 'child_process';
|
||||
import * as ora from 'ora';
|
||||
|
||||
|
||||
export default class Publish extends Command {
|
||||
static description = 'Push all changes to git repository';
|
||||
|
||||
static examples = [
|
||||
`$ foam publish -m "Optional log message"`,
|
||||
]
|
||||
|
||||
static flags = {
|
||||
message: flags.string({
|
||||
char: 'm',
|
||||
description: "optional message"
|
||||
}),
|
||||
remote: flags.string({
|
||||
char: 'r',
|
||||
description: "remote"
|
||||
}),
|
||||
branch: flags.string({
|
||||
char: 'b',
|
||||
description: "branch"
|
||||
})
|
||||
}
|
||||
|
||||
async execWithSpinner(command: string, message: string) {
|
||||
const spinner = ora(message).start();
|
||||
|
||||
// @todo handle errors
|
||||
const response = execSync(command).toString();
|
||||
|
||||
spinner.succeed(`${message} Done!`);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async printPublishInfo(remote: string) {
|
||||
// @todo actually get this data from GH API
|
||||
|
||||
const [, remotePath] = execSync(`git remote get-url ${remote}`).toString().trim().split(':');
|
||||
const [repo, org] = remotePath.split('/').reverse();
|
||||
console.log('');
|
||||
console.log(`🎉 Your changes will be available shortly at https://${org}.github.io/${repo.replace('.git', '')}`);
|
||||
console.log('');
|
||||
|
||||
}
|
||||
|
||||
async run() {
|
||||
const {flags} = this.parse(Publish);
|
||||
|
||||
// @todo improve
|
||||
const message = flags.message || 'foam publish';
|
||||
const remote = flags.remote || 'origin';
|
||||
const branch = flags.branch || 'master';
|
||||
|
||||
await this.execWithSpinner(`git add -A`, 'Staging changes...');
|
||||
await this.execWithSpinner(`git commit -m "${message}"`, 'Creating a commit...');
|
||||
await this.execWithSpinner(`git push ${remote} ${branch}`, "Publishing...");
|
||||
await this.printPublishInfo(remote);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
import * as fs from 'fs'
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param fileUri absolute path for the file that needs to renamed
|
||||
* @param newFileName "new file name" without the extension
|
||||
*/
|
||||
export const renameFile = async (fileUri: string, newFileName: string) => {
|
||||
const fileName = fileUri.split('/').pop();
|
||||
const extension = fileName?.split('.').pop();
|
||||
const newFileUri = fileUri.replace(`${fileName}`, `${newFileName}.${extension}`);
|
||||
const dirName = path.dirname(fileUri);
|
||||
const extension = path.extname(fileUri);
|
||||
const newFileUri = path.join(dirName, `${newFileName}${extension}`);
|
||||
|
||||
return fs.promises.rename(fileUri, newFileUri);
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
export const writeFileToDisk = async (fileUri: string, data: string): Promise<Boolean> => {
|
||||
return fs.promises.writeFile(fileUri, data).then(() => true).catch(err => {
|
||||
console.log('error while writing to file: ', err)
|
||||
return false;
|
||||
})
|
||||
export const writeFileToDisk = async (fileUri: string, data: string) => {
|
||||
return fs.promises.writeFile(fileUri, data);
|
||||
}
|
||||
@@ -3,6 +3,8 @@ import { renameFile } from '../src/utils/rename-file'
|
||||
import * as fs from 'fs';
|
||||
import mockFS from 'mock-fs';
|
||||
|
||||
const doesFileExist = (path) => fs.promises.access(path).then(() => true).catch(() => false);
|
||||
|
||||
describe('renameFile', () => {
|
||||
|
||||
const fileUri = './test/oldFileName.md';
|
||||
@@ -16,10 +18,11 @@ describe('renameFile', () => {
|
||||
});
|
||||
|
||||
it('should rename existing file', async () => {
|
||||
expect(fs.existsSync(fileUri)).toBe(true);
|
||||
expect(await doesFileExist(fileUri)).toBe(true);
|
||||
|
||||
renameFile(fileUri, 'new-file-name');
|
||||
|
||||
expect(fs.existsSync(fileUri)).toBe(false);
|
||||
expect(fs.existsSync('./test/new-file-name.md')).toBe(true);
|
||||
expect(await doesFileExist(fileUri)).toBe(false);
|
||||
expect(await doesFileExist('./test/new-file-name.md')).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ describe('writeFileToDisk', () => {
|
||||
it('should overrwrite existing file in the disk with the new data', async () => {
|
||||
const expected = `content in the new file`;
|
||||
await writeFileToDisk(fileUri, expected);
|
||||
const actual = fs.readFileSync(fileUri, { encoding: 'utf8' });
|
||||
const actual = await fs.promises.readFile(fileUri, { encoding: 'utf8' });
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
})
|
||||
17
yarn.lock
17
yarn.lock
@@ -2350,6 +2350,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/graphlib/-/graphlib-2.1.6.tgz#5c7b515bfadc08d737f2e84fadbd151117c73207"
|
||||
integrity sha512-os2Xj+pV/iwLkLX17LWuXdPooA4Jf4xg8WSdKPUi0tCSseP95oikcA1irOgVl3K2QYnoXrjJT3qVZeQ1uskB7g==
|
||||
|
||||
"@types/inquirer@^6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be"
|
||||
integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw==
|
||||
dependencies:
|
||||
"@types/through" "*"
|
||||
rxjs "^6.4.0"
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
|
||||
@@ -2444,6 +2452,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
|
||||
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
|
||||
|
||||
"@types/through@*":
|
||||
version "0.0.30"
|
||||
resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
|
||||
integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/unist@^2.0.0", "@types/unist@^2.0.2":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
|
||||
@@ -5937,7 +5952,7 @@ inquirer@^6.2.0, inquirer@^6.2.2:
|
||||
strip-ansi "^5.1.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^7.0.0, inquirer@^7.0.4:
|
||||
inquirer@^7.0.0, inquirer@^7.0.4, inquirer@^7.3.2:
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.2.tgz#25245d2e32dc9f33dbe26eeaada231daa66e9c7c"
|
||||
integrity sha512-DF4osh1FM6l0RJc5YWYhSDB6TawiBRlbV9Cox8MWlidU218Tb7fm3lQTULyUJDfJ0tjbzl0W4q651mrCCEM55w==
|
||||
|
||||
Reference in New Issue
Block a user