Logo Zephyrnet

Zbuduj JavaScript Command Line Interface (CLI) za pomocą Node.js.

Data:

Chociaż Node.js jest świetny dla „tradycyjnych” aplikacji internetowych, jego potencjalne zastosowania są znacznie szersze. Mikroserwisy, REST API, oprzyrządowanie, praca z Internetem Rzeczy, a nawet aplikacje desktopowe: to cię wspiera.

Innym obszarem, w którym Node.js jest naprawdę przydatny, jest tworzenie aplikacji wiersza poleceń — i to właśnie będziemy robić w tym artykule. Zaczniemy od przyjrzenia się kilku pakietom innych firm, które mają pomóc w pracy z wierszem poleceń, a następnie zbudujemy od podstaw przykład z prawdziwego świata.

To, co zamierzamy zbudować, to narzędzie do inicjowania repozytorium Git. Jasne, będzie działać git init pod maską, ale zrobi coś więcej niż tylko to. Utworzy również zdalne repozytorium na GitHub bezpośrednio z wiersza poleceń, umożliwiając użytkownikowi interaktywne tworzenie .gitignore pliku, a na koniec wykonaj wstępne zatwierdzenie i wypchnięcie.

Jak zawsze, kod towarzyszący temu samouczkowi można znaleźć na naszym GitHub repo.

Zbuduj węzeł CLI

Ten artykuł został zaktualizowany w 2020 roku. Aby uzyskać bardziej dogłębną wiedzę na temat JavaScript, przeczytaj naszą książkę, JavaScript: Novice to Ninja, 2. edycja.

Zanim zagłębimy się i zaczniemy budować, warto zastanowić się, dlaczego możemy wybrać Node.js do zbudowania aplikacji wiersza poleceń.

Najbardziej oczywistą zaletą jest to, że jeśli to czytasz, prawdopodobnie już się z tym zapoznałeś — a także JavaScript.

Kolejną kluczową zaletą, jak zobaczymy w dalszej części, jest to, że silny ekosystem Node.js oznacza, że ​​wśród setek tysięcy pakietów dostępnych do różnych celów jest wiele, które są specjalnie zaprojektowane, aby pomóc w tworzeniu potężnych narzędzia wiersza polecenia.

Wreszcie możemy użyć npm zarządzać wszelkimi zależnościami, zamiast martwić się o menedżery pakietów specyficzne dla systemu operacyjnego, takie jak Aptitude, Yum lub Homebrew.

Wskazówka: niekoniecznie jest to prawdą, ponieważ narzędzie wiersza polecenia może mieć inne zależności zewnętrzne.

Co zbudujemy: ginit

Ginit, nasz Node CLI w akcji

W tym samouczku stworzymy narzędzie wiersza poleceń, które wywołuję git. Jego git init, ale na sterydach.

Pewnie zastanawiasz się, co to u licha oznacza.

Jak zapewne już wiesz, git init inicjuje repozytorium Git w bieżącym folderze. Jednak zwykle jest to tylko jeden z wielu powtarzających się kroków związanych z procesem podłączania nowego lub istniejącego projektu do Git. Na przykład w ramach typowego przepływu pracy możesz:

  1. zainicjuj lokalne repozytorium, uruchamiając git init
  2. utwórz zdalne repozytorium, na przykład na GitHub lub Bitbucket — zazwyczaj opuszczając wiersz poleceń i uruchamiając przeglądarkę internetową
  3. dodaj pilota
  4. Stwórz .gitignore filet
  5. dodaj swoje pliki projektu
  6. zatwierdź początkowy zestaw plików
  7. wypchnij do zdalnego repozytorium.

Często w grę wchodzi więcej kroków, ale będziemy się ich trzymać na potrzeby naszej aplikacji. Niemniej jednak te kroki są dość powtarzalne. Czy nie byłoby lepiej, gdybyśmy mogli to wszystko zrobić z wiersza poleceń, bez kopiowania i wklejania adresów URL Git i tym podobnych?

Więc to, co zrobi ginit, to utworzy repozytorium Git w bieżącym folderze, utworzy zdalne repozytorium — będziemy do tego używać GitHub — a następnie doda je jako zdalne. Następnie zapewni prosty interaktywny „kreator” do tworzenia .gitignore plik, dodaj zawartość folderu i prześlij go do zdalnego repozytorium. Może to nie zaoszczędzić godzin, ale usunie niektóre początkowe tarcia podczas rozpoczynania nowego projektu.

Mając to na uwadze, zacznijmy.

Zależności aplikacji

Jedno jest pewne: pod względem wyglądu konsola nigdy nie będzie miała wyrafinowanego graficznego interfejsu użytkownika. Nie oznacza to jednak, że musi to być zwykły, brzydki, monochromatyczny tekst. Możesz być zaskoczony, jak wiele możesz zrobić wizualnie, jednocześnie zachowując funkcjonalność. Przyjrzymy się kilku bibliotekom do ulepszania wyświetlania: kreda do kolorowania wyjścia i Clui aby dodać kilka dodatkowych elementów wizualnych. Tylko dla zabawy, użyjemy figleta stworzyć fantazyjny baner oparty na ASCII, a my również użyjemy jasny aby wyczyścić konsolę.

Pod względem wejścia i wyjścia, niski poziom readline Moduł Node.js może być używany do podpowiadania użytkownikowi i żądania danych wejściowych, a w prostych przypadkach jest więcej niż wystarczający. Ale zamierzamy skorzystać z pakietu innej firmy, który dodaje wyższy stopień wyrafinowania — Informujący się. Oprócz zapewniania mechanizmu zadawania pytań, implementuje również proste kontrolki wejściowe: przyciski radiowe i pola wyboru myśl, ale w konsoli.

Będziemy też używać minimista do parsowania argumentów wiersza poleceń.

Oto pełna lista pakietów, których użyjemy specjalnie do tworzenia w wierszu poleceń:

  • kreda — koloruje wyjście
  • jasny — czyści ekran terminala
  • Clui — rysuje w wierszu poleceń tabele, wskaźniki i błystki
  • figleta — tworzy grafikę ASCII z tekstu
  • informujący się — tworzy interaktywny interfejs wiersza poleceń
  • minimista — analizuje opcje argumentów
  • sklep konfiguracyjny — łatwo ładuje i zapisuje konfigurację bez konieczności zastanawiania się, gdzie i jak.

Dodatkowo będziemy również używać:

Pierwsze kroki

Chociaż zamierzamy stworzyć aplikację od podstaw, nie zapominaj, że możesz również pobrać kopię kodu z repozytorium, które towarzyszy temu artykułowi.

Utwórz nowy katalog dla projektu. Nie musisz tego nazywać ginit, oczywiście:

mkdir ginit
cd ginit

Stwórz nowy package.json file:

npm init -y

I edytuj go, aby wyglądał tak:

{ "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" ], "author": "<YOUR NAME>", "license": "ISC"
}

Teraz zainstaluj zależności:

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

Teraz utwórz index.js plik w tym samym folderze i require następujące zależności:

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

Dodawanie niektórych metod pomocniczych

Mamy zamiar stworzyć lib folder, w którym podzielimy nasz kod pomocniczy na moduły:

  • pliki.js — podstawowe zarządzanie plikami
  • zapytaj.js — interakcja z użytkownikiem w wierszu poleceń
  • github.js — zarządzanie tokenami dostępu
  • repo.js — Zarządzanie repozytorium Git.

Zacznijmy lib/files.js. Tutaj musimy:

  • pobierz bieżący katalog (aby uzyskać domyślną nazwę repozytorium)
  • sprawdź, czy katalog istnieje (aby określić, czy bieżący folder jest już repozytorium Git, szukając folderu o nazwie .git).

Brzmi to prosto, ale jest kilka rzeczy, które należy wziąć pod uwagę.

Po pierwsze, możesz ulec pokusie, aby użyć fs modułu ścieżka rzeczywistaSynchronizacja metoda, aby uzyskać bieżący katalog:

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

Zadziała to, gdy wywołujemy aplikację z tego samego katalogu (na przykład używając node index.js), ale pamiętaj, że zamierzamy udostępnić naszą aplikację konsolową globalnie. Oznacza to, że będziemy potrzebować nazwy katalogu, w którym pracujemy, a nie katalogu, w którym znajduje się aplikacja. W tym celu lepiej użyć proces.cwd:

path.basename(process.cwd());

Po drugie, preferowana metoda sprawdzania, czy plik lub katalog istnieje ciągle się zmienia. Obecnym sposobem jest użycie existsSync. To powraca true jeśli ścieżka istnieje, false Inaczej.

Na koniec warto zauważyć, że podczas pisania aplikacji wiersza poleceń korzystanie z synchronicznej wersji tego rodzaju metod jest w porządku.

Podsumowując, stwórzmy pakiet narzędziowy w lib/files.js:

const fs = require('fs');
const path = require('path'); module.exports = { getCurrentDirectoryBase: () => { return path.basename(process.cwd()); }, directoryExists: (filePath) => { return fs.existsSync(filePath); }
};

Wróć do index.js i upewnij się, że require nowy plik:

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

Mając to na miejscu, możemy rozpocząć tworzenie aplikacji.

Inicjowanie węzła CLI

Teraz zaimplementujmy fazę startową naszej aplikacji konsolowej.

Aby zademonstrować niektóre pakiety, które zainstalowaliśmy w celu zwiększenia wydajności konsoli, wyczyśćmy ekran, a następnie wyświetlmy baner:

// index.js clear(); console.log( chalk.yellow( figlet.textSync('Ginit', { horizontalLayout: 'full' }) )
);

Możesz uruchomić aplikację za pomocą node index.js. Wynik tego jest pokazany poniżej.

Baner powitalny w naszym Node CLI, stworzony przy użyciu Chalk i Figlet

Następnie przeprowadźmy proste sprawdzenie, aby upewnić się, że bieżący folder nie jest już repozytorium Git. To proste: po prostu sprawdzamy, czy istnieje .git folder przy użyciu metody narzędziowej, którą właśnie stworzyliśmy:

//index.js if (files.directoryExists('.git')) { console.log(chalk.red('Already a Git repository!')); process.exit();
}

Wskazówka: zauważ, że używamy moduł kreda aby wyświetlić wiadomość w kolorze czerwonym.

Monitowanie użytkownika o wprowadzenie danych

Następną rzeczą, którą musimy zrobić, jest utworzenie funkcji, która poprosi użytkownika o poświadczenia GitHub.

Możemy użyć Informujący się dla tego. Moduł zawiera szereg metod dla różnych typów podpowiedzi, które są z grubsza analogiczne do kontrolek formularzy HTML. Aby zebrać nazwę użytkownika i hasło użytkownika GitHub, użyjemy input i password typy odpowiednio.

Najpierw utwórz lib/inquirer.js i wstaw ten kod:

const inquirer = require('inquirer'); module.exports = { askGithubCredentials: () => { const questions = [ { name: 'username', type: 'input', message: 'Enter your GitHub username or e-mail address:', validate: function( value ) { if (value.length) { return true; } else { return 'Please enter your username or e-mail address.'; } } }, { name: 'password', type: 'password', message: 'Enter your password:', validate: function(value) { if (value.length) { return true; } else { return 'Please enter your password.'; } } } ]; return inquirer.prompt(questions); },
};

Jak widać, inquirer.prompt() zadaje użytkownikowi serię pytań, podanych w postaci tablicy jako pierwszy argument. Każde pytanie składa się z obiektu, który definiuje name pola, type (po prostu używamy input i password odpowiednio tutaj, ale później przyjrzymy się bardziej zaawansowanemu przykładowi) oraz znak zachęty (message) wystawić.

Dane wejściowe podane przez użytkownika zostaną przekazane do funkcji wywołującej jako Promise. Jeśli się powiedzie, otrzymamy prosty obiekt o dwóch właściwościach — username i password.

Możesz to wszystko przetestować, dodając następujące elementy do index.js:

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

Następnie uruchom skrypt za pomocą node index.js.

Uzyskiwanie danych wejściowych użytkownika za pomocą Inquirer

Wskazówka: po zakończeniu testowania nie zapomnij usunąć linii const inquirer = require('./lib/inquirer'); od index.js, ponieważ tak naprawdę nie będziemy go potrzebować w tym pliku.

Radzenie sobie z uwierzytelnianiem GitHub

Następnym krokiem jest utworzenie funkcji pobierającej token OAuth dla interfejsu API GitHub. Zasadniczo zamierzamy „wymienić” nazwę użytkownika i hasło na token.

Oczywiście nie chcemy, aby użytkownicy musieli wprowadzać swoje dane uwierzytelniające za każdym razem, gdy korzystają z narzędzia. Zamiast tego będziemy przechowywać token OAuth na potrzeby kolejnych żądań. To tutaj sklep konfiguracyjny nadchodzi paczka.

Przechowywanie konfiguracji

Przechowywanie konfiguracji jest zewnętrznie dość proste: możesz po prostu czytać i zapisywać do/z pliku JSON bez potrzeby korzystania z pakietu innej firmy. Jednak pakiet configstore zapewnia kilka kluczowych zalet:

  1. Określa najbardziej odpowiednią lokalizację pliku dla Ciebie, biorąc pod uwagę Twój system operacyjny i bieżącego użytkownika.
  2. Nie ma potrzeby jawnego odczytywania lub zapisywania do pliku. Po prostu modyfikujesz obiekt configstore i robisz to w tle.

Aby z niego skorzystać, po prostu utwórz instancję, przekazując jej identyfikator aplikacji. Na przykład:

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

Jeśli configstore plik nie istnieje, zwróci pusty obiekt i utworzy plik w tle. Jeśli jest już configstore plik, jego zawartość zostanie udostępniona Twojej aplikacji. Możesz teraz użyć conf jako prosty obiekt, pobierając lub ustawiając właściwości zgodnie z wymaganiami. Jak wspomniano powyżej, nie musisz się martwić o późniejsze zapisanie go. Zadbamy o to za Ciebie.

Wskazówka: w systemie macOS plik znajdziesz w /Users/[YOUR-USERNME]/.config/configstore/ginit.json. W Linuksie jest w /home/[YOUR-USERNME]/.config/configstore/ginit.json.

Komunikacja z GitHub API

Stwórzmy bibliotekę do obsługi tokena GitHub. Utwórz plik lib/github.js i umieść w nim następujący kod:

const CLI = require('clui');
const Configstore = require('configstore');
const Octokit = require('@octokit/rest');
const Spinner = CLI.Spinner;
const { createBasicAuth } = require("@octokit/auth-basic"); const inquirer = require('./inquirer');
const pkg = require('../package.json'); const conf = new Configstore(pkg.name);

Dodajmy teraz funkcję, która sprawdza, czy mamy już token dostępu. Dodamy również funkcję, która pozwoli innym bibliotekom na dostęp octokit(GitHub) funkcje:

let octokit; module.exports = { getInstance: () => { return octokit; }, getStoredGithubToken: () => { return conf.get('github.token'); },
};

Jeśli conf obiekt istnieje i ma github.token oznacza to, że token jest już w magazynie. W takim przypadku zwracamy wartość tokena z powrotem do funkcji wywołującej. Dojdziemy do tego później.

Jeśli żaden token nie zostanie wykryty, musimy go pobrać. Oczywiście uzyskanie tokena OAuth wiąże się z żądaniem sieciowym, co oznacza krótkie oczekiwanie na użytkownika. Daje nam to możliwość przyjrzenia się Clui pakiet, który zawiera kilka ulepszeń dla aplikacji konsolowych, między innymi animowany spinner.

Tworzenie spinnera jest łatwe:

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

Gdy skończysz, po prostu zatrzymaj go, a zniknie z ekranu:

status.stop();

Wskazówka: możesz również ustawić podpis dynamicznie, używając update metoda. Może to być przydatne, jeśli masz jakiś wskaźnik postępu — na przykład wyświetlając procent ukończenia.

Oto kod do uwierzytelnienia za pomocą GitHub:

module.exports = { getInstance: () => { ... }, getStoredGithubToken: () => { ... }, getPersonalAccesToken: async () => { const credentials = await inquirer.askGithubCredentials(); const status = new Spinner('Authenticating you, please wait...'); status.start(); const auth = createBasicAuth({ username: credentials.username, password: credentials.password, async on2Fa() { // TBD }, 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 was not found in the response"); } } finally { status.stop(); } },
};

Przejdźmy przez to:

  1. Pytamy użytkownika o podanie swoich danych uwierzytelniających za pomocą askGithubCredentials wcześniej zdefiniowaną metodę.
  2. Używamy utwórzBasicAuth metoda tworzenia auth funkcję, którą wywołamy w następnym kroku. Do tej metody przekazujemy nazwę użytkownika i hasło użytkownika, a także obiekt tokena o dwóch właściwościach:
    • note — notatka przypominająca nam, do czego służy token OAuth.
    • scopes — lista zakresów, w których znajduje się ta autoryzacja. Możesz przeczytać więcej o dostępnych zakresach w dokumentacji GitHub.
  3. Wtedy my await wynik wywołania auth funkcja wewnątrz a try blok.
  4. Jeśli uwierzytelnienie się powiedzie, a w odpowiedzi znajduje się token, ustawiamy go w configstore na następny raz i zwróć token.
  5. Jeśli brakuje tokena lub uwierzytelnianie nie powiedzie się z jakiegokolwiek powodu, błąd pojawi się na stosie, abyśmy mogli go złapać index.js. Zaimplementujemy tę funkcję później.

Wszelkie tokeny dostępu, które utworzysz, zarówno ręcznie, jak i za pośrednictwem interfejsu API, tak jak tutaj robimy, będziesz mógł zobacz je tutaj. W trakcie rozwoju może się okazać, że trzeba usunąć token dostępu ginit — identyfikowany przez note parametr podany powyżej — aby można było go ponownie wygenerować.

Jeśli śledzisz i chciałbyś wypróbować to, co mamy do tej pory, możesz zaktualizować index.js w sposób następujący:

const github = require('./lib/github'); ... const run = async () => { let token = github.getStoredGithubToken(); if(!token) { token = await github.getPersonalAccesToken(); } console.log(token);
};

Przy pierwszym uruchomieniu powinieneś zostać poproszony o podanie nazwy użytkownika i hasła GitHub. Aplikacja powinna następnie utworzyć osobisty token dostępu na GitHub i zapisać token w configstore, przed zalogowaniem do konsoli. Za każdym razem, gdy uruchomisz aplikację po tym, aplikacja pobierze token prosto z configstore i zapisz to na ekranie.

Radzenie sobie z uwierzytelnianiem dwuskładnikowym

Mam nadzieję, że zauważyłeś on2Fa metody w powyższym kodzie. Zostanie to wywołane, gdy użytkownik ma włączone uwierzytelnianie dwuskładnikowe na swoim koncie GitHub. Wypełnijmy to teraz:

// inquirer.js const inquirer = require('inquirer'); module.exports = { askGithubCredentials: () => { ... }, getTwoFactorAuthenticationCode: () => { return inquirer.prompt({ name: 'twoFactorAuthenticationCode', type: 'input', message: 'Enter your two-factor authentication code:', validate: function(value) { if (value.length) { return true; } else { return 'Please enter your two-factor authentication code.'; } } }); },
};

Możemy nazwać getTwoFactorAuthenticationCode metoda z wewnątrz on2Fa metoda, na przykład:

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

A teraz nasza aplikacja może obsługiwać konta GitHub z włączonym uwierzytelnianiem dwuskładnikowym.

Tworzenie repozytorium

Gdy mamy już token OAuth, możemy go użyć do stworzenia zdalnego repozytorium za pomocą GitHub.

Ponownie możemy użyć Inquirera, aby zadać serię pytań. Potrzebujemy nazwy repozytorium, poprosimy o opcjonalny opis, a także musimy wiedzieć, czy ma być publiczne czy prywatne.

Użyjemy minimista aby pobrać domyślne dla nazwy i opisu z opcjonalnych argumentów wiersza poleceń. Na przykład:

ginit my-repo "just a test repository"

To ustawi domyślną nazwę na my-repo i opis do just a test repository.

Poniższy wiersz umieści argumenty w tablicy indeksowanej podkreśleniem:

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

Wskazówka: to tylko naprawdę rysuje powierzchnię opakowania minimist. Możesz go również użyć do interpretacji flag, przełączników i par nazwa/wartość. Zapoznaj się z dokumentacją, aby uzyskać więcej informacji.

Napiszemy kod, który przeanalizuje argumenty wiersza poleceń i zada serię pytań. Najpierw zaktualizuj lib/inquirer.js w sposób następujący:

const inquirer = require('inquirer');
const files = require('./files'); module.exports = { askGithubCredentials: () => { ... }, getTwoFactorAuthenticationCode: () => { ... }, askRepoDetails: () => { const argv = require('minimist')(process.argv.slice(2)); const questions = [ { type: 'input', name: 'name', message: 'Enter a name for the repository:', default: argv._[0] || files.getCurrentDirectoryBase(), validate: function( value ) { if (value.length) { return true; } else { return 'Please enter a name for the repository.'; } } }, { type: 'input', name: 'description', default: argv._[1] || null, message: 'Optionally enter a description of the repository:' }, { type: 'list', name: 'visibility', message: 'Public or private:', choices: [ 'public', 'private' ], default: 'public' } ]; return inquirer.prompt(questions); },
};

Następnie utwórz plik lib/repo.js i dodaj ten kod:

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('Creating remote repository...'); status.start(); try { const response = await github.repos.createForAuthenticatedUser(data); return response.data.ssh_url; } finally { status.stop(); } },
};

Gdy już mamy te informacje, możemy po prostu użyć pakietu GitHub, aby utwórz repozytorium, co da nam adres URL do nowo utworzonego repozytorium. Następnie możemy skonfigurować go jako pilota w naszym lokalnym repozytorium Git. Najpierw jednak interaktywnie stwórzmy .gitignore plik.

Tworzenie pliku .gitignore

W następnym kroku utworzymy prosty „kreator” wiersza poleceń, aby wygenerować .gitignore plik. Jeśli użytkownik uruchamia naszą aplikację w istniejącym katalogu projektu, pokażmy mu listę plików i katalogów znajdujących się już w bieżącym katalogu roboczym i pozwól mu wybrać, które zignorować.

Pakiet Inquirer zapewnia checkbox typ wejścia właśnie do tego.

Pola wyboru Pytającego w akcji

Pierwszą rzeczą, którą musimy zrobić, to przeskanować bieżący katalog, ignorując .git folder i wszelkie istniejące .gitignore plik (robimy to za pomocą lodash's bez metoda):

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

Jeśli nie ma nic do dodania, nie ma sensu kontynuować, więc po prostu touch obecny .gitignore złożyć i wykupić funkcję:

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

Na koniec wykorzystajmy pole wyboru „widget” Inquirera, aby wyświetlić listę plików. Wstaw następujący kod w lib/inquirer.js:

askIgnoreFiles: (filelist) => { const questions = [ { type: 'checkbox', name: 'ignore', message: 'Select the files and/or folders you wish to ignore:', choices: filelist, default: ['node_modules', 'bower_components'] } ]; return inquirer.prompt(questions);
},

Zauważ, że możemy również podać listę wartości domyślnych. W tym przypadku dokonujemy wstępnej selekcji node_modules i bower_components, czy istnieją.

Po wprowadzeniu kodu Inquirer możemy teraz skonstruować createGitignore() funkcjonować. Wstaw ten kod w lib/repo.js:

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'); }
},

Po „przesłaniu” generujemy a .gitignore łącząc wybraną listę plików oddzielonych znakiem nowej linii. Nasza funkcja teraz w dużej mierze gwarantuje, że mamy .gitignore , dzięki czemu możemy przystąpić do inicjalizacji repozytorium Git.

Interakcja z Git z poziomu aplikacji

Istnieje wiele sposobów interakcji z Git, ale być może najprostszym jest użycie prosty-git pakiet. Zapewnia to zestaw metod, które można łączyć w łańcuchy, które za kulisami uruchamiają plik wykonywalny Git.

Oto powtarzające się zadania, których użyjemy do zautomatyzowania:

  1. biegać git init
  2. Dodaj .gitignore filet
  3. dodaj pozostałą zawartość katalogu roboczego
  4. wykonać wstępne zatwierdzenie
  5. dodaj nowo utworzone zdalne repozytorium
  6. wypchnij katalog roboczy do pilota.

Wstaw następujący kod w lib/repo.js:

setupRepo: async (url) => { const status = new Spinner('Initializing local repository and pushing to remote...'); status.start(); try { git.init() .then(git.add('.gitignore')) .then(git.add('./*')) .then(git.commit('Initial commit')) .then(git.addRemote('origin', url)) .then(git.push('origin', 'master')); } finally { status.stop(); }
},

Wszystko razem

Najpierw ustawmy funkcję pomocniczą w lib/github.js za założenie oauth poświadczenie:

githubAuth: (token) => { octokit = new Octokit({ auth: token });
},

Następnie tworzymy funkcję w index.js do obsługi logiki pozyskiwania tokena. Umieść ten kod przed run() funkcjonować:

const getGithubToken = async () => { // Fetch token from config store let token = github.getStoredGithubToken(); if(token) { return token; } // No token found, use credentials to access GitHub account token = await github.getPersonalAccesToken(); return token;
};

Na koniec aktualizujemy run() funkcji, pisząc kod, który będzie obsługiwał główną logikę aplikacji:

const repo = require('./lib/repo'); ... const run = async () => { try { // Retrieve & Set Authentication Token const token = await getGithubToken(); github.githubAuth(token); // Create remote repository const url = await repo.createRemoteRepo(); // Create .gitignore file await repo.createGitignore(); // Set up local repository and push to remote await repo.setupRepo(url); console.log(chalk.green('All done!')); } catch(err) { if (err) { switch (err.status) { case 401: console.log(chalk.red('Couldn't log you in. Please provide correct credentials/token.')); break; case 422: console.log(chalk.red('There is already a remote repository or token with the same name')); break; default: console.log(chalk.red(err)); } } }
};

Jak widać, upewniamy się, że użytkownik jest uwierzytelniony przed wywołaniem wszystkich naszych innych funkcji (createRemoteRepo(), createGitignore(), setupRepo()) sekwencyjnie. Kod radzi sobie również z ewentualnymi błędami i oferuje użytkownikowi odpowiednią informację zwrotną.

Możesz sprawdzić ukończone indeks.js plik w naszym repozytorium GitHub.

W tym momencie powinieneś mieć działającą aplikację. Spróbuj i upewnij się, że działa zgodnie z oczekiwaniami.

Udostępnianie polecenia ginit na całym świecie

Jedyne, co pozostało do zrobienia, to udostępnienie naszego polecenia globalnie. Aby to zrobić, musimy dodać szulernia linia do góry index.js:

#!/usr/bin/env node

Następnie musimy dodać bin własność do naszego package.json plik. To mapuje nazwę polecenia (ginit) do nazwy pliku do wykonania (względem package.json):

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

Następnie zainstaluj moduł globalnie, a otrzymasz działające polecenie powłoki:

npm install -g

Wskazówka: zadziała to również w systemie Windows, ponieważ npm zainstaluje opakowanie cmd obok twojego skryptu.

Jeśli chcesz potwierdzić, że instalacja zadziałała, możesz wyświetlić listę swoich globalnie zainstalowanych modułów Node, używając tego:

npm ls -g --depth=0

Idąc dalej

Mamy całkiem fajną, aczkolwiek prostą aplikację wiersza poleceń do inicjowania repozytoriów Git. Ale możesz zrobić o wiele więcej, aby jeszcze bardziej to ulepszyć.

Jeśli jesteś użytkownikiem Bitbucket, możesz dostosować program do korzystania z interfejsu Bitbucket API do tworzenia repozytorium. Jest Dostępne opakowanie Node.js API aby pomóc Ci zacząć. Możesz dodać dodatkową opcję wiersza poleceń lub monit, aby zapytać użytkownika, czy chce korzystać z GitHub lub Bitbucket (do tego idealnie nadaje się Inquirer), czy po prostu zastąpić kod specyficzny dla GitHub alternatywą Bitbucket.

Możesz również zapewnić możliwość określenia własnego zestawu ustawień domyślnych dla .gitgnore pliku, zamiast zakodowanej na sztywno listy. Pakiet preferencji może być tutaj odpowiedni lub możesz dostarczyć zestaw „szablonów” — być może podpowiadając użytkownikowi typ projektu. Możesz również przyjrzeć się zintegrowaniu go z .gitignore.io narzędzie wiersza polecenia/API.

Poza tym możesz również dodać dodatkową walidację, zapewnić możliwość pominięcia niektórych sekcji i nie tylko.

Źródło: https://www.sitepoint.com/javascript-command-line-interface-cli-node-js/?utm_source=rss

spot_img

Najnowsza inteligencja

spot_img