Skip to main content

Création d’une interface CLI avec une application GitHub App

Suivez ce tutoriel pour écrire une interface CLI en Ruby qui permet de générer un jeton d’accès utilisateur pour une GitHub App via le flux d’appareil.

Introduction

Ce tutoriel montre la procédure pour créer une interface de ligne de commande (CLI) qui s’appuie sur une GitHub App, et la procédure pour utiliser le flux d’appareil afin de générer un jeton d’accès utilisateur pour l’application.

L’interface CLI a trois commandes :

  • help : génère les instructions d’utilisation.
  • login : génère un jeton d’accès utilisateur que l’application peut utiliser pour effectuer des demandes d’API au nom de l’utilisateur.
  • whoami : retourne des informations sur l’utilisateur connecté.

Ce tutoriel utilise Ruby, mais vous pouvez écrire une interface CLI et utiliser le flux d’appareil pour générer un jeton d’accès utilisateur avec le langage de programmation de votre choix.

À propos du flux d’appareil et des jetons d’accès utilisateur

L’interface CLI utilise le flux d’appareil pour authentifier un utilisateur et générer un jeton d’accès utilisateur. L’interface CLI peut ensuite utiliser le jeton d’accès utilisateur afin d’effectuer des demandes d’API pour le compte de l’utilisateur authentifié.

Votre application doit utiliser un jeton d’accès utilisateur si vous souhaitez attribuer des actions de l’application à un utilisateur. Pour plus d’informations, consultez « Authentification auprès d’une application GitHub pour le compte d’un utilisateur ».

Deux méthodes permettent de générer un jeton d’accès utilisateur pour une GitHub App : le flux d’application web et le flux d’appareil. Vous devez utiliser le flux d’appareil pour générer un jeton d’accès utilisateur si votre application est sans périphérique de contrôle ou n’a pas accès à un navigateur. Les outils CLI, les Raspberry Pi simples et les applications de bureau doivent par exemple utiliser le flux d’appareil. Si votre application a accès à une interface web, vous devez utiliser le flux d’application web à la place. Pour plus d’informations, consultez « Génération d’un jeton d’accès utilisateur pour une application GitHub » et « Création d’un bouton « Se connecter avec GitHub » avec une application GitHub App ».

Prérequis

Ce tutoriel part du principe que vous avez déjà inscrit une GitHub App. Pour plus d’informations sur l’inscription d’une GitHub App, consultez « Inscription d’une application GitHub ».

Avant de suivre ce tutoriel, vous devez activer le flux d’appareil pour votre application. Pour plus d’informations sur l’activation du flux d’appareil pour votre application, consultez « Modification d’une inscription d’application GitHub ».

Ce tutoriel suppose que vous disposez de connaissances de base de Ruby. Pour plus d’informations, consultez Ruby.

Obtenir l’ID client

Vous avez besoin de l’ID client de votre application pour générer un jeton d’accès utilisateur via le flux d’appareil.

  1. Dans le coin supérieur droit de n’importe quelle page sur GitHub, cliquez sur votre photo de profil.
  2. Accédez aux paramètres de votre compte.
    • Pour une application appartenant à un compte personnel, cliquez sur Paramètres.
    • Pour une application appartenant à une organisation :
      1. Cliquez sur Vos organisations.
      2. À droite de l’organisation, cliquez sur Paramètres.
  3. Dans la barre latérale gauche, cliquez sur Paramètres de développeur.
  4. Dans la barre latérale à gauche, cliquez sur GitHub Apps .
  5. À côté de l’GitHub App que vous souhaitez utiliser, cliquez sur Modifier.
  6. Dans la page des paramètres de l’application, recherchez l’ID client de votre application. Vous l’utiliserez ultérieurement dans ce tutoriel. Notez que l’ID client est différent de l’ID de l’application.

Écrire l’interface CLI

Ces étapes vous guident dans la création d’une interface CLI et l’utilisation du flux d’appareil pour obtenir un jeton d’accès utilisateur. Pour passer au code final, consultez « Exemple de code complet ».

Programme d’installation

  1. Créez un fichier Ruby pour contenir le code qui va générer un jeton d’accès utilisateur. Dans ce tutoriel, le fichier est nommé app_cli.rb.

  2. Dans votre terminal, à partir du répertoire où app_cli.rb est stocké, exécutez la commande suivante pour transformer app_cli.rb en exécutable :

    Text
    chmod +x app_cli.rb
    
  3. Ajoutez cette ligne en haut de app_cli.rb afin d’indiquer que l’interpréteur Ruby doit être utilisé pour exécuter le script :

    Ruby
    #!/usr/bin/env ruby
    
  4. Ajoutez ces dépendances en haut de app_cli.rb, comme suit #!/usr/bin/env ruby :

    Ruby
    require "net/http"
    require "json"
    require "uri"
    require "fileutils"
    

    Ces éléments font tous partie de la bibliothèque standard Ruby. Vous n’avez donc pas besoin d’installer de gems.

  5. Ajoutez la fonction suivante main qui va servir de point d’entrée. La fonction inclut une instruction case permettant d’effectuer différentes actions selon la commande spécifiée. Vous développerez cette instruction case ultérieurement.

    Ruby
    def main
      case ARGV[0]
      when "help"
        puts "`help` is not yet defined"
      when "login"
        puts "`login` is not yet defined"
      when "whoami"
        puts "`whoami` is not yet defined"
      else
        puts "Unknown command `#{ARGV[0]}`"
      end
    end
    
  6. En bas du fichier, ajoutez la ligne suivante pour appeler la fonction de point d’entrée. Cet appel de fonction doit rester en bas du fichier quand vous ajoutez des fonctions supplémentaires à ce fichier ultérieurement au cours de ce tutoriel.

    Ruby
    main
    
  7. Vous pouvez également vérifier votre progression :

    app_cli.rb se présente maintenant comme suit :

    Ruby
    #!/usr/bin/env ruby
    
    require "net/http"
    require "json"
    require "uri"
    require "fileutils"
    
    def main
      case ARGV[0]
      when "help"
        puts "`help` is not yet defined"
      when "login"
        puts "`login` is not yet defined"
      when "whoami"
        puts "`whoami` is not yet defined"
      else
        puts "Unknown command `#{ARGV[0]}`"
      end
    end
    
    main
    

    Dans votre terminal, dans le répertoire où app_cli.rb est stocké, exécutez ./app_cli.rb help. Cette sortie doit s’afficher :

    `help` is not yet defined
    

    Vous pouvez également tester votre script sans commande ou avec une commande non prise en charge. ./app_cli.rb create-issue doit par exemple générer :

    Unknown command `create-issue`
    

Ajouter une commande help

  1. Ajoutez la fonction suivante help à app_cli.rb. Actuellement, la fonction help imprime une ligne pour indiquer aux utilisateurs que cette interface CLI prend une commande « help ». Vous développerez cette fonction help ultérieurement.

    Ruby
    def help
      puts "usage: app_cli <help>"
    end
    
  2. Mettez à jour la fonction main pour appeler la fonction help quand la commande help est fournie :

    Ruby
    def main
      case ARGV[0]
      when "help"
        help
      when "login"
        puts "`login` is not yet defined"
      when "whoami"
        puts "`whoami` is not yet defined"
      else
        puts "Unknown command #{ARGV[0]}"
      end
    end
    
  3. Vous pouvez éventuellement voir votre progression :

    app_cli.rb se présente maintenant comme suit. L'ordre des fonctions n'a pas d'importance tant que l'appel de fonction main se trouve à la fin du fichier.

    Ruby
    #!/usr/bin/env ruby
    
    require "net/http"
    require "json"
    require "uri"
    require "fileutils"
    
    def help
      puts "usage: app_cli <help>"
    end
    
    def main
      case ARGV[0]
      when "help"
        help
      when "login"
        puts "`login` is not yet defined"
      when "whoami"
        puts "`whoami` is not yet defined"
      else
        puts "Unknown command #{ARGV[0]}"
      end
    end
    
    main
    

    Dans votre terminal, dans le répertoire où app_cli.rb est stocké, exécutez ./app_cli.rb help. Cette sortie doit s’afficher :

    usage: app_cli <help>
    

Ajouter une commande login

La commande login exécute le flux d’appareil pour obtenir un jeton d’accès utilisateur. Pour plus d’informations, consultez « Génération d’un jeton d’accès utilisateur pour une application GitHub ».

  1. En haut de votre fichier, après les instructions require, ajoutez le CLIENT_ID de votre GitHub App en tant que constante dans app_cli.rb. Pour plus d’informations sur la recherche de l’ID client de votre application, consultez « Obtenir l’ID client ». Remplacez YOUR_CLIENT_ID par l’ID client de votre application :

    Ruby
    CLIENT_ID="YOUR_CLIENT_ID"
    
  2. Ajoutez la fonction suivante parse_response à app_cli.rb. Cette fonction analyse une réponse de l’API REST GitHub. Quand l’état de la réponse est 200 OK ou 201 Created, la fonction retourne le corps de la réponse analysé. Dans les autres cas, la fonction imprime la réponse et le corps, puis quitte le programme.

    Ruby
    def parse_response(response)
      case response
      when Net::HTTPOK, Net::HTTPCreated
        JSON.parse(response.body)
      else
        puts response
        puts response.body
        exit 1
      end
    end
    
  3. Ajoutez la fonction suivante request_device_code à app_cli.rb. Cette fonction envoie une requête POST à https://github.com/login/device/code et retourne la réponse.

    Ruby
    def request_device_code
      uri = URI("https://github.com/login/device/code")
      parameters = URI.encode_www_form("client_id" => CLIENT_ID)
      headers = {"Accept" => "application/json"}
    
      response = Net::HTTP.post(uri, parameters, headers)
      parse_response(response)
    end
    
  4. Ajoutez la fonction suivante request_token à app_cli.rb. Cette fonction envoie une requête POST à https://github.com/login/oauth/access_token et retourne la réponse.

    Ruby
    def request_token(device_code)
      uri = URI("https://github.com/login/oauth/access_token")
      parameters = URI.encode_www_form({
        "client_id" => CLIENT_ID,
        "device_code" => device_code,
        "grant_type" => "urn:ietf:params:oauth:grant-type:device_code"
      })
      headers = {"Accept" => "application/json"}
      response = Net::HTTP.post(uri, parameters, headers)
      parse_response(response)
    end
    
  5. Ajoutez la fonction suivante poll_for_token à app_cli.rb. Cette fonction interroge https://github.com/login/oauth/access_token à l’intervalle spécifié jusqu’à ce que GitHub réponde avec un paramètre access_token au lieu d’un paramètre error. Elle écrit ensuite le jeton d’accès utilisateur dans un fichier et limite les autorisations sur le fichier.

    Ruby
    def poll_for_token(device_code, interval)
    
      loop do
        response = request_token(device_code)
        error, access_token = response.values_at("error", "access_token")
    
        if error
          case error
          when "authorization_pending"
            # The user has not yet entered the code.
            # Wait, then poll again.
            sleep interval
            next
          when "slow_down"
            # The app polled too fast.
            # Wait for the interval plus 5 seconds, then poll again.
            sleep interval + 5
            next
          when "expired_token"
            # The `device_code` expired, and the process needs to restart.
            puts "The device code has expired. Please run `login` again."
            exit 1
          when "access_denied"
            # The user cancelled the process. Stop polling.
            puts "Login cancelled by user."
            exit 1
          else
            puts response
            exit 1
          end
        end
    
        File.write("./.token", access_token)
    
        # Set the file permissions so that only the file owner can read or modify the file
        FileUtils.chmod(0600, "./.token")
    
        break
      end
    end
    
  6. Ajoutez la fonction login suivante.

    Cette fonction :

    1. Appelle la fonction request_device_code et obtient les paramètres verification_uri, user_code, device_code et interval dans la réponse.
    2. Invite les utilisateurs à entrer le user_code de l’étape précédente.
    3. Appelle poll_for_token pour interroger GitHub afin d’obtenir un jeton d’accès.
    4. Indique à l’utilisateur que l’authentification a réussi.
    Ruby
    def login
      verification_uri, user_code, device_code, interval = request_device_code.values_at("verification_uri", "user_code", "device_code", "interval")
    
      puts "Please visit: #{verification_uri}"
      puts "and enter code: #{user_code}"
    
      poll_for_token(device_code, interval)
    
      puts "Successfully authenticated!"
    end
    
  7. Mettez à jour la fonction main pour appeler la fonction login quand la commande login est fournie :

    Ruby
    def main
      case ARGV[0]
      when "help"
        help
      when "login"
        login
      when "whoami"
        puts "`whoami` is not yet defined"
      else
        puts "Unknown command #{ARGV[0]}"
      end
    end
    
  8. Mettez à jour la fonction help pour inclure la commande login :

    Ruby
    def help
      puts "usage: app_cli <login | help>"
    end
    
  9. Vous pouvez également vérifier votre progression :

    app_cli.rb ressemble maintenant à ceci, où YOUR_CLIENT_ID est l’ID client de votre application. L'ordre des fonctions n'a pas d'importance tant que l'appel de fonction main se trouve à la fin du fichier.

    Ruby
    #!/usr/bin/env ruby
    
    require "net/http"
    require "json"
    require "uri"
    require "fileutils"
    
    CLIENT_ID="YOUR_CLIENT_ID"
    
    def help
      puts "usage: app_cli <login | help>"
    end
    
    def main
      case ARGV[0]
      when "help"
        help
      when "login"
        login
      when "whoami"
        puts "`whoami` is not yet defined"
      else
        puts "Unknown command #{ARGV[0]}"
      end
    end
    
    def parse_response(response)
      case response
      when Net::HTTPOK, Net::HTTPCreated
        JSON.parse(response.body)
      else
        puts response
        puts response.body
        exit 1
      end
    end
    
    def request_device_code
      uri = URI("https://github.com/login/device/code")
      parameters = URI.encode_www_form("client_id" => CLIENT_ID)
      headers = {"Accept" => "application/json"}
    
      response = Net::HTTP.post(uri, parameters, headers)
      parse_response(response)
    end
    
    def request_token(device_code)
      uri = URI("https://github.com/login/oauth/access_token")
      parameters = URI.encode_www_form({
        "client_id" => CLIENT_ID,
        "device_code" => device_code,
        "grant_type" => "urn:ietf:params:oauth:grant-type:device_code"
      })
      headers = {"Accept" => "application/json"}
      response = Net::HTTP.post(uri, parameters, headers)
      parse_response(response)
    end
    
    def poll_for_token(device_code, interval)
    
      loop do
        response = request_token(device_code)
        error, access_token = response.values_at("error", "access_token")
    
        if error
          case error
          when "authorization_pending"
            # The user has not yet entered the code.
            # Wait, then poll again.
            sleep interval
            next
          when "slow_down"
            # The app polled too fast.
            # Wait for the interval plus 5 seconds, then poll again.
            sleep interval + 5
            next
          when "expired_token"
            # The `device_code` expired, and the process needs to restart.
            puts "The device code has expired. Please run `login` again."
            exit 1
          when "access_denied"
            # The user cancelled the process. Stop polling.
            puts "Login cancelled by user."
            exit 1
          else
            puts response
            exit 1
          end
        end
    
        File.write("./.token", access_token)
    
        # Set the file permissions so that only the file owner can read or modify the file
        FileUtils.chmod(0600, "./.token")
    
        break
      end
    end
    
    def login
      verification_uri, user_code, device_code, interval = request_device_code.values_at("verification_uri", "user_code", "device_code", "interval")
    
      puts "Please visit: #{verification_uri}"
      puts "and enter code: #{user_code}"
    
      poll_for_token(device_code, interval)
    
      puts "Successfully authenticated!"
    end
    
    main
    
    1. Dans votre terminal, dans le répertoire où app_cli.rb est stocké, exécutez ./app_cli.rb login. Vous devez obtenir une sortie similaire à celle-ci. Le code est différent à chaque fois :

      Please visit: https://github.com/login/device
      and enter code: CA86-8D94
      
    2. Accédez à https://github.com/login/device dans votre navigateur, entrez le code de l’étape précédente, puis cliquez sur Continuer.

    3. GitHub doit afficher une page qui vous invite à autoriser votre application. Cliquez sur le bouton « Autoriser ».

    4. Votre terminal doit maintenant indiquer « Authentifié avec succès ».

Ajouter une commande whoami

Maintenant que votre application peut générer un jeton d’accès utilisateur, vous pouvez effectuer des demandes d’API pour le compte de l’utilisateur. Ajoutez une commande whoami pour obtenir le nom d’utilisateur de l’utilisateur authentifié.

  1. Ajoutez la fonction suivante whoami à app_cli.rb. Cette fonction obtient les informations sur l’utilisateur avec le point de terminaison de l’API REST /user. Elle génère le nom d’utilisateur qui correspond au jeton d’accès utilisateur. Si le fichier .token est introuvable, elle invite l’utilisateur à exécuter la fonction login.

    Ruby
    def whoami
      uri = URI("https://api.github.com/user")
    
      begin
        token = File.read("./.token").strip
      rescue Errno::ENOENT => e
        puts "You are not authorized. Run the `login` command."
        exit 1
      end
    
      response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
        body = {"access_token" => token}.to_json
        headers = {"Accept" => "application/vnd.github+json", "Authorization" => "Bearer #{token}"}
    
        http.send_request("GET", uri.path, body, headers)
      end
    
      parsed_response = parse_response(response)
      puts "You are #{parsed_response["login"]}"
    end
    
  2. Mettez à jour la fonction parse_response pour gérer le cas d’un jeton qui a expiré ou a été révoqué. Si vous obtenez maintenant une réponse 401 Unauthorized, l’interface CLI invite l’utilisateur à exécuter la commande login.

    Ruby
    def parse_response(response)
      case response
      when Net::HTTPOK, Net::HTTPCreated
        JSON.parse(response.body)
      when Net::HTTPUnauthorized
        puts "You are not authorized. Run the `login` command."
        exit 1
      else
        puts response
        puts response.body
        exit 1
      end
    end
    
  3. Mettez à jour la fonction main pour appeler la fonction whoami quand la commande whoami est fournie :

    Ruby
    def main
      case ARGV[0]
      when "help"
        help
      when "login"
        login
      when "whoami"
        whoami
      else
        puts "Unknown command #{ARGV[0]}"
      end
    end
    
  4. Mettez à jour la fonction help pour inclure la commande whoami :

    Ruby
    def help
      puts "usage: app_cli <login | whoami | help>"
    end
    
  5. Vérifiez votre code par rapport à l’exemple de code complet présenté dans la section suivante. Vous pouvez tester votre code en suivant les étapes décrites dans la section « Test » sous l’exemple de code complet.

Exemple de code complet

Il s’agit de l’exemple de code complet décrit dans la section précédente. Remplacez YOUR_CLIENT_ID par l’ID client de votre application.

Ruby
#!/usr/bin/env ruby

require "net/http"
require "json"
require "uri"
require "fileutils"

CLIENT_ID="YOUR_CLIENT_ID"

def help
  puts "usage: app_cli <login | whoami | help>"
end

def main
  case ARGV[0]
  when "help"
    help
  when "login"
    login
  when "whoami"
    whoami
  else
    puts "Unknown command #{ARGV[0]}"
  end
end

def parse_response(response)
  case response
  when Net::HTTPOK, Net::HTTPCreated
    JSON.parse(response.body)
  when Net::HTTPUnauthorized
    puts "You are not authorized. Run the `login` command."
    exit 1
  else
    puts response
    puts response.body
    exit 1
  end
end

def request_device_code
  uri = URI("https://github.com/login/device/code")
  parameters = URI.encode_www_form("client_id" => CLIENT_ID)
  headers = {"Accept" => "application/json"}

  response = Net::HTTP.post(uri, parameters, headers)
  parse_response(response)
end

def request_token(device_code)
  uri = URI("https://github.com/login/oauth/access_token")
  parameters = URI.encode_www_form({
    "client_id" => CLIENT_ID,
    "device_code" => device_code,
    "grant_type" => "urn:ietf:params:oauth:grant-type:device_code"
  })
  headers = {"Accept" => "application/json"}
  response = Net::HTTP.post(uri, parameters, headers)
  parse_response(response)
end

def poll_for_token(device_code, interval)

  loop do
    response = request_token(device_code)
    error, access_token = response.values_at("error", "access_token")

    if error
      case error
      when "authorization_pending"
        # The user has not yet entered the code.
        # Wait, then poll again.
        sleep interval
        next
      when "slow_down"
        # The app polled too fast.
        # Wait for the interval plus 5 seconds, then poll again.
        sleep interval + 5
        next
      when "expired_token"
        # The `device_code` expired, and the process needs to restart.
        puts "The device code has expired. Please run `login` again."
        exit 1
      when "access_denied"
        # The user cancelled the process. Stop polling.
        puts "Login cancelled by user."
        exit 1
      else
        puts response
        exit 1
      end
    end

    File.write("./.token", access_token)

    # Set the file permissions so that only the file owner can read or modify the file
    FileUtils.chmod(0600, "./.token")

    break
  end
end

def login
  verification_uri, user_code, device_code, interval = request_device_code.values_at("verification_uri", "user_code", "device_code", "interval")

  puts "Please visit: #{verification_uri}"
  puts "and enter code: #{user_code}"

  poll_for_token(device_code, interval)

  puts "Successfully authenticated!"
end

def whoami
  uri = URI("https://api.github.com/user")

  begin
    token = File.read("./.token").strip
  rescue Errno::ENOENT => e
    puts "You are not authorized. Run the `login` command."
    exit 1
  end

  response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    body = {"access_token" => token}.to_json
    headers = {"Accept" => "application/vnd.github+json", "Authorization" => "Bearer #{token}"}

    http.send_request("GET", uri.path, body, headers)
  end

  parsed_response = parse_response(response)
  puts "You are #{parsed_response["login"]}"
end

main

Test

Ce tutoriel part du principe que le code de votre application est stocké dans un fichier nommé app_cli.rb.

  1. Dans votre terminal, dans le répertoire où app_cli.rb est stocké, exécutez ./app_cli.rb help. Vous devez obtenir une sortie similaire à celle-ci.

    usage: app_cli <login | whoami | help>
    
  2. Dans votre terminal, dans le répertoire où app_cli.rb est stocké, exécutez ./app_cli.rb login. Vous devez obtenir une sortie similaire à celle-ci. Le code est différent à chaque fois :

    Please visit: https://github.com/login/device
    and enter code: CA86-8D94
    
  3. Accédez à https://github.com/login/device dans votre navigateur, entrez le code de l’étape précédente, puis cliquez sur Continuer.

  4. GitHub doit afficher une page qui vous invite à autoriser votre application. Cliquez sur le bouton « Autoriser ».

  5. Votre terminal doit maintenant indiquer « Authentifié avec succès ».

  6. Dans votre terminal, dans le répertoire où app_cli.rb est stocké, exécutez ./app_cli.rb whoami. Une sortie de ce type doit s’afficher, où octocat est votre nom d’utilisateur.

    You are octocat
    
  7. Ouvrez le fichier .token dans votre éditeur et modifiez le jeton. Le jeton est désormais non valide.

  8. Dans votre terminal, dans le répertoire où app_cli.rb est stocké, exécutez ./app_cli.rb whoami. Vous devez normalement voir une sortie similaire à celle-ci :

    You are not authorized. Run the `login` command.
    
  9. Supprimez le fichier .token.

  10. Dans votre terminal, dans le répertoire où app_cli.rb est stocké, exécutez ./app_cli.rb whoami. Vous devez normalement voir une sortie similaire à celle-ci :

    You are not authorized. Run the `login` command.
    

Étapes suivantes

Ajustez le code selon les besoins de votre application

Ce tutoriel a montré comment écrire une interface CLI qui utilise le flux d’appareil pour générer un jeton d’accès utilisateur. Vous pouvez développer cette interface CLI pour accepter des commandes supplémentaires. Vous pouvez par exemple ajouter une commande create-issue qui ouvre un problème. N’oubliez pas de mettre à jour les autorisations de votre application si des autorisations supplémentaires sont nécessaires pour les demandes d’API que vous souhaitez effectuer. Pour plus d’informations, consultez « Choix des autorisations pour une application GitHub ».

Stocker les jetons en toute sécurité

Ce tutoriel génère un jeton d’accès utilisateur et l’enregistre dans un fichier local. Vous ne devez jamais valider (commit) ce fichier ni diffuser le jeton.

Selon votre appareil, vous pouvez choisir d'autres méthodes de stockage du jeton. Vous devez vérifier les meilleures pratiques pour stocker des jetons sur votre appareil.

Pour plus d’informations, consultez « Meilleures pratiques pour la création d’une application GitHub ».

Suivre les bonnes pratiques

Vous devez vous efforcer de suivre les bonnes pratiques avec votre GitHub App. Pour plus d’informations, consultez « Meilleures pratiques pour la création d’une application GitHub ».