[Перевод] Пошаговое руководство по созданию интерфейса командной строки с помощью Node.js

JavaScript
[Перевод] Пошаговое руководство по созданию интерфейса командной строки с помощью Node.js

Node.js имеет более широкий спектр применения, помимо написания «традиционных» веб-приложений. микросервисы,REST API, инструменты, Интернет вещей и даже настольные приложения, он может удовлетворить любые ваши потребности в разработке.

Эта статья предназначена для использованияNode.jsдля создания инструментов командной строкиCLI. Начнем с рассмотрения некоторых сторонних инструментов для создания командных строк.npm包, затем создайте инструмент командной строки с нуля.

Мы собираемся реализовать инструмент командной строки, задачей которого является инициализация репозитория Git. Конечно, это не просто работает в фоновом режиме.git init, он будет делать что-то еще. Мы можем использовать его для инициализации репозитория Git и предоставления пользователям возможности интерактивного создания..gitignoreфайл и, наконец, выполнить фиксацию и отправить код в удаленный репозиторий.

Как всегда, вы можетеГитхаб (https://github.com/sssssssh/ginit)Найдите код, сопровождающий это руководство, на .

1. Зачем использовать Node.js для создания инструментов командной строки

Прежде чем мы углубимся в это, нам необходимо понять, почему мы выбралиNode.jsдля создания инструментов командной строки.

Самое очевидное преимущество заключается в том, что если вы читаете это, то, вероятно, потому, что выJavaScriptуже знаете.

Еще одним важным преимуществом является то, что использованиеNode.jsЭкосистема означает, что вы можете использовать тысячиnpm包. Многие из них были созданы для создания мощных инструментов командной строки.

Наконец, мы можем пройтиnpmУправляйте зависимостями, не беспокоясь о проблемах совместимости, вызванных определенными инструментами управления системными пакетами, такими какapt,yum,homebrew.

2. Создайте инструмент командной строки: ginit

С помощью этого урока мы создадимginitинструмент командной строки. он достигаетgit init, но не только эту функцию.

Вам может быть интересно, для чего именно это нужно.

Как мы все знаем,git initбудет инициализирован в текущей папкеgit仓库. Однако обычно это связывание нового или существующего проекта сGitодин из многих повторяющихся шагов выше. Например, в рамках классического рабочего процесса вы можете:

  1. пройти черезgit initИнициализировать локальный репозиторий
  2. Создайте удаленный репозиторий, что обычно нужно делать через браузер
  3. добавить в удаленный
  4. Создайте.gitignoreдокумент
  5. Добавьте свой собственный файл проекта
  6. Отправьте исходные файлы проекта
  7. отправить в удаленный репозиторий

Обычно требуется больше операций, однако в учебных целях мы реализуем только описанные выше шаги в этом руководстве. Эти шаги повторяются, и мы делаем это через инструменты командной строки, не лучше ли это, чем вставка и копированиеgitКак насчет ссылки на репозиторий лучше?

следовательно,ginitВсе, что вам нужно сделать, это создать в текущей папкеGitрепозиторий, создайте удаленный репозиторий (здесь мы используем git), затем добавьте его в качестве удаленного репозитория, затем он предоставит простой интерактивный мастер для создания.gitignore, добавьте файл и отправьте его на пульт. Возможно, он не уменьшит ваше время, однако уменьшит часть вашей повторяющейся работы.

Имея это в виду, давайте начнем!

3. Зависимости проекта

Одно можно сказать наверняка: консоли никогда не будут иметь утонченный графический интерфейс с точки зрения внешнего вида. Однако это не означает, что он должен быть уродливым монохромным текстом. Вы можете быть удивлены, насколько хорошо инструмент командной строки может работать, оставаясь при этом функциональным. Мы нашли несколько библиотек, улучшающих представление интерфейса:chalkИспользуется для вывода цветного текста в терминал;cluiИспользуется для добавления некоторых компонентов пользовательского интерфейса. Там тоже весело, будем пользоватьсяfigletсоздать на основеASCIIкрутые баннеры и воспользуйтесь преимуществамиclearочистить консоль.

С точки зрения ввода и вывода,Node.jsоснованиеReadlineМодулей более чем достаточно для запроса пользовательского ввода. Однако мы будем использовать стороннюю библиотекуInquirer, который обеспечивает более сложную функциональность. Помимо реализации функции опроса пользователя, также предусмотрена функция радиокнопок и флажков в консоли.

мы также будем использоватьminimistдля анализа аргументов, введенных в командной строке.

Это полная версия, которую мы использовали при разработке инструмента командной строки.npmСписок пакетов:

  • chalk: Сделать наш вывод красочным;
  • clear: очистить экран терминала;
  • clui: Рисовать таблицы, дашборды, индикаторы загрузки и т.д. в командной строке;
  • figlet: сгенерировано на основеASCIIискусство слова;
  • inquirer: создать интерактивный интерфейс командной строки;
  • minimist: анализировать аргументы командной строки;
  • configstore: легко загружать и сохранять информацию о конфигурации;

Дополнительно мы будем использовать следующие пакеты:

  • @octokit/rest: на основеNode.jsинструмент Github REST API;
  • @octokit/auth-basic: Githubреализация стратегии аутентификации;
  • lodash: библиотека инструментов JavaScript;
  • simple-git: существуетNode.jsвыполнить вGitинструменты для команд;
  • touch: выполнитьUnix touchинструменты для команд;

4. Начните свое шоу

Хотя мы создали этот инструмент командной строки с нуля, не забывайте, что вы также можетеРепозиторий GitHub (https://github.com/sssssssh/ginit)Скопируйте код в .

Создайте новый каталог для этого проекта, конечно, вы можете назвать его по-другому, это не обязательноginit:

mkdir ginit
cd ginit

создать новыйpackage.jsonдокумент:

npm init -y

в конечном итоге сгенерируетpackage.jsonдокумент

{
    "name": "ginit",
    "version": "1.0.0",
    "description": "'git init' on steroids",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [
        "Git",
        "CLI"
    ],
    "license": "ISC"
}

Теперь приступайте к установке зависимостей проекта:

npm install chalk clear clui figlet inquirer minimist configstore @octokit/rest @octokit/auth-basic lodash simple-git touch

Создать проект в проектеindex.jsфайл плюс следующий код:

// index.js

const chalk = require('chalk');
const clear = require('clear');
const figlet = require('figlet');

5. Добавьте несколько полезных методов

создать каталогlibдиректорию и разделим наш код на следующие модули:

  • file.js: Базовое управление файлами
  • inquirer.js: обрабатывает взаимодействие с пользователем в командной строке;
  • github.js: управлять токеном git пользователя;
  • repo.js: Управление складом Git;

давайте начнем писатьlib/file.jsкод в . Нам нужно сделать следующее:

  1. Получить текущий каталог (как имя текущего репозитория по умолчанию);
  2. Проверьте, существует ли каталог (проверив.gitСуществует ли каталог, чтобы определить, есть ли в текущем каталоге репозиторий git);

Это звучит достаточно просто, однако есть несколько вопросов, которые следует учитывать.

Во-первых, вы можете подумать об использованииfsмодульныйrealpathSyncспособ получить текущий каталог:

path.basename(path.dirname(fs.realpathSync(__filename)));

Этот метод отлично работает, когда мы вызываем его из корня файла, где находится командная строка. Однако наш инструмент командной строки можно вызвать из любого каталога. Это означает, что нам нужно получить имя текущего рабочего каталога, а не имя каталога, в котором находится код командной строки. Итак, вам лучше использоватьprocess.cwd():

path.basename(process.cwd());

Во-вторых, лучший способ проверить, существует ли файл, этоРазнообразие. В настоящее время лучшим способом является использованиеexistsSync, если файл существует, он вернетtrue, иначе возвратfalse.

Объединив вышеизложенное, давайтеlib/files.jsДобавьте следующий код в:

// files.js

const fs = require('fs');
const path = require('path');

module.exports = {
    // 获取目录名称
    getCurrentDirectoryBase: () => {
        return path.basename(process.cwd());
    },

    // 判断目录是否存在
    directoryExists: (filePath) => {
        return fs.existsSync(filePath);
    },
};

существуетindex.js, добавьте следующий код:

// index.js

const files = require('./lib/files');

С этим мы можем начать разработку нашего инструмента командной строки.

6. Инициализируйте инструмент командной строки

Теперь давайте реализуем фазу запуска инструмента командной строки.

Чтобы отобразить модули, которые мы установили для улучшения вывода консоли, мы сначала очищаем экран, а затем отображаем баннер вindex.jsДобавьте следующий код в:

// index.js

// 清除命令行
clear();

// 输出Logo
console.log(chalk.yellow(figlet.textSync('Ginit', { horizontalLayout: 'full' })));

Вы можете сделать это, запустивnode index.jsчтобы выполнить его, вывод выглядит следующим образом:

Далее, давайте сделаем простую проверку, чтобы убедиться, что в текущем каталоге нет репозитория git. Это легко, просто используйте метод, который мы создали, чтобы проверить.gitСуществует ли метод, вindex.jsДобавьте следующий код в:

// 判断是否存在.git文件
if (files.directoryExists('.git')) {
    console.log(chalk.red('已经存在一个本地仓库!'));
    process.exit();
}

7. Запрашивать пользователя для ввода

Далее нам нужно создать функцию, которая поможет пользователю ввести своиGitHubНомер счета и пароль.

мы можем использоватьInquirerДля достижения этого он предоставляет множество типов подсказок. Эти методы чем-то похожи наHTMLэлементы управления в . Для сбора пользовательскихGitHubУчетная запись и пароль, нам нужно использовать элементы управления вводом и паролем.

Первый вlib/inquirer.jsДобавьте следующий код в:

// inquirer.js

const inquirer = require('inquirer');
const files = require('./files');

module.exports = {
    // 询问git账号信息
    askGithubCredentials: () => {
        const questions = [
            {
                name: 'username',
                type: 'input',
                message: '请输入你的git账号或邮箱地址:',
                validate: function (value) {
                    if (value.length) {
                        return true;
                    } else {
                        return '请输入你的git账号或邮箱地址.';
                    }
                },
            },
            {
                name: 'password',
                type: 'password',
                message: '请输入你的密码:',
                validate: function (value) {
                    if (value.length) {
                        return true;
                    } else {
                        return '请输入你的密码.';
                    }
                },
            },
        ];
        return inquirer.prompt(questions);
    }
};

Как видите, поinquirer.prompt()Задаем пользователю ряд вопросов, которые мы передаем функции в виде массиваprompt. Каждый вопрос состоит из объекта, гдеnameпредставляет имя поля,typeУказывает, что мы хотим использовать тип элемента управления,messageто, что мы хотим показать пользователю,validateэто функция, которая проверяет поля ввода пользователя.

inquirer.prompt()вернетPromiseобъекта, если проверка пройдет, мы получимnameа такжеpasswordОбъект с 2 свойствами.

Добавьте следующий код вindex.js:

// index.js

const inquirer  = require('./lib/inquirer');

const run = async () => {
    const credentials = await inquirer.askGithubCredentials();
    console.log(credentials);
};

run();

бегатьnode index.jsРезультат выглядит следующим образом:

Совет: когда вы закончите тестирование, не забудьте поставитьconst inquirer = require('./lib/inquirer');отindex.js, потому что нам это не нужно.

8. Обработка авторизации GitHub

Следующим шагом является создание функции, которая получаетGitHub APIизOAuth TOKEN. На самом деле мы получаем его через номер счета и парольtoken.

Конечно, мы не хотим, чтобы пользователям приходилось вводить номер учетной записи и пароль каждый раз, когда они используют наш инструмент. Вместо этого мы сэкономимOAuthТокен используется для последующих запросов. Это будет использоватьconfigstoreЭтот пакет.

Девять, сохраните конфигурацию

Сохранение информации о конфигурации выглядит просто на первый взгляд, вы можете просто прочитать и записать файл JSON. но,configstoreЭтот пакет имеет следующие преимущества:

  1. Он определит лучшее место для хранения файлов в зависимости от вашей операционной системы и текущего пользователя;
  2. Не нужно читать файл, просто изменитеconfigstoreОбъекта достаточно, и он поможет вам с последним;

Использование очень простое, создайте экземпляр и передайте идентификатор, например:

const Configstore = require('configstore');
const conf = new Configstore('ginit');

еслиconfigstoreЕсли файл не существует, он вернет пустой объект и создаст файл в фоновом режиме. Если файл существует, вы можете напрямую использовать его содержимое. Теперь вы можете напрямую изменять по мере необходимостиconfсвойства объекта. При этом не нужно беспокоиться о том, как его сохранить, он сам о себе позаботится.

Подсказка: вmacOSВ системе файл будет сохранен в/Users/[YOUR-USERNME]/.config/configstore/ginit.jsonВниз. существуетLinuxФайлы в системе хранятся в/home/[YOUR-USERNME]/.config/configstore/ginit.json.

10. Общайтесь с GitHub API

Давайте создадим файл для обработкиGitHub Token. Создайтеlib/github.jsи скопируйте следующий код:

// github.js

const CLI = require('clui');
const Configstore = require('configstore');
const Spinner = CLI.Spinner;
const { Octokit } = require("@octokit/rest")
const { createBasicAuth } = require('@octokit/auth-basic');

const inquirer = require('./inquirer');
const pkg = require('../package.json');
// 初始化本地的存储配置
const conf = new Configstore(pkg.name);

Теперь давайте создадим функцию, чтобы проверить, есть ли у насtoken. Мы также создали функцию для других модулей, чтобы получить ее.octokitпример. существуетlib/github.jsДобавьте следующий код в:

// github.js

// ...初始化

// 模块内部的单例
let octokit;

module.exports = {
    // 获取octokit实例
    getInstance: () => {
        return octokit;
    },

    // 获取本地token
    getStoredGithubToken: () => {
        return conf.get('github.token');
    }
}

еслиconfобъект существует иgithub.tokenсвойство тоже существует, значитtokenсуществует. Здесь мы можем поставитьtokenВернитесь к вызывающей функции. Мы поговорим об этом позже.

Если не провереноtoken, вам нужно получить один. Конечно, получитьOAuth tokenОн включает в себя сетевые запросы, а это означает, что пользователям нужно немного подождать. Пользуясь случаем, мы видимcluiОбеспечивает улучшения пользовательского интерфейса полосы управления, одним из них является эффект загрузки.

Создать эффект загрузки легко:

const status = new Spinner('Authenticating you, please wait...');
status.start();

Когда закончите, просто остановите его, и он исчезнет с экрана:

status.stop();

Подсказка: вы также можете использоватьupdateдля динамического набора текста. Это может быть полезно, если вам нужен индикатор прогресса, например, показывающий текущий процент прогресса.

Скопируйте следующий код вlib/github.js, законченоGitHubКод проверки подлинности:

// github.js

module.exports = {
    // 获取实例
    getInstance: () => { ... },

    // 获取本地token
    getStoredGithubToken: () => { ... },

    // 通过个人账号信息获取token
    getPersonalAccessToken: async () => {
        const credentials = await inquirer.askGithubCredentials();
        const status = new Spinner('验证身份中,请等待...');

        status.start();

        const auth = createBasicAuth({
            username: credentials.username,
            password: credentials.password,
            async on2Fa() {
                // 等待实现
            },
            token: {
                scopes: ['user', 'public_repo', 'repo', 'repo:status'],
                note: 'ginit, the command-line tool for initalizing Git repos',
            },
        });

        try {
            const res = await auth();

            if (res.token) {
                conf.set('github.token', res.token);
                return res.token;
            } else {
                throw new Error('获取GitHub token失败');
            }
        } finally {
            status.stop();
        }
    }
};

Давайте сделаем это шаг за шагом:

  1. Используйте функцию, которую мы определили ранееaskGithubCredentialsзапрашивать учетную запись и пароль пользователя;
  2. Мы используемcreateBasicAuthсоздатьauthФункция, удобный обратный звонок. Необходимо передать эту функцию имени пользователя и паролю пользователя, но также необходимо передать одинtokenобъект, который имеет следующие 2 свойства:
    1. note: зафиксировать цель получения токена;
    2. scopes: список разрешенных областей использования информации, вы можетеGitHubУзнайте больше на;
  3. мы будемtry catchиспользовать вawaitСинтаксис ожидает возврата результата функции;
  4. Если авторизация прошла успешно, мы получимtoken, вы можете положить его вconfigstore, удобно использовать непосредственно в следующий раз;
  5. Если авторизация по какой-то причине не удалась, мы ее перехватим и обработаем исключение по коду состояния;

любой вы создаетеtoken(независимо от того, созданы ли они вручную или сгенерированы через API) можно увидеть здесь. Во время разработки может потребоваться удалитьginitизtoken(можно получить черезnoteидентификация параметра) для его регенерации.

возобновитьindex.jsкод в:

// index.js

const github = require('./lib/github');

...

const run = async () => {
    // 从本地获取token记录
    let token = github.getStoredGithubToken();
    if(!token) {
        // 通过账号、密码获取token
        token = await github.getPersonalAccessToken();
    }
    console.log(token);
};

При первом запуске вам потребуется ввести имя пользователя и пароль. мы будем вgithubсоздатьtokenи сохранить его. В следующий раз, когда мы запустим, мы будем напрямую использовать сохраненныйtokenВыполните аутентификацию личности.

11. Работа с двухфакторной аутентификацией

Надеюсь, вы заметили в коде вышеon2Faфункция. Эта функция будет вызываться, когда учетная запись пользователя использует двухфакторную аутентификацию. впусти насlib/inquirer.jsВставьте следующий код в:

// inquirer.js

const inquirer = require('inquirer');

module.exports = {
    // 询问git账号信息
    askGithubCredentials: () => { ... },

    // 询问双重认证码
    getTwoFactorAuthenticationCode: () => {
        return inquirer.prompt({
            name: 'twoFactorAuthenticationCode',
            type: 'input',
            message: '请输入你的双重认证验证码:',
            validate: function (value) {
                if (value.length) {
                    return true;
                } else {
                    return '请输入你的双重认证验证码:.';
                }
            },
        });
    }
}

Исправлятьlib/github.jsсерединаon2Faфункция:

// github.js

async on2Fa() {
    status.stop();
    const res = await inquirer.getTwoFactorAuthenticationCode();
    status.start();
    return res.twoFactorAuthenticationCode;
}

Теперь наша программа может обрабатыватьGitHubДвухфакторная аутентификация.

12. Создайте склад

ПолучатьOauthПосле токена мы можем использовать его для создания удаленных репозиториев.

Точно так же мы можем использоватьInquirerзадать ряд вопросов. Нам нужно получить имя репозитория, мы можем попросить пользователя заполнить описание, и нам нужно спросить, является ли репозиторий общедоступным или частным.

мы можем использоватьminimistчтобы получить имя и описание репозитория из аргументов командной строки.

ginit my-repo "just a test repository"

Следующий код будет анализировать массив:

const argv = require('minimist')(process.argv.slice(2));
// { _: [ 'my-repo', 'just a test repository' ] }

Мы реализуем вышеупомянутый опрос через код. Сначала скопируйте следующий код вlib/inquirer.jsсередина:

// inquirer.js

const inquirer = require('inquirer');
const files = require('./files');

module.exports = {
    // 询问git账号信息
    askGithubCredentials: () => { ... },

    // 询问双重认证码
    getTwoFactorAuthenticationCode: () => { ... },

    // 询问仓库详细信息
    askRepoDetails: () => {
        const argv = require('minimist')(process.argv.slice(2));

        const questions = [
            {
                type: 'input',
                name: 'name',
                message: '请输入git仓库名称:',
                default: argv._[0] || files.getCurrentDirectoryBase(),
                validate: function (value) {
                    if (value.length) {
                        return true;
                    } else {
                        return '请输入git仓库名称.';
                    }
                },
            },
            {
                type: 'input',
                name: 'description',
                default: argv._[1] || null,
                message: '请输入仓库描述(选填):',
            },
            {
                type: 'list',
                name: 'visibility',
                message: '共有仓库 或 私有仓库:',
                choices: ['public', 'private'],
                default: 'public',
            },
        ];
        return inquirer.prompt(questions);
    }
};

Создайтеlib/repo.jsфайл и добавьте следующий код:

// repo.js

const CLI = require('clui');
const fs = require('fs');
const git = require('simple-git/promise')();
const Spinner = CLI.Spinner;
const touch = require('touch');
const _ = require('lodash');

const inquirer = require('./inquirer');
const gh = require('./github');

module.exports = {
    // 创建远程仓库
    createRemoteRepo: async () => {
        const github = gh.getInstance();
        const answers = await inquirer.askRepoDetails();

        const data = {
            name: answers.name,
            description: answers.description,
            private: answers.visibility === 'private',
        };

        const status = new Spinner('创建远程仓库中...');
        status.start();

        try {
            const response = await github.repos.createForAuthenticatedUser(data);
            return response.data.ssh_url;
        } finally {
            status.stop();
        }
    }
}

Получив указанную выше информацию, я могу создать репозиторий Git. Мы устанавливаем сгенерированный склад локально как наш удаленный склад. Но перед этим давайте интерактивно создадим.gitignoreфайл.

13. Создайте .gitignore

Далее мы собираемся создать простой «мастер» командной строки для генерации.gitignoreдокумент. Если пользователь запускает наш инструмент командной строки в существующем каталоге проекта, покажите ему файлы и каталоги, которые уже существуют в текущем каталоге, и позвольте ему выбрать, какие файлы и папки следует игнорировать.

inquirerДля нас предусмотрен флажок для использования.

Нам нужно просканировать текущий каталог.gitа также.gitignoreдругие документы.

const filelist = _.without(fs.readdirSync('.'), '.git', '.gitignore');

Если нет файла для добавления в «.gitignore», создайте его напрямую.gitignoreфайл

if (filelist.length) {
  ...
} else {
  touch('.gitignore');
}

впусти насlib/inquirer.jsДобавьте следующий код в:

// inquirer.js

// 选择需要忽略的文件
askIgnoreFiles: (fileList) => {
    const questions = [
        {
            type: 'checkbox',
            name: 'ignore',
            message: '请选择你想要忽略的文件:',
            choices: fileList,
            default: ['node_modules', 'bower_components'],
        },
    ];
    return inquirer.prompt(questions);
},

Примечание. Мы можем предоставить некоторые параметры по умолчанию, еслиnode_modulesа такжеbower_componentsЕсли он существует, мы предварительно выберем его.

существуетlib/repo.js, мы добавляем следующий код:

// repo.js

// 创建git ignore
createGitignore: async () => {
    const fileList = _.without(fs.readdirSync('.'), '.git', '.gitignore');

    if (fileList.length) {
        const answers = await inquirer.askIgnoreFiles(fileList);

        if (answers.ignore.length) {
            // 写入信息
            fs.writeFileSync('.gitignore', answers.ignore.join('\n'));
        } else {
            // 创建文件
            touch('.gitignore');
        }
    } else {
        // 创建文件
        touch('.gitignore');
    }
},

После отправки мы сгенерируем.gitignoreдокумент. Так как он может быть сгенерирован.gitignoreфайл, давайте инициализируем репозиторий git.

14. Взаимодействие с git из командной строки

Существует множество реализаций иgitИнтерактивный способ, однако, самый простой способ, вероятно,simple-git. Эта библиотека предоставляет набор асинхронных функций, которые можно связать для выполнения команд git в фоновом режиме.

Вот повторяющаяся задача, которую нам нужно выполнить:

  1. бегатьgit init
  2. Добавить к.gitignore
  3. Добавьте остальные файлы в каталог
  4. Завершить первоначальную отправку
  5. Добавьте только что созданный удаленный репозиторий
  6. отправить код на удаленный

существуетlib/repo.jsДобавьте следующий код в:

// repo.js

// 设置
setupRepo: async (url) => {
    const status = new Spinner('初始化本地仓库并推送到远端仓库中...');
    status.start();

    try {
        await git.init();
        await git.add('.gitignore');
        await git.add('./*');
        await git.commit('Initial commit')
        await git.addRemote('origin', url);
        await git.push('origin', 'master');
    } finally {
        status.stop();
    }
},

15. Соедините код вместе

Во-первых, нам нужноlib/github.jsДобавьте в файл функцию, функция которой заключается в созданииoauthСертификация:

// github.js

// 通过token登陆
githubAuth: (token) => {
    octokit = new Octokit({
        auth: token,
    });
},

Затем нам нужно создать функцию для управления выборкойtokenлогика. существуетrunПеред функцией добавьте следующий код:

// index.js

// 获取github token
const getGithubToken = async () => {
    // 从本地获取token记录
    let token = github.getStoredGithubToken();
    if (token) {
        return token;
    }

    // 通过账号、密码获取token
    token = await github.getPersonalAccessToken();
    return token;
};

Наконец, мы обновляем нашrunфункция:

// index.js

const run = async () => {
    try {
        // 获取token
        const token = await getGithubToken();
        github.githubAuth(token);

        // 创建远程仓库
        const url = await repo.createRemoteRepo();

        // 创建 .gitignore
        await repo.createGitignore();

        // 初始化本地仓库并推送到远端
        await repo.setupRepo(url);

        console.log(chalk.green('All done!'));
    } catch (err) {
        if (err) {
            switch (err.status) {
                case 401:
                    console.log(chalk.red("登陆失败,请提供正确的登陆信息"));
                    break;
                case 422:
                    console.log(chalk.red('远端已存在同名仓库'));
                    break;
                default:
                    console.log(chalk.red(err));
            }
        }
    }
};

Как видите, перед вызовом других наших функций (createRemoteRepo(), createGitignore(), setupRepo()), мы удостоверяемся, что пользователь аутентифицирован. Кроме того, любые ошибки обрабатываются, и пользователю предоставляется соответствующая обратная связь.

Вы можете найти полный код в репозитории git.

Теперь у вас есть инструмент командной строки, который вы можете запустить. Запустите его и посмотрите, работает ли он так, как вы ожидаете.

16. Сделайте команду ginit глобально доступной

Еще одна вещь, которую необходимо сделать, — сделать нашу командную строку доступной глобально. Чтобы добиться этого, нам нужноindex.jsзаголовок файла сshebang.

#!/usr/bin/env node

Затем нам нужноpackage.jsonдобавить один кbinАтрибуты. Используется для привязки имени командыginitи исполняемые файлы.

"bin": {
  "ginit": "./index.js"
}

Затем установите модуль глобально, и инструмент командной строки готов к использованию.

npm install -g

Если вы хотите убедиться, что установка эффективна, вы можете перечислить модули узла, установленные глобально на этом компьютере, чтобы увидеть:

npm ls -g --depth=0

17. Внешний вид

Мы создали красивую и лаконичную инициализациюGitИнструмент командной строки для репозиториев. И вы можете многое сделать, чтобы улучшить его.

если выBitbucketпользователь, вы можете использоватьBitbucket APIЭто добавляет командную строку для созданияBitbucket仓库的功能。 этопакет узла bitbucket-apiпоможет вам. Вы можете добавить еще один параметр командной строки или спросить пользователя, хотят ли они использоватьBitbucket, или напрямую обрабатывать настоящееGitHubзаменить код наBitbucket.

вы можете предоставить.gitignoreКоллекция файлов по умолчанию, не жестко закодированная.preferencesЭтот пакет подходит для этого сценария, или вы можете предоставить шаблон, который предлагает пользователю ввести соответствующий тип шаблона. Он также может быть интегрирован в.gitignore.ioсередина.

В дополнение к этому вы можете добавить другие проверки, предоставить возможность пропускать определенные шаги и многое другое.

Это старая статья, но автор обновил часть контента в феврале этого года, чтобы удалить недопустимые зависимости. При этом в процессе чтения я также оптимизировал код примера.

обо мне

Я занимаюсь переносом кода без эмоций. Каждую неделю я буду обновлять от 1 до 2 статей, связанных с интерфейсом. Если вам интересно, вы можете отсканировать приведенный ниже QR-код, чтобы подписаться или выполнить поиск непосредственно в WeChat.前端补习班Сфокусируйся на.

Трудно быть опытным во фронтенде, давайте делать уроки вместе!

Хорошо, перевод завершен, оригинальная ссылка здесьBuild a JavaScript Command Line Interface (CLI) with Node.js.