Fermer

octobre 16, 2019

Construire une interface de ligne de commande JavaScript avec Node.js –


Bien que Node.js soit destiné aux applications Web «traditionnelles», ses utilisations potentielles sont beaucoup plus vastes. Microservices, API REST, outils, utilisation de l'Internet des objets et même des applications de bureau: tout est dans le dos.

Un autre domaine dans lequel Node.js est vraiment utile est la construction d'applications en ligne de commande – et c'est ce que nous allons faire. faire dans cet article. Nous allons commencer par examiner un certain nombre de packages tiers conçus pour faciliter l'utilisation de la ligne de commande, puis créer un exemple réel à partir de rien.

Ce que nous allons construire est un outil d'initialisation. un référentiel Git. Bien sûr, il va lancer git init sous le capot, mais il fera plus que cela. Il créera également un référentiel distant sur GitHub directement à partir de la ligne de commande, permettant à l'utilisateur de créer de manière interactive un fichier .gitignore et enfin d'effectuer une validation et une activation initiales.

Comme toujours, le code qui l'accompagne Ce tutoriel est disponible sur notre GitHub repo .

 Construire un nœud CLI

Avant de plonger et de commencer à construire, il est intéressant de savoir pourquoi nous pourrions choisir Node.js pour le construire. une application en ligne de commande.

L’avantage le plus évident est que, si vous lisez ceci, vous êtes probablement déjà au courant – et, en fait, avec JavaScript.

Un autre avantage clé, car nous allons Nous constatons au fur et à mesure que l'écosystème fort de Node.js signifie que parmi les centaines de milliers de packages disponibles à des fins diverses, il en existe un certain nombre qui sont spécifiquement conçus pour vous aider à créer de puissants outils de ligne de commande.

Enfin, nous pouvons utiliser npm pour gérer les dépendances éventuelles, Plutôt que d'avoir à vous soucier des gestionnaires de packages spécifiques à un système d'exploitation, tels que Aptitude, Yum ou Homebrew.

Conseil: ce n'est pas forcément vrai, votre outil de ligne de commande peut avoir d'autres dépendances externes.

Ce que nous allons construire: ginit

 Ginit, notre interface de ligne de commande de nœud en action

Pour ce didacticiel, nous allons créer un utilitaire de ligne de commande que j'appelle . . C'est git init mais sous stéroïdes.

Vous vous demandez probablement ce que cela signifie en réalité.

Comme vous le savez sans doute déjà, git init initialise un référentiel Git. dans le dossier en cours. Cependant, il ne s’agit en général que d’une des nombreuses étapes répétitives nécessaires pour connecter un projet nouveau ou existant à Git. Par exemple, dans le cadre d'un flux de travail typique, vous pouvez:

  1. initialiser le référentiel local en exécutant git init
  2. pour créer un référentiel distant, par exemple sur GitHub ou Bitbucket – généralement en laissant la ligne de commande Ouvrir un navigateur Web
  3. Ajouter la télécommande
  4. Créer un fichier .gitignore
  5. Ajouter vos fichiers de projet
  6. Valider le jeu de fichiers initial
  7. dans le référentiel distant. .

Il y a souvent plusieurs étapes à suivre, mais nous nous en tenons à celles-ci pour les besoins de notre application. Néanmoins, ces étapes sont assez répétitives. Ne serait-il pas préférable de faire tout cela à partir de la ligne de commande, sans copier-coller des URL Git, etc.?

Ce que ginit va faire, c'est créer un référentiel Git dans le dossier en cours, créer une télécommande. référentiel – nous utiliserons GitHub pour cela – et l'ajouterons comme télécommande. Ensuite, il fournira un «assistant» interactif simple pour créer un fichier .gitignore ajoutez le contenu du dossier et transférez-le dans le référentiel distant. Cela ne vous épargnera peut-être pas des heures, mais éliminera une partie des frictions lors du démarrage d'un nouveau projet.

Dans cet esprit, commençons.

Les dépendances de l'application

Une chose est sûre: en termes d'apparence, la console n'aura jamais la sophistication d'une interface utilisateur graphique. Néanmoins, cela ne veut pas dire que le texte doit être clair, monochrome et monochrome. Vous pourriez être surpris par tout ce que vous pouvez faire visuellement, tout en le maintenant fonctionnel. Nous allons examiner quelques bibliothèques pour améliorer l'affichage: la craie pour coloriser la sortie et clui pour ajouter des éléments visuels supplémentaires. Juste pour le plaisir, nous allons utiliser figlet pour créer une bannière basée sur ASCII et utiliser également clear pour nettoyer la console.

En termes d'entrée et de sortie , le module de bas niveau Readline Node.js peut être utilisé pour inviter l'utilisateur à demander une entrée et, dans les cas simples, il est largement suffisant. Mais nous allons tirer parti d’un package tiers qui ajoute un degré de sophistication accru – Inquirer . En plus de fournir un mécanisme pour poser des questions, il implémente également des contrôles d'entrée simples: pensez aux boutons radio et aux cases à cocher, mais dans la console.

Nous utiliserons également de minimiste pour analyser les arguments de ligne de commande. .

Voici une liste complète des packages que nous utiliserons spécifiquement pour le développement sur la ligne de commande:

  • chalk – colorise la sortie
  • clear – efface l'écran du terminal [19659018] clui – dessine des tableaux, des jauges et des filateurs en ligne de commande
  • figlet – crée un art ASCII à partir du texte
  • enquirer – crée un ordre interactif interface utilisateur en ligne
  • minimiste – analyse les options d’argument
  • configstore – charge et enregistre facilement la configuration sans que vous ayez à vous demander où et comment.

En outre, nous ' Nous utiliserons également les éléments suivants:

  • @ octokit / rest un client d'API GEST REST pour Node.js
  • lodash – une bibliothèque d'utilitaires JavaScript
  • simple-git – un outil permettant d'exécuter des commandes Git dans une application Node.js [19659018] touch – un outil pour mettre en oeuvre la commande tactile Unix

Mise en route

Bien que nous allons créer l'application à partir de rien, n'oubliez pas que vous pouvez également en obtenir une copie. du code du référentiel qui accompagne cet article .

Créez un nouveau répertoire pour le projet. Vous n’êtes pas obligé de l’appeler ginit bien sûr:

 mkdir ginit
cd ginit

Créez un nouveau fichier package.json :

 npm init -y

Et éditez-le pour ressembler à ceci:

 {
  "nom": "ginit",
  "version": "1.0.0",
  "description": "'git init' sur les stéroïdes",
  "main": "index.js",
  "scripts": {
    "test": "echo " Erreur: aucun test spécifié  "&& exit 1"
  },
  "keywords": [
    "Git",
    "CLI"
  ],
  "auteur": "",
  "licence": "ISC"
}

Maintenant, installez les dépendances:

 npm installez craie clear clui figlet enquêteur configstore minimiste @ octokit / rest lodash simple-git touch

Créez à présent un fichier index.js dans le même dossier et nécessite les dépendances suivantes:

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

Ajout de méthodes d'aide

Nous allons créer un dossier lib dans lequel nous scindons le code d'assistance en modules:

  • files.js – Gestion de base des fichiers [19659018] inquirer.js – Interaction utilisateur en ligne de commande
  • github.js – Gestion des jetons d'accès
  • repo.js – Gestion des référentiels Git.

Commençons par lib / files.js . Ici, nous devons:

  • obtenir le répertoire actuel (pour obtenir un nom de référentiel par défaut)
  • vérifier si un répertoire existe (pour déterminer si le dossier actuel est déjà un référentiel Git en recherchant un dossier nommé .git ).

Cela semble simple, mais il y a quelques pièges à prendre en considération.

Premièrement, vous pourriez être tenté d'utiliser le module fs realpathSync Méthode pour obtenir le répertoire en cours:

 chemin.nom_basé (chemin.dirname (fs.realpathSync (__ nomfichier)));

Cela fonctionnera lorsque nous appellerons l’application depuis le même répertoire (par exemple, en utilisant node index.js ), mais gardez à l’esprit que nous allons rendre notre application console disponible dans le monde entier. Cela signifie que nous voudrons le nom du répertoire dans lequel nous travaillons, pas celui où se trouve l’application. Pour cela, il est préférable d’utiliser process.cwd :

 path.basename (process.cwd ());

Deuxièmement, la méthode privilégiée pour vérifier l'existence d'un fichier ou d'un répertoire ne cesse de changer . La méthode actuelle consiste à utiliser existSync . Ceci retourne true si le chemin existe, false sinon

Enfin, il convient de noter que lorsque vous écrivez une application en ligne de commande, utilisez la version synchrone de ces sortes.

En résumé, créons un paquet d’utilitaires dans lib / files.js :

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

module.exports = {
  getCurrentDirectoryBase: () => {
    return path.basename (process.cwd ());
  },

  directoryExists: (chemin_fichier) => {
    return fs.existsSync (filePath);
  }
};

Retournez à index.js et assurez-vous que avez besoin de du nouveau fichier:

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

Ceci mis en place, nous pouvons commencer à développer l’application.

Initialisation de la CLI du nœud

Maintenant, implémentons la phase de démarrage de notre application console.

Afin de démontrer certains des paquetages que nous avons installé pour améliorer la sortie de la console, effacons l'écran, puis affichons une bannière:

 // index.js

clair();

console.log (
  craie. jaune (
    figlet.textSync ('Ginit', {horizontalLayout: 'full'})
  )
)

Vous pouvez exécuter l'application à l'aide du noeud index.js . La sortie de ceci est montrée ci-dessous.

 La ​​bannière de bienvenue sur notre Node CLI, créée à l'aide de Chalk and Figlet

Ensuite, vérifions simplement que le dossier actuel ne l'est pas. déjà un référentiel Git. C’est simple: nous vérifions simplement l’existence d’un dossier .git à l’aide de la méthode utilitaire que nous venons de créer:

 // index.js

if (files.directoryExists ('.git')) {
  console.log (chalk.red ('Déjà un référentiel Git!'));
  process.exit ();
}

Conseil: notez que nous utilisons le module de craie pour afficher un message de couleur rouge.

Inviter l'utilisateur à entrer

Nous devons ensuite créer, c'est créer une fonction qui invitera l'utilisateur à entrer ses informations d'identification GitHub.

Nous pouvons utiliser Inquirer pour cela. Le module comprend un certain nombre de méthodes pour différents types d'invites, qui sont à peu près analogues aux contrôles de formulaire HTML. Afin de collecter le nom d'utilisateur et le mot de passe GitHub de l'utilisateur, nous allons utiliser les types d'entrée et respectivement.

Créez d'abord lib / inquirer.js et insérer ce code:

 const enquirer = require ('enquirer');

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

module.exports = {
  askGithubCredentials: () => {
    questions constantes = [
      {
        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.';
          }
        }
      }
    ];
    retour enquêteur.prompt (questions);
  },
};

Comme vous pouvez le constater, inquirer.prompt () demande à l'utilisateur une série de questions, fournies sous la forme d'un tableau comme premier argument. Chaque question est composée d'un objet définissant le nom du champ, de type (nous utilisons simplement les entrées et . ] respectivement ici, mais nous verrons plus loin un exemple plus avancé), et l'invite (message ) à afficher.

L'entrée fournie par l'utilisateur sera transmise à la fonction appelante en tant que Promesse . En cas de succès, nous nous retrouverons avec un objet simple avec deux propriétés; nom d'utilisateur et mot de passe .

Vous pouvez tester tout cela en ajoutant ce qui suit à index.js :

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

const run = async () => {
  const credentials = wait enquirer.askGithubCredentials ();
  console.log (informations d'identification);
};

courir();

Ensuite, exécutez le script en utilisant node index.js .

 Obtention de la saisie de l'utilisateur avec Inquirer

Conseil: Lorsque vous avez terminé, testez, ' t oubliez de supprimer la ligne const enquirer = require ('./ lib / enquirer'); de index.js car nous n’en aurons pas réellement besoin dans ce fichier. [19659097] Traitement de l'authentification GitHub

L'étape suivante consiste à créer une fonction permettant de récupérer un jeton OAuth pour l'API GitHub. Nous allons essentiellement "échanger" le nom d'utilisateur et le mot de passe d'un jeton.

Bien sûr, nous ne voulons pas que les utilisateurs soient obligés de saisir leurs informations d'identification chaque fois qu'ils utilisent l'outil. Au lieu de cela, nous allons stocker le jeton OAuth pour les requêtes suivantes. C’est là que le paquet configstore entre en jeu.

Stockage de la configuration

Le stockage de la configuration est très simple: vous pouvez simplement lire et écrire dans un fichier JSON sans avoir besoin de tiers. paquet. Cependant, le paquet configstore offre quelques avantages clés:

  1. Il détermine l'emplacement le plus approprié pour le fichier, en tenant compte de votre système d'exploitation et de l'utilisateur actuel.
  2. Il n'est pas nécessaire de lire ou d'écrire explicitement dans le fichier. fichier. Vous modifiez simplement un objet configstore qui s’en occupe à l’arrière-plan.

Pour l’utiliser, créez simplement une instance en lui transmettant un identificateur d’application. Par exemple:

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

Si le fichier du configstore n’existe pas, il renverra un objet vide et créera le fichier en arrière-plan. S'il existe déjà un fichier configstore le contenu sera décodé en JSON et mis à la disposition de votre application. Vous pouvez maintenant utiliser conf comme objet simple, en obtenant ou en définissant des propriétés selon vos besoins. Comme mentionné ci-dessus, vous n'avez pas à vous soucier de le sauvegarder après.

Astuce: sur macOS, vous trouverez le fichier dans / Users / [YOUR-USERNME] /. Config / configstore / ginit.json sous Linux. c'est dans / home / [YOUR-USERNME] /. config / configstore / ginit.json

Communication avec l'API GitHub

Créons une bibliothèque pour gérer le jeton GitHub. Créez le fichier lib / github.js et placez-y le code suivant:

 const CLI = require ('clui');
const Configstore = require ('configstore');
const Octokit = require ('@ octokit / rest');
const Spinner = CLI.Spinner;

const enquirer = require ('./ enquirer');
const pkg = require ('../ package.json');

const conf = new Configstore (pkg.name);

Ajoutons maintenant la fonction qui vérifie si nous avons déjà un jeton d’accès. Nous allons également ajouter une fonction qui permet aux autres bibliothèques d’accéder aux fonctions de octokit (GitHub):

 module.exports = {
  getInstance: () => {
    renvoyer un octokit;
  },

  getStoredGithubToken: () => {
    return conf.get ('github.token');
  },
};

Si un objet conf existe et qu’il a la propriété github.token cela signifie qu’un jeton est déjà stocké. Dans ce cas, nous renvoyons la valeur du jeton à la fonction appelante. Nous y reviendrons plus tard.

Si aucun jeton n’est détecté, nous devons en récupérer un. Bien sûr, obtenir un jeton OAuth implique une requête réseau, ce qui signifie une courte attente pour l'utilisateur. Cela nous donne l’occasion d’examiner le package clui qui apporte quelques améliorations aux applications sur console, notamment une visionneuse animée.

Il est facile de créer une visionneuse:

 const status = new Spinner ('Je ​​vous authentifie, veuillez patienter ...');
status.start ();

Une fois que vous avez terminé, arrêtez-le simplement et il disparaîtra de l’écran:

 status.stop ();

Conseil: vous pouvez également définir la légende de manière dynamique à l'aide de la méthode update . Cela peut être utile si vous avez une indication de progrès, par exemple en affichant le pourcentage terminé.

Voici le code pour s’authentifier avec GitHub:

 ...

laissez octokit;

module.exports = {

  ...

  setGithubCredentials: async () => {
    const credentials = wait enquirer.askGithubCredentials ();
    octokit = nouvel octokit ({
      auth: {
        nom d'utilisateur: credentials.username,
        mot de passe: credentials.password,
      }
    });
   },

  registerNewToken: async () => {
    const status = new Spinner ('Je vous authentifie, veuillez patienter ...');
    status.start ();

    essayer {
      réponse const = wait octokit.oauthAuthorizations.createAuthorization ({
        champs d'application: ['user', 'public_repo', 'repo', 'repo:status'],
        note: 'ginit, l'outil en ligne de commande pour initaliser les dépôts Git'
      });
      const token = response.data.token;
      si (jeton) {
        conf.set ('github.token', jeton);
        rendre le jeton;
      } autre {
        jeter une nouvelle erreur ("Jeton manquant", "Le jeton GitHub n'a pas été trouvé dans la réponse");
      }
    } catch (err) {
      jeter err;
    } enfin {
      status.stop ();
    }
  },
};

Passons à autre chose:

  1. nous déclarons une variable octokit dans la partie supérieure du module
  2. . Nous invitons l'utilisateur à indiquer ses informations d'identification à l'aide de la méthode askGithubCredentials définie précédemment.
  3. nous passons une option auth au constructeur Octokit pour permettre à les requêtes authentifiées
  4. d'assigner le résultat à la variable octokit pour qu'il soit disponible
  5. tout au long du module, nous essayons d'enregistrer un nouveau jeton d'accès pour notre application
  6. si nous parvenons à obtenir un jeton d'accès, nous le plaçons dans le configstore .
  7. nous retournons ensuite le jeton.

Tous les jetons d'accès que vous créez, que ce soit manuellement ou via l'API, comme vous le faites ici, vous pourrez les voir ici . Au cours du développement, vous devrez peut-être supprimer le jeton d'accès de ginit – identifiable par le paramètre note fourni ci-dessus – pour pouvoir le générer à nouveau.

Conseil: si vous Si l'authentification à deux facteurs est activée sur votre compte GitHub, le processus est légèrement plus compliqué. Vous devez demander le code de confirmation – par exemple, un code envoyé par SMS – puis le fournir à l’aide de l’en-tête X-GitHub-OTP . Voir la documentation pour plus d'informations.

Si vous suivez et souhaitez essayer ce que nous avons jusqu'à présent, vous pouvez mettre à jour index.js comme suit:

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

...

const run = async () => {
  let token = github.getStoredGithubToken ();
  si (! jeton) {
    attendez github.setGithubCredentials ();
    jeton = attendez github.registerNewToken ();
  }
  console.log (jeton);
}:

Veuillez noter que vous risquez d'obtenir une erreur Promise en cas d'incident, tel que la saisie d'un mot de passe incorrect. Je vous montrerai plus tard comment gérer ces erreurs.

Création d'un référentiel

Une fois que nous avons un jeton OAuth, nous pouvons l'utiliser pour créer un référentiel distant avec GitHub.

pouvez utiliser Inquirer pour poser une série de questions. Nous avons besoin d’un nom pour le repo, nous demanderons une description facultative, ainsi que savoir si elle doit être publique ou privée.

Nous utiliserons le minimiste pour saisir les valeurs par défaut des nom et description à partir des arguments de ligne de commande facultatifs. Par exemple:

 ginit my-repo "juste un référentiel de test"

Cela donnera le nom par défaut à my-repo et la description à juste un référentiel test .

La ligne suivante placera les arguments dans un tableau indexé par un trait de soulignement:

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

Astuce: cela ne fait qu'effleurer la surface du paquetage minimiste. Vous pouvez également l'utiliser pour interpréter des indicateurs, des commutateurs et des paires nom / valeur. Consultez la documentation pour plus d'informations.

Nous allons écrire du code pour analyser les arguments de la ligne de commande et poser une série de questions. Commencez par mettre à jour lib / inquirer.js en insérant le code suivant juste après la fonction askGithubCredentials :

 askRepoDetails: () => {
  const argv = require ('minimist') (process.argv.slice (2));

  questions const = [
    {
      type: 'input',
      name: 'name',
      message: 'Enter a name for the repository:',
      default: argv._[0] || files.getCurrentDirectoryBase (),
      valider: fonction (valeur) {
        si (valeur.longueur) {
          retourne vrai;
        } autre {
          return 'Veuillez saisir un nom pour le référentiel.';
        }
      }
    },
    {
      type: 'entrée',
      nom: 'description',
      défaut: argv ._ [1] || nul,
      message: 'Entrez éventuellement une description du référentiel:'
    },
    {
      type: 'liste',
      nom: 'visibilité',
      message: 'Public ou privé:',
      choix: [ 'public', 'private' ],
      défaut: 'public'
    }
  ];
  retour enquêteur.prompt (questions);
},

Créez ensuite le fichier lib / repo.js et ajoutez le code suivant:

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

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

module.exports = {
  createRemoteRepo: async () => {
    const github = gh.getInstance ();
    const réponses = wait enquirer.askRepoDetails ();

    const data = {
      nom: réponses.nom,
      description: réponses.description,
      private: (answers.visibility === 'private')
    };

    const status = new Spinner ('Création d'un référentiel distant ...');
    status.start ();

    essayer {
      réponse const = wait github.repos.createForAuthenticatedUser (data);
      return response.data.ssh_url;
    } catch (err) {
      jeter err;
    } enfin {
      status.stop ();
    }
  },
};

Une fois que nous avons ces informations, nous pouvons simplement utiliser le paquet GitHub pour créer un repo ce qui nous donnera une URL pour le dépôt nouvellement créé. Nous pouvons ensuite configurer cela en tant que télécommande dans notre référentiel Git local. Tout d’abord, cependant, créons de manière interactive un fichier .gitignore .

Création d’un fichier .gitignore

Pour la prochaine étape, nous allons créer un simple “assistant” en ligne de commande pour générer un .gitignore fichier. Si l'utilisateur exécute notre application dans un répertoire de projet existant, montrons-leur une liste des fichiers et des répertoires déjà présents dans le répertoire de travail en cours et laissez-les sélectionner ceux à ignorer.

Le paquet Inquirer fournit un . case à cocher comme type d'entrée.

 Les cases à cocher de l'enquêteur en action

La première chose à faire est de parcourir le répertoire actuel, en ignorant le dossier .git . et tout fichier .gitignore existant (nous le faisons en utilisant la méthode [lodash sans ):

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

S'il n'y a rien à ajouter, cela ne sert à rien de continuer, alors touchons simplement le fichier .gitignore actuel et renonçons à la fonction:

 if (filelist. longueur) {
  ...
} autre {
  toucher ('. gitignore');
}

Enfin, utilisons le "widget" de la case à cocher de Inquirer pour répertorier les fichiers. Insérez le code suivant dans lib / inquirer.js :

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

Notez que nous pouvons également fournir une liste des valeurs par défaut. Dans ce cas, nous présélectionnons node_modules et bower_components s'ils existent,

Avec le code Inquirer en place, nous pouvons maintenant construire le généralement créé par createGitignore ( ) fonction. Insérer ce code dans lib / repo.js :

 createGitignore: async () => {
  const filelist = _.without (fs.readdirSync ('.'), '.git', '.gitignore');

  if (filelist.length) {
    const réponses = wait enquirer.askIgnoreFiles (filelist);

    if (answers.ignore.length) {
      fs.writeFileSync ('.gitignore', answers.ignore.join (' n'));
    } autre {
      toucher ('.gitignore');
    }
  } autre {
    toucher ('. gitignore');
  }
},

Une fois “soumis”, nous générons ensuite un .gitignore en joignant la liste de fichiers sélectionnée, séparés par une nouvelle ligne. Notre fonction garantit à peu près maintenant que nous avons un fichier .gitignore de sorte que nous pouvons procéder à l'initialisation d'un référentiel Git.

Interaction avec Git depuis l'application

Il existe plusieurs façons pour interagir avec Git, mais le plus simple est peut-être d'utiliser le paquetage simple-git . Ceci fournit un ensemble de méthodes chaînables qui, en coulisse, exécutent l'exécutable Git.

Voici les tâches répétitives que nous allons utiliser pour automatiser:

  1. exécuter git init
  2. ajouter le . ] .gitignore fichier
  3. ajoute le contenu restant du répertoire de travail
  4. effectue un commit initial
  5. ajoute le référentiel distant nouvellement créé
  6. déplace le répertoire de travail vers le répertoire distant.

Insérez le code suivant dans lib / repo.js :

 setupRepo: async (url) => {
  const status = new Spinner ('Initialisation du référentiel local et transmission à distance ...');
  status.start ();

  retourne git.init ()
    .then (git.add ('. gitignore'))
    .then (git.add ('./*'))
    .then (git.commit ('Commit initial'))
    .then (git.addRemote ('origine', url))
    .then (git.push ('origine', 'maître'))
    .finally (status.stop ());
},

Tout mettre en place

Définissons tout d'abord une fonction d'assistance dans lib / github.js pour la création d'un oauth authentification:

 githubAuth: (token) => {
  octokit = nouvel octokit ({
    auth: jeton
  });
},

Ensuite, nous créons une fonction dans index.js pour gérer la logique d'acquisition du jeton. Placez ce code avant la fonction run () ::

 const getGithubToken = async () => {
  // Récupération du jeton depuis le magasin de configuration
  let token = github.getStoredGithubToken ();
  si (jeton) {
    rendre le jeton;
  }

  // Aucun jeton trouvé, utilisez les informations d'identification pour accéder au compte GitHub
  attendez github.setGithubCredentials ();

  // enregistrer un nouveau jeton
  jeton = attendez github.registerNewToken ();
  rendre le jeton;
};

Enfin, nous mettons à jour la fonction run () en écrivant un code qui gérera la logique principale de l'application:

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

...

const run = async () => {
  essayer {
    // Récupérer et définir le jeton d'authentification
    jeton de const = wait getGithubToken ();
    github.githubAuth (jeton);

    // Créer un référentiel distant
    const url = wait repo.createRemoteRepo ();

    // Créer un fichier .gitignore
    attendez repo.createGitignore ();

    // Configurer le référentiel local et pousser à distance
    attendez repo.setupRepo (url);
    console.log (chalk.green ('Tout est fait!'));
  } catch (err) {
      si (err) {
        switch (err.status) {
          cas 401:
            console.log (chalk.red ('Impossible de vous connecter. Veuillez fournir les informations de connexion / le jeton corrects.'));
            Pause;
          cas 422:
            console.log (chalk.red ('Il existe déjà un référentiel distant portant le même nom'));
            Pause;
          défaut:
            console.log (err);
        }
      }
  }
};

Comme vous pouvez le constater, nous nous assurons que l'utilisateur est authentifié avant d'appeler toutes nos autres fonctions ( createRemoteRepo () createGitignore () setupRepo () ) séquentiellement. Le code traite également les erreurs et offre à l'utilisateur des informations en retour appropriées.

Vous pouvez consulter le fichier index.js terminé sur notre rapport GitHub.

À ce stade, vous devriez avoir une application opérationnelle. Essayez-le et assurez-vous qu'il fonctionne comme prévu.

Rendre la commande ginit disponible dans le monde entier

Il ne reste plus qu'à rendre notre commande disponible dans le monde entier. Pour ce faire, nous devons ajouter une ligne shebang au sommet du index.js :

 #! / Usr / bin / env node

Ensuite, nous devons ajouter une propriété bin à notre fichier package.json . Cela associe le nom de la commande ( ginit ) au nom du fichier à exécuter (par rapport à package.json ).

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

Après cela, installez le module globalement et vous obtiendrez une commande shell:

 npm install -g

Astuce: cela fonctionnera également sous Windows, car npm installera utilement un wrapper cmd à côté de votre script .

Si vous souhaitez confirmer que l'installation a fonctionné, vous pouvez Répertoriez vos modules de nœud installés globalement à l'aide de:

 npm ls --depth = 0

Nous disposons d’une application en ligne de commande assez astucieuse, bien que simple, pour l’initialisation des référentiels Git. Mais vous pouvez faire beaucoup plus pour l’améliorer davantage.

Si vous êtes un utilisateur de Bitbucket, vous pouvez adapter le programme à l’utilisation de l’API de Bitbucket pour créer un référentiel. Un wrapper d’API Node.js est disponible pour vous aider à démarrer. Vous pouvez souhaiter ajouter une option de ligne de commande supplémentaire ou une invite pour demander à l'utilisateur s'il souhaite utiliser GitHub ou Bitbucket (Inquirer serait parfait pour cela) ou simplement remplacer le code spécifique à GitHub par une alternative à Bitbucket.

Vous pouvez également fournir la possibilité de spécifier votre propre ensemble de valeurs par défaut pour le fichier .gitgnore au lieu d'une liste codée en dur. Le paquet de préférences peut convenir ici, ou vous pouvez fournir un ensemble de «modèles» – invitant peut-être l'utilisateur à indiquer le type de projet. Vous pouvez également envisager de l'intégrer à l'outil / API de ligne de commande .gitignore.io .

Au-delà de cela, vous pouvez également vouloir ajouter une validation supplémentaire, permettre d'ignorer certaines sections, et plus. Si vous avez d'autres idées, faites-le-nous savoir dans les commentaires.




Source link