Skip to main content

Erstellen von CI-Prüfungen mit einer GitHub-App

Erstelle einen kontinuierlichen Integrationsserver, um Tests mithilfe einer GitHub App und Überprüfungen durchzuführen.

Einführung

In diesem Tutorial wird veranschaulicht, wie du einen CI-Server (Continuous Integration) erstellst, der Tests für neuen Code ausführt, der in ein Repository gepusht wird. In diesem Tutorial wird gezeigt, wie du eine GitHub App erstellst und konfigurierst, um als Server zu fungieren, der GitHub-REST-API - und -Webhook-Ereignisse empfängt und darauf reagiert.

In diesem Tutorial verwendest du deinen Computer oder Codespace als Server, während du deine App entwickelst. Sobald die App für die Verwendung in der Produktion bereit ist, solltest du deine App auf einem dedizierten Server bereitstellen.

In diesem Tutorial wird Ruby verwendet, du kannst jedoch jede Programmiersprache verwenden, die du auf deinem Server ausführen kannst.

Dieses Tutorial ist in zwei Teile unterteilt:

  • Im ersten Teil erfährst du, wie du das Framework für einen CI-Server mit der REST-API von GitHub einrichtest, neue Überprüfungsausführungen für CI-Tests erstellst, wenn ein Repository neu gepushte Commits empfängt, und Überprüfungsausführungen erneut ausführst, wenn ein Benutzer diese Aktion für GitHub anfordert.
  • Im zweiten Teil fügst du deinem CI-Test eine Funktion hinzu, indem du deinem CI-Server einen Lintertest hinzufügst. Außerdem erstellst du Anmerkungen, die auf den Tabs „Überprüfungen“ und „Geänderte Dateien“ eines Pull Requests angezeigt werden, und korrigierst automatisch Linter-Empfehlungen, indem du auf dem Tab „Überprüfungen“ des Pull Requests die Schaltfläche „Dies beheben“ verfügbar machst.

Informationen zu Continuous Integration (CI)

Bei der Softwarepraktik der CI erfolgen häufige Codecommits an ein gemeinsames Repository. Häufigere Commits tragen dazu bei, Fehler schneller zu erkennen, und verringern die Codemenge, die ein Entwickler beim Debuggen eines Fehlers bearbeiten muss. Durch häufige Code-Aktualisierungen lassen sich zudem Änderungen von verschiedenen Mitgliedern eines Software-Entwicklungsteams leichter zusammenführen. Dies bedeutet einen erheblichen Vorteil für die Entwickler, die sich damit stärker auf das Schreiben des Codes konzentrieren können, statt Fehler debuggen oder Mergekonflikte beheben zu müssen.

Auf einem CI-Server wird Code zum Ausführen von CI-Tests wie Code-Linter (zum Überprüfen der Formatvorlagenformatierung), Sicherheitsüberprüfungen, Code Coverage und andere Überprüfungen bei neuen Codecommits in einem Repository gehostet. CI-Server können auch Code für Staging- oder Produktionsserver erstellen und bereitstellen. Beispiele für die Arten von CI-Tests, die du mit einer GitHub App erstellen kannst, findest du in den Continuous Integration-Apps, die im GitHub Marketplace verfügbar sind.

Informationen zu Überprüfungen

Mit der REST-API von GitHub kannst du CI-Tests (Überprüfungen) einrichten, die automatisch für jeden Codecommit in einem Repository ausgeführt werden. Die API meldet detaillierte Informationen zu jeder Überprüfung auf der Registerkarte Überprüfungen des Pull Requests auf GitHub. Du kannst Überprüfungen in einem Repository verwenden, um zu bestimmen, wann mit einem Codecommit Fehler verursacht werden.

Zu den Überprüfungen gehören Überprüfungsausführungen, Überprüfungssammlungen und Commitstatus.

  • Eine Überprüfungsausführung ist ein einzelner CI-Test, der mit einem Commit ausgeführt wird.
  • Eine Prüfungssuite ist eine Gruppe von Prüfungsläufen.
  • Ein Commitstatus gibt den Status eines Commits an, zum Beispiel , , oder , und ist in einem Pull Request auf GitHub sichtbar. Sowohl Überprüfungssammlungen und Überprüfungsausführungen enthalten Commitstatus.

GitHub erstellt mithilfe des Standardflows automatisch -Ereignisse für neue Codecommits in einem Repository. Du kannst die Standardeinstellungen jedoch ändern. Weitere Informationen finden Sie unter AUTOTITLE. Und so sieht der Standardablauf aus:

  1. Wenn jemand Code in das Repository pusht, sendet GitHub das Ereignis automatisch mit einer Aktion an alle GitHub Apps, die im Repository installiert sind und über die entsprechende Berechtigung verfügen. Dieses Ereignis teilt den Apps mit, dass Code in das Repository gepusht wurde und dass GitHub automatisch eine neue Überprüfungssammlung erstellt hat.
  2. Wenn Ihre App dieses Ereignis empfängt, kann sie dieser Suite Prüfungsläufe hinzufügen.
  3. Deine Überprüfungsausführungen können Anmerkungen enthalten, die in bestimmten Codezeilen angezeigt werden. Anmerkungen werden auf der Registerkarte Checks angezeigt. Wenn du eine Anmerkung für eine Datei erstellst, die zu einem Pull Request gehört, wird diese auch auf der Registerkarte Files changed angezeigt. Weitere Informationen findest du im -Objekt unter AUTOTITLE.

Weitere Informationen zu Überprüfungen findest du unter AUTOTITLE und AUTOTITLE.

Voraussetzungen

In diesem Tutorial wird vorausgesetzt, dass du über grundlegende Kenntnisse der Ruby-Programmiersprache verfügst.

Bevor du anfängst, solltest du dich mit den folgenden Konzepten vertraut machen:

  • GitHub Apps
  • Webhooks
  • REST-API überprüft Endpunkte

Überprüfungen können auch mit der GraphQL-API verwendet werden, der Fokus dieses Tutorials liegt jedoch auf der REST-API. Weitere Informationen zu den GraphQL-Objekten findest du in der GraphQL-Dokumentation unter den Einträgen Check Suite und Check Run.

Einrichten

Die folgenden Abschnitte führen dich durch die Einrichtung der folgenden Komponenten:

  • ein Repository zum Speichern des Codes für deine App
  • eine Möglichkeit zum lokalen Empfang von Webhooks
  • eine GitHub App, die die Webhookereignisse „Überprüfungssammlung“ und „Überprüfungsausführung“ abonniert hat, über die Schreibberechtigung für Überprüfungen verfügt und eine Webhook-URL verwendet, die du lokal empfangen kannst

Erstellen eines Repositorys zum Speichern von Code für deine GitHub App

  1. Erstelle ein Repository zum Speichern des Codes für deine App. Weitere Informationen finden Sie unter AUTOTITLE.

  2. Klone dein Repository aus dem vorherigen Schritt. Weitere Informationen finden Sie unter AUTOTITLE. Du kannst einen lokalen Klon oder GitHub Codespaces verwenden.

  3. Navigiere in einem Terminal zu dem Verzeichnis, in dem dein Klon gespeichert ist.

  4. Erstelle eine Ruby-Datei mit dem Namen . Diese Datei enthält den gesamten Code für deine App. Du fügst dieser Datei später Inhalte hinzu.

  5. Wenn das Verzeichnis noch keine -Datei enthält, füge eine -Datei hinzu. Du fügst dieser Datei später Inhalte hinzu. Weitere Informationen zu Dateien finden Sie unter AUTOTITLE.

  6. Erstelle eine Datei mit dem Namen . In dieser Datei werden die Gem-Abhängigkeiten beschrieben, die dein Ruby-Code benötigt. Füge zu deinem Dokument den folgenden Inhalt hinzu:

    Ruby
    source 'http://rubygems.org'
    
    gem 'sinatra', '~> 2.0'
    gem 'jwt', '~> 2.1'
    gem 'octokit', '~> 4.0'
    gem 'puma'
    gem 'rubocop'
    gem 'dotenv'
    gem 'git'
    
  7. Erstelle eine Datei mit dem Namen . Diese Datei konfiguriert deinen Sinatra-Server für die Ausführung. Füge der -Datei den folgenden Inhalt hinzu:

    Ruby
    require './server'
    run GHAapp
    

Eine Webhook-Proxy-URL abrufen

Um deine App lokal zu entwickeln, kannst du eine Webhook-Proxy-URL verwenden, um Webhookereignisse von GitHub an deinen Computer oder Codespace weiterzuleiten. In diesem Tutorial wird „Smee.io“ verwendet, um eine Webhook-Proxy-URL bereitzustellen und Ereignisse weiterzuleiten.

  1. Führe in einem Terminal den folgenden Befehl aus, um den Smee-Client zu installieren:

    Shell
    npm install --global smee-client
    
  2. Navigiere im Browser zu .

  3. Klicke auf Neuen Kanal starten.

  4. Kopiere die vollständige URL unter „Webhook-Proxy-URL“.

  5. Führe im Terminal den folgenden Befehl aus, um den Smee-Client zu starten: Ersetze durch die Webhook-Proxy-URL, die du im vorherigen Schritt kopiert hast.

    Shell
    smee --url YOUR_DOMAIN --path /event_handler --port 3000
    

    Es sollte eine Ausgabe wie die folgende angezeigt werden:

    Forwarding https://smee.io/YOUR_DOMAIN to http://127.0.0.1:3000/event_handler
    Connected https://smee.io/YOUR_DOMAIN
    

Durch den Befehl wird Smee veranlasst, alle vom Smee-Kanal empfangenen Webhookereignisse an den Smee-Client weiterzuleiten, der auf deinem Computer ausgeführt wird. Die Option leitet Ereignisse an die Route weiter. Die -Option gibt Port 3000 an. Dabei handelt es sich um den Port, auf den dein Server lauschen soll, wenn du im weiteren Verlauf des Tutorials mehr Code hinzufügst. Mithilfe von Smee muss der Computer nicht für das öffentliche Internet verfügbar sein, damit er Webhooks von GitHub empfangen kann. Du kannst auch die Smee-URL im Browser öffnen, um Webhooknutzlasten zu überprüfen, wenn sie eingehen.

Es empfiehlt sich, dieses Terminalfenster geöffnet zu lassen und die Verbindung mit Smee aufrechtzuerhalten, während du die restlichen Schritte in diesem Leitfaden ausführst. Obwohl du die Verbindung mit dem Smee-Client trennen und erneut herstellen kannst, ohne deine eindeutige Domäne zu verlieren, ist es einfacher, die Verbindung aufrechtzuerhalten und andere Befehlszeilenaufgaben in einem anderen Terminalfenster auszuführen.

Registrieren einer GitHub App

Für dieses Tutorial musst du eine GitHub App mit folgenden Eigenschaften registrieren:

  • aktive Webhooks
  • Verwendung einer Webhook-URL, die du lokal empfangen kannst
  • hat die Repositoryberechtigung „Überprüfungen“
  • Abonniert die Webhook-Ereignisse „Check suite“ und „Check run“

Die folgenden Schritte führen dich durch das Konfigurieren einer GitHub App mit diesen Einstellungen. Weitere Informationen zu GitHub App-Einstellungen findest du unter AUTOTITLE.

  1. Klicke auf GitHub in der oberen rechten Ecke einer beliebigen Seite auf dein Profilfoto.

  2. Navigieren Sie zu den Einstellungen für Ihr Konto.

    • Klicken Sie bei einer App, die zu einem persönlichen Konto gehört, auf Einstellungen.
    • Für eine App im Besitz einer Organisation:
      1. Klicke Sie auf Ihre Organisationen.
      2. Klicken Sie rechts neben der Organisation auf Einstellungen.
    • Für eine App im Besitz eines Unternehmens:
      1. Klicken Sie auf Enterprise-Einstellungen.
  3. Navigieren Sie zu den GitHub App-Einstellungen.

    • Für eine App, die einem persönlichen Konto oder einer Organisation gehört:
      1. Klicke in der linken Randleiste auf Developer settings und dann auf GitHub Apps.
    • Für eine App im Besitz eines Unternehmens:
      1. Klicken Sie in der linken Randleiste auf Einstellungen, und dann auf GitHub Apps.
  4. Klicken Sie auf Neue GitHub App .

  5. Geben Sie unter „Name der GitHub App“ einen Namen für Ihre App ein. Beispielsweise , wobei dein GitHub-Benutzername ist.

  6. Gib unter „Homepage-URL“ eine URL für deine App ein. Du kannst beispielsweise die URL des Repositorys verwenden, das du erstellt hast, um den Code für deine App zu speichern.

  7. Überspringe die Abschnitte „Identifizieren und Autorisieren von Benutzern“ und „Nach der Installation“ dieses Tutorials.

  8. Stelle sicher, dass unter „Webhooks“ die Option Aktiv ausgewählt ist.

  9. Gib unter „Webhook-URL“ deine Webhook-Proxy-URL von früher ein. Weitere Informationen findest du unter Abrufen einer Webhookproxy-URL.

  10. Gib unter „Webhookgeheimnis“ eine zufällige Zeichenfolge ein. Dieses Geheimnis wird verwendet, um zu überprüfen, ob Webhooks von GitHub gesendet werden. Speichere diese Zeichenfolge. Du wirst sie später verwenden.

  11. Wähle unter „Repositoryberechtigungen“ neben „Prüfungen“ die Option Lesen & Schreiben aus.

  12. Wähle unter „Ereignisse abonnieren“ die Optionen Prüfungsreihe und Prüfungslauf aus.

  13. Wählen Sie unter „Wo kann diese GitHub App installiert werden?“ die Option Nur in diesem Konto aus. Sie können dies später ändern, wenn Sie Ihre App veröffentlichen möchten.

    Hinweis

    Wenn Ihre GitHub App unter einem Unternehmen registriert ist, gilt dieser Schritt nicht.

  14. Klicken Sie auf Erstellen von GitHub App.

Speichere die identifizierenden Informationen und Anmeldeinformationen deiner App

In diesem Tutorial erfährst du, wie du die Anmeldeinformationen deiner App und identifizierende Informationen als Umgebungsvariablen in einer -Datei speichern kannst. Wenn du deine App bereitstellst, musst du die Art ändern, in der die Anmeldeinformationen gespeichert werden. Weitere Informationen findest du unter Bereitstellen deiner App.

Stelle sicher, dass du dich auf einem sicheren Computer befindest, bevor du diese Schritte ausführst, da du deine Anmeldeinformationen lokal speicherst.

  1. Navigiere in deinem Terminal zu dem Verzeichnis, in dem dein Klon gespeichert ist.

  2. Erstelle eine Datei namens auf der obersten Ebene dieses Verzeichnisses.

  3. Füge zu deiner hinzu. Dadurch vermeidest du, versehentlich die Zugangsdaten deiner App zu veröffentlichen.

  4. Füge der -Datei den folgenden Inhalt hinzu. Ersetze durch den Namen von Ihre GitHub Enterprise Server-Instance. Du aktualisierst die anderen Werte in einem späteren Schritt.

    Shell
    GITHUB_APP_IDENTIFIER="YOUR_APP_ID"
    GITHUB_WEBHOOK_SECRET="YOUR_WEBHOOK_SECRET"
    GITHUB_PRIVATE_KEY="YOUR_PRIVATE_KEY"
    
  5. Navigiere zur Seite „Einstellungen“ für deine App:

    1. Klicke auf GitHub in der oberen rechten Ecke einer beliebigen Seite auf dein Profilfoto.

    2. Navigieren Sie zu den Einstellungen für Ihr Konto.

      • Klicken Sie bei einer App, die zu einem persönlichen Konto gehört, auf Einstellungen.
      • Für eine App im Besitz einer Organisation:
        1. Klicke Sie auf Ihre Organisationen.
        2. Klicken Sie rechts neben der Organisation auf Einstellungen.
      • Für eine App im Besitz eines Unternehmens:
        1. Klicken Sie auf Enterprise-Einstellungen.
    3. Klicke in der linken Randleiste auf Developer settings.

    4. Klicke auf der linken Randleiste auf GitHub Apps .

    5. Klicke neben dem Namen deiner App auf Bearbeiten.

  6. Suche auf der Einstellungenseite deiner App neben „App-ID“ die App-ID für deine App.

  7. Ersetze in deiner -Datei durch die App-ID deiner App.

  8. Ersetze in deiner -Datei durch das Webhookgeheimnis für deine App. Wenn du dein Webhookgeheimnis vergessen hast, klicke unter „Webhookgeheimnis (optional)“ auf Geheimnis ändern. Gib ein neues Geheimnis ein, und klicke dann auf Änderungen speichern.

  9. Klicke auf der Einstellungenseite deiner App unter „Private Schlüssel“ auf Privaten Schlüssel generieren. Es wird eine private -Schlüsseldatei auf deinen Computer heruntergeladen.

  10. Öffne die -Datei mit einem Text-Editor, oder verwende den folgenden Befehl auf der Befehlszeile, um den Inhalt der Datei anzuzeigen: .

  11. Kopiere den gesamten Inhalt der Datei und füge ihn als Wert von in deine Datei ein. Setze den gesamten Wert in Anführungszeichen.

    Hier siehst du eine env-Beispieldatei:

    GITHUB_APP_IDENTIFIER=12345
    GITHUB_WEBHOOK_SECRET=your webhook secret
    GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
    ...
    HkVN9...
    ...
    -----END RSA PRIVATE KEY-----"
    

Füge Code für deine GitHub App hinzu

In diesem Abschnitt erfährst, wie du grundlegenden Vorlagencode für deine GitHub App hinzufügen und erklären kannst, was der Code tut. Später im Tutorial erfährst du, wie du diesen Code änderst und hinzufügst, um die Funktionalität deiner App zu erweitern.

Füge deiner -Datei den folgenden Vorlagencode hinzu:

Ruby
require 'sinatra/base'  # Use the Sinatra web framework
require 'octokit'       # Use the Octokit Ruby library to interact with GitHub's REST API
require 'dotenv/load'   # Manages environment variables
require 'json'          # Allows your app to manipulate JSON data
require 'openssl'       # Verifies the webhook signature
require 'jwt'           # Authenticates a GitHub App
require 'time'          # Gets ISO 8601 representation of a Time object
require 'logger'        # Logs debug statements

# This code is a Sinatra app, for two reasons:
#   1. Because the app will require a landing page for installation.
#   2. To easily handle webhook events.

class GHAapp < Sinatra::Application

  # Sets the port that's used when starting the web server.
  set :port, 3000
  set :bind, '0.0.0.0'

  # Expects the private key in PEM format. Converts the newlines.
  PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n"))

  # Your registered app must have a webhook secret.
  # The secret is used to verify that webhooks are sent by GitHub.
  WEBHOOK_SECRET = ENV['GITHUB_WEBHOOK_SECRET']

  # The GitHub App's identifier (type integer).
  APP_IDENTIFIER = ENV['GITHUB_APP_IDENTIFIER']

  # Turn on Sinatra's verbose logging during development
  configure :development do
    set :logging, Logger::DEBUG
  end

  # Executed before each request to the `/event_handler` route
  before '/event_handler' do
    get_payload_request(request)
    verify_webhook_signature

    # If a repository name is provided in the webhook, validate that
    # it consists only of latin alphabetic characters, `-`, and `_`.
    unless @payload['repository'].nil?
      halt 400 if (@payload['repository']['name'] =~ /[0-9A-Za-z\-\_]+/).nil?
    end

    authenticate_app
    # Authenticate the app installation in order to run API operations
    authenticate_installation(@payload)
  end

  post '/event_handler' do

    # ADD EVENT HANDLING HERE #

    200 # success status
  end

  helpers do

    # ADD CREATE_CHECK_RUN HELPER METHOD HERE #

    # ADD INITIATE_CHECK_RUN HELPER METHOD HERE #

    # ADD CLONE_REPOSITORY HELPER METHOD HERE #

    # ADD TAKE_REQUESTED_ACTION HELPER METHOD HERE #

    # Saves the raw payload and converts the payload to JSON format
    def get_payload_request(request)
      # request.body is an IO or StringIO object
      # Rewind in case someone already read it
      request.body.rewind
      # The raw text of the body is required for webhook signature verification
      @payload_raw = request.body.read
      begin
        @payload = JSON.parse @payload_raw
      rescue => e
        fail 'Invalid JSON (#{e}): #{@payload_raw}'
      end
    end

    # Instantiate an Octokit client authenticated as a GitHub App.
    # GitHub App authentication requires that you construct a
    # JWT (https://jwt.io/introduction/) signed with the app's private key,
    # so GitHub can be sure that it came from the app and not altered by
    # a malicious third party.
    def authenticate_app
      payload = {
          # The time that this JWT was issued, _i.e._ now.
          iat: Time.now.to_i,

          # JWT expiration time (10 minute maximum)
          exp: Time.now.to_i + (10 * 60),

          # Your GitHub App's identifier number
          iss: APP_IDENTIFIER
      }

      # Cryptographically sign the JWT.
      jwt = JWT.encode(payload, PRIVATE_KEY, 'RS256')

      # Create the Octokit client, using the JWT as the auth token.
      @app_client ||= Octokit::Client.new(bearer_token: jwt)
    end

    # Instantiate an Octokit client, authenticated as an installation of a
    # GitHub App, to run API operations.
    def authenticate_installation(payload)
      @installation_id = payload['installation']['id']
      @installation_token = @app_client.create_app_installation_access_token(@installation_id)[:token]
      @installation_client = Octokit::Client.new(bearer_token: @installation_token)
    end

    # Check X-Hub-Signature to confirm that this webhook was generated by
    # GitHub, and not a malicious third party.
    #
    # GitHub uses the WEBHOOK_SECRET, registered to the GitHub App, to
    # create the hash signature sent in the `X-HUB-Signature` header of each
    # webhook. This code computes the expected hash signature and compares it to
    # the signature sent in the `X-HUB-Signature` header. If they don't match,
    # this request is an attack, and you should reject it. GitHub uses the HMAC
    # hexdigest to compute the signature. The `X-HUB-Signature` looks something
    # like this: 'sha1=123456'.
    def verify_webhook_signature
      their_signature_header = request.env['HTTP_X_HUB_SIGNATURE'] || 'sha1='
      method, their_digest = their_signature_header.split('=')
      our_digest = OpenSSL::HMAC.hexdigest(method, WEBHOOK_SECRET, @payload_raw)
      halt 401 unless their_digest == our_digest

      # The X-GITHUB-EVENT header provides the name of the event.
      # The action value indicates the which action triggered the event.
      logger.debug "---- received event #{request.env['HTTP_X_GITHUB_EVENT']}"
      logger.debug "----    action #{@payload['action']}" unless @payload['action'].nil?
    end

  end

  # Finally some logic to let us run this server directly from the command line,
  # or with Rack. Don't worry too much about this code. But, for the curious:
  # $0 is the executed file
  # __FILE__ is the current file
  # If they are the same—that is, we are running this file directly, call the
  # Sinatra run method
  run! if __FILE__ == $0
end

Im Rest dieses Abschnitts wird erläutert, was der Vorlagencode tut. Es gibt keine Schritte, die du in diesem Abschnitt ausführen musst. Wenn du bereits mit dem Vorlagencode vertraut bist, kannst du mit Starten des Servers fortfahren.

Verstehen des Vorlagencodes

Öffne die -Datei in einem Text-Editor. In dieser Datei werden Kommentare angezeigt, die zusätzlichen Kontext für den Vorlagencode bereitstellen. Es empfiehlt sich, diese Kommentare sorgfältig zu lesen und sogar eigene Kommentare zu neuem Code hinzuzufügen, den du schreibst.

Unterhalb der Liste der erforderlichen Dateien werden Sie als erstes den Code für die Deklaration sehen. Du schreibst den gesamten Code für die GitHub App innerhalb dieser Klasse. In den folgenden Abschnitten wird ausführlich erläutert, was der Code innerhalb dieser Klasse tut.

  • Festlegen des Ports
  • Lesen der Umgebungsvariablen
  • Aktiviere die Protokollierung.
  • Definieren eines -Filters
  • Definieren des Routenhandlers
  • Definieren der Hilfsmethoden

Festlegen des Ports

Das Erste, was Sie in der Deklaration sehen werden, ist . Dadurch wird der Port, der beim Starten des Webservers verwendet wird, so festgelegt, dass er mit dem Port übereinstimmt, an den du deine Webhook-Payloads in Get a Webhook Proxy URL umgeleitet hast.

  # Sets the port that's used when starting the web server.
  set :port, 3000
  set :bind, '0.0.0.0'

Lesen der Umgebungsvariablen

Als Nächstes liest diese Klasse die drei Umgebungsvariablen aus, die du beim Speichern der identifizierenden Informationen und Anmeldeinformationen deiner App festgelegt hast, und speichert sie anschließend in Variablen, um sie später zu verwenden.

# Expects the private key in PEM format. Converts the newlines.
PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n"))

# Your registered app must have a webhook secret.
# The secret is used to verify that webhooks are sent by GitHub.
WEBHOOK_SECRET = ENV['GITHUB_WEBHOOK_SECRET']

# The GitHub App's identifier (type integer).
APP_IDENTIFIER = ENV['GITHUB_APP_IDENTIFIER']

Aktiviere die Protokollierung.

Als Nächstes wird ein Codeblock angezeigt, der die Protokollierung während der Entwicklung ermöglicht. Dies ist die Standardumgebung in Sinatra. Mit diesem Code wird die Protokollierung auf der -Ebene aktiviert, sodass eine nützliche Ausgabe im Terminal angezeigt wird, während du die App entwickelst.

# Turn on Sinatra's verbose logging during development
configure :development do
  set :logging, Logger::DEBUG
end

Definieren eines -Filters

In Sinatra werden -Filter verwendet, mit denen du Code vor dem Routenhandler ausführen kannst. Vom -Block in der Vorlage werden vier Hilfsmethoden aufgerufen: , , und . Weitere Informationen findest du in der Sinatra-Dokumentation unter Filter und Hilfsprogramme.

  # Executed before each request to the `/event_handler` route
  before '/event_handler' do
    get_payload_request(request)
    verify_webhook_signature

    # If a repository name is provided in the webhook, validate that
    # it consists only of latin alphabetic characters, `-`, and `_`.
    unless @payload['repository'].nil?
      halt 400 if (@payload['repository']['name'] =~ /[0-9A-Za-z\-\_]+/).nil?
    end

    authenticate_app
    # Authenticate the app installation in order to run API operations
    authenticate_installation(@payload)
  end

Jede dieser Hilfsmethoden wird später im Codeblock definiert, der mit beginnt. Weitere Informationen findest du unter Definieren der Hilfsmethoden.

Unter , ist der Code, der mit beginnt, eine Sicherheitsmaßnahme. Wenn durch eine Webhook-Nutzlast ein Repository-Name angegeben wird, überprüft dieser Code, ob der Repository-Name nur lateinische Buchstaben, Bindestriche und Unterstriche enthält. Dadurch wird sichergestellt, dass ein fehlerhafter Akteur nicht versucht, beliebige Befehle auszuführen oder falsche Repositorynamen einzuschleusen. Später überprüft die -Hilfsmethode im Codeblock, der mit beginnt, auch eingehende Webhooknutzlasten als zusätzliche Sicherheitsmaßnahme.

Definieren eines Routenhandlers

Im Vorlagencode ist eine leere Route enthalten. Dieser Code verarbeitet alle Anforderungen an die Route. Hier fügst du später mehr Code hinzu.

post '/event_handler' do

end

Definieren der Hilfsmethoden

Vier Hilfsmethoden werden im -Block des Vorlagencodes aufgerufen. Der -Codeblock definiert jede dieser Hilfsmethoden.

Verarbeiten der Webhooknutzlast

Mit der ersten Hilfsmethode wird die Webhooknutzlast erfasst und in das JSON-Format konvertiert. Dies vereinfacht den Zugriff auf die Daten der Nutzlast erheblich.

Überprüfen der Webhooksignatur

Die zweite Hilfsmethode führt die Überprüfung der Webhooksignatur durch, um sicherzustellen, dass das Ereignis von GitHub generiert wurde. Weitere Informationen zum Code in der -Hilfsmethode findest du unter AUTOTITLE. Wenn die Webhooks sicher sind, werden mit dieser Methode alle am Terminal eingehenden Nutzlasten protokolliert. Der Protokollierungscode ist hilfreich, damit du dich vergewissern kannst, dass der Webserver funktioniert.

Authentifizieren als GitHub App

Mit der dritten Hilfsmethode () kann sich deine GitHub App authentifizieren, sodass sie ein Installationstoken anfordern kann.

Zum Tätigen von API-Aufrufen verwendest du die Octokit-Bibliothek. Wenn du etwas Interessantes mit dieser Bibliothek tust, musst du deine GitHub App authentifizieren. Weitere Informationen zur Octokit-Bibliothek findest du in der Octokit-Dokumentation.

GitHub Apps verfügt über drei Authentifizierungsmethoden:

  • Authentifizieren als GitHub App mithilfe eines JSON-Webtokens (JWT)
  • Authentifizieren als spezifische Installation einer GitHub App mithilfe eines Installationszugriffstokens
  • Authentifizieren im Namen eines Benutzers In diesem Tutorial wird diese Authentifizierungsmethode nicht verwendet.

Im nächsten Abschnitt, Authentifizieren als Installation, erfährst du mehr über die Authentifizierung als Installation.

Die Authentifizierung als GitHub App ermöglicht dir verschiedene Aktionen:

  • Du kannst Verwaltungsinformationen auf hoher Ebene über deine GitHub App abrufen.
  • Du kannst Zugriffstoken für eine Installation der App anfordern.

Du würdest beispielsweise die Authentifizierung als GitHub App durchführen, um eine Liste der Konten (Organisationskonten und persönliche Konten) abzurufen, von denen die App installiert wurde. Mithilfe dieser Authentifizierungsmethode kannst du jedoch nicht besonders viel mit der API anfangen. Du musst eine Authentifizierung als Installation durchführen, um auf die Daten eines Repositorys zugreifen und Vorgänge im Auftrag der Installation ausführen zu können. Dazu musst du zuerst eine Authentifizierung als GitHub App durchführen, um ein Installationszugriffstoken anzufordern. Weitere Informationen finden Sie unter AUTOTITLE.

Bevor du die Octokit.rb-Bibliothek zum Tätigen von API-Aufrufen verwenden kannst, musst du einen Octokit-Client initialisieren, der mithilfe der -Hilfsmethode als GitHub App authentifiziert wurde.

# Instantiate an Octokit client authenticated as a GitHub App.
# GitHub App authentication requires that you construct a
# JWT (https://jwt.io/introduction/) signed with the app's private key,
# so GitHub can be sure that it came from the app an not altered by
# a malicious third party.
def authenticate_app
  payload = {
      # The time that this JWT was issued, _i.e._ now.
      iat: Time.now.to_i,

      # JWT expiration time (10 minute maximum)
      exp: Time.now.to_i + (10 * 60),

      # Your GitHub App's identifier number
      iss: APP_IDENTIFIER
  }

  # Cryptographically sign the JWT
  jwt = JWT.encode(payload, PRIVATE_KEY, 'RS256')

  # Create the Octokit client, using the JWT as the auth token.
  @app_client ||= Octokit::Client.new(bearer_token: jwt)
end

Vom obigen Code wird ein JSON Web Token (JWT) generiert und (zusammen mit dem privaten Schlüssel der App) zum Initialisieren des Octokit-Clients verwendet. GitHub überprüft die Authentifizierung einer Anforderung, indem das Token mit dem gespeicherten öffentlichen Schlüssel der App überprüft wird. Weitere Informationen zur Funktionsweise dieses Codes findest du unter AUTOTITLE.

Authentifizieren als Installation

Die vierte und letzte Hilfsmethode, , initialisiert einen Octokit-Client, der als Installation authentifiziert ist, mit dem du authentifizierte Aufrufe an die API tätigen kannst.

Eine Installation bezieht sich auf ein beliebiges Benutzer- oder Organisationskonto, für das die App installiert wurde. Selbst wenn jemand der Anwendung Zugriff auf mehr als ein Repository in diesem Konto gewährt, zählt dies nur als eine Installation, da sie innerhalb desselben Kontos erfolgt.

# Instantiate an Octokit client authenticated as an installation of a
# GitHub App to run API operations.
def authenticate_installation(payload)
  installation_id = payload['installation']['id']
  installation_token = @app_client.create_app_installation_access_token(installation_id)[:token]
  @installation_client = Octokit::Client.new(bearer_token: installation_token)
end

Mit der Octokit-Methode wird ein Installationstoken erstellt. Weitere Informationen findest du in der Octokit-Dokumentation unter create_installation_access_token.

Diese Methode akzeptiert zwei Argumente:

  • Installation (ganze Zahl): Die ID einer GitHub App-Installation
  • Optionen (Hash, Standardwert ist ): anpassbare Optionen

Jedes Mal, wenn eine GitHub App einen Webhook empfängt, ist ein -Objekt mit einer darin enthalten. Mit dem Client, der als GitHub App authentifiziert wurde, übergibst du diese ID an die Methode , um ein Zugriffstoken für jede einzelne Installation zu generieren. Da du keine Optionen an die Methode übergibst, werden die Optionen standardmäßig einem leeren Hash zugewiesen. Die Antwort für enthält zwei Felder: und . Der Vorlagencode wählt das Token in der Antwort aus und initialisiert einen Installationsclient.

Bei dieser Methode wird jedes Mal, wenn Ihre App eine neue Webhook-Payload empfängt, ein Client für die Installation erstellt, die das Ereignis ausgelöst hat. Mit diesem Authentifizierungsprozess kann die GitHub App für alle Installationen eines beliebigen Kontos genutzt werden.

Starten des Servers

Die App hat noch keine eigentliche Funktion, aber an diesem Punkt kannst du die App auf dem Server ausführen.

  1. Stelle in deinem Terminal sicher, dass Smee weiterhin ausgeführt wird. Weitere Informationen findest du unter Abrufen einer Webhookproxy-URL.

  2. Öffne eine neue Registerkarte in deinem Terminal und in das Verzeichnis, in dem du das Repository geklont hast, das du zuvor im Tutorial erstellt hast. Weitere Informationen finden Sie unter Create a repository to store code for your GitHub App. Der Ruby-Code in diesem Repository startet einen Sinatra-Webserver.

  3. Installiere die Abhängigkeiten, indem du die folgenden beiden Befehle nacheinander ausführst:

    Shell
    gem install bundler
    
    Shell
    bundle install
    
  4. Starte nach der Installation der Abhängigkeiten den Server, indem du den folgenden Befehl ausführst:

    Shell
    bundle exec ruby server.rb
    

    Du solltest eine Antwort wie diese erhalten:

    > == Sinatra (v2.2.3) has taken the stage on 3000 for development with backup from Puma
    > Puma starting in single mode...
    > * Puma version: 6.3.0 (ruby 3.1.2-p20) ("Mugi No Toki Itaru")
    > *  Min threads: 0
    > *  Max threads: 5
    > *  Environment: development
    > *          PID: 14915
    > * Listening on http://0.0.0.0:3000
    > Use Ctrl-C to stop
    

    Wenn ein Fehler angezeigt wird, vergewissere dich, dass du die -Datei in dem Verzeichnis erstellt hast, das enthält.

  5. Navigiere zum Testen des Servers in deinem Browser zu .

    Wenn eine Fehlerseite mit der Aufschrift „Sinatra kennt dieses Ditty nicht“ angezeigt wird, funktioniert die App wie erwartet. Zwar wird eine Fehlerseite angezeigt, aber eben eine Sinatra-Fehlerseite. Das bedeutet, dass die App wie erwartet mit dem Server verbunden ist. Diese Meldung wird angezeigt, weil Sie der App nichts anderes zum Anzeigen gegeben haben.

Testen, dass der Server deine App lauscht

Du kannst testen, ob der Server die App überwacht, indem du ein zu empfangendes Ereignis auslöst. Dazu installierst du die App in einem Testrepository, das das -Ereignis an deine App sendet. Wenn die App das Ereignis empfängt, solltest du eine Ausgabe auf der Terminalregisterkarte sehen, auf der du ausführst.

  1. Erstelle ein neues Repository zum Testen deines Tutorialcodes. Weitere Informationen finden Sie unter AUTOTITLE.

  2. Installiere GitHub App für das soeben erstellte Repository. Weitere Informationen finden Sie unter AUTOTITLE. Wähle während des Installationsvorgangs Nur Repositorys auswählen aus, und wähle das Repository aus, das du im vorherigen Schritt erstellt hast.

  3. Nachdem du auf Installieren geklickt hast, sieh dir die Ausgabe auf der Terminalregisterkarte an, auf der du ausführst. Die Ausgabe sollte folgendermaßen aussehen:

    > D, [2023-06-08T15:45:43.773077 #30488] DEBUG -- : ---- received event installation
    > D, [2023-06-08T15:45:43.773141 #30488]] DEBUG -- : ----    action created
    > 192.30.252.44 - - [08/Jun/2023:15:45:43 -0400] "POST /event_handler HTTP/1.1" 200 - 0.5390
    

    Wenn die Ausgabe wie folgt angezeigt wird, bedeutet dies, dass deine App eine Benachrichtigung erhalten hat, dass sie in deinem GitHub-Konto installiert wurde. Die App wird wie erwartet auf dem Server ausgeführt.

    Wenn diese Ausgabe nicht angezeigt wird, stellen Sie sicher, dass Smee ordnungsgemäß auf einem anderen Terminal-Tab läuft. Wenn Sie Smee neu starten müssen, beachten Sie, dass Sie auch die App deinstallieren und erneut installieren müssen, um das Ereignis erneut an Ihre App zu senden und die Ausgabe im Terminal anzuzeigen.

Wenn du dich fragst, woher die obige Terminalausgabe stammt: Sie ist im App-Vorlagencode geschrieben, den du unter dem Abschnitt "Code hinzufügen für deine GitHub App" ergänzt hast.

Teil 1: Erstellen der API für Überprüfungen

In diesem Teil fügen Sie den Code hinzu, der benötigt wird, um Webhook-Ereignisse zu empfangen, sowie um Prüfungen auszuführen und zu aktualisieren. Darüber hinaus erfährst du auch, wie Überprüfungsausführungen erstellt werden, wenn eine Überprüfung auf GitHub erneut angefordert wurde. Am Ende dieses Abschnitts kannst du den Prüflauf anzeigen, den du in einem Pull Request auf GitHub erstellt hast.

In diesem Abschnitt werden mit der Überprüfungsausführung noch keine Überprüfungen für den Code durchgeführt. Diese Funktionalität wird erst in Teil 2: Erstellen eines CI-Tests hinzugefügt.

Du solltest bereits einen Smee-Kanal konfiguriert haben, über den Webhooknutzdaten an deinen lokalen Server weitergeleitet werden. Dein Server sollte ausgeführt werden und mit der GitHub App verbunden sein, die du in einem Testrepository registriert und installiert hast.

Folgende Schritte werden in Teil 1 durchgeführt:

  1. Hinzufügen von Ereignisbehandlung
  2. Erstellen eines Prüflaufs
  3. Aktualisieren eines Prüflaufs

Schritt 1.1. Ereignisbehandlung hinzufügen

Da deine App die Ereignisse „Überprüfungssammlung“ und „Überprüfungsausführung“ abonniert hat, erhält sie nun die - und -Webhooks. GitHub sendet Webhooknutzlasten als -Anforderungen. Da du die Smee-Webhooknutzdaten an weitergeleitet hast, erhält der Server die -Anforderungsnutzdaten auf der -Route.

Öffne die -Datei, die du in Hinzufügen von Code für deine GitHub App erstellt hast, und suche nach dem folgenden Code. Im Vorlagencode ist eine leere -Route bereits enthalten. Die leere Route sieht wie folgt aus:

  post '/event_handler' do

    # ADD EVENT HANDLING HERE #

    200 # success status
  end

Füge in den Codeblock, der mit beginnt, an der Stelle, an der steht, den folgenden Code ein. Diese Route verarbeitet das -Ereignis.

Ruby
    # Get the event type from the HTTP_X_GITHUB_EVENT header
    case request.env['HTTP_X_GITHUB_EVENT']
    when 'check_suite'
      # A new check_suite has been created. Create a new check run with status queued
      if @payload['action'] == 'requested' || @payload['action'] == 'rerequested'
        create_check_run
      end
      # ADD CHECK_RUN METHOD HERE #
    end

Alle Ereignisse, die von GitHub gesendet werden, enthalten den Anforderungsheader , der den Ereignistyp in der -Anforderung angibt. Im Moment sind nur Ereignisse vom Typ von Interesse, die immer dann gesendet werden, wenn eine neue Überprüfungssammlung erstellt wird. Alle Ereignisse enthalten ein zusätzliches -Feld, das die Aktion angibt, durch die die Ereignisse ausgelöst wurden. Bei kann das -Feld , oder angeben.

Mit der Aktion wird jedes Mal, wenn Code in das Repository gepusht wird, eine Überprüfungsausführung angefordert, während mit der Aktion angefordert wird, dass du für Code, der im Repository bereits vorhanden ist, erneut eine Überprüfung ausführst. Da für die beiden Aktionen und eine Überprüfungsausführung erstellt werden muss, rufe das Hilfsprogramm auf. Lassen Sie uns diese Methode jetzt schreiben.

Schritt 1.2. Einen Prüflauf erstellen

Füge diese neue Methode als Sinatra-Hilfsprogramm hinzu, wenn sie auch von anderen Routen verwendet werden soll.

Füge in den Codeblock, der mit , wo es heißt , beginnt, den folgenden Code ein.

Ruby
    # Create a new check run with status "queued"
    def create_check_run
      @installation_client.create_check_run(
        # [String, Integer, Hash, Octokit Repository object] A GitHub repository.
        @payload['repository']['full_name'],
        # [String] The name of your check run.
        'Octo RuboCop',
        # [String] The SHA of the commit to check
        # The payload structure differs depending on whether a check run or a check suite event occurred.
        @payload['check_run'].nil? ? @payload['check_suite']['head_sha'] : @payload['check_run']['head_sha'],
        # [Hash] 'Accept' header option, to avoid a warning about the API not being ready for production use.
        accept: 'application/vnd.github+json'
      )
    end

Mit diesem Code wird der Endpunkt mithilfe der Octokit-Methode create_check_run aufgerufen. Weitere Informationen zum Endpunkt findest du unter AUTOTITLE.

Zum Erstellen einer Überprüfungsausführung sind nur zwei Parameter erforderlich: und . In diesem Code nennen wir die Überprüfungsausführung „Octo RuboCop“, da wir RuboCop verwenden, um den CI-Test später im Tutorial zu implementieren. Du kannst jedoch einen beliebigen Namen für die Überprüfung auswählen. Weitere Informationen zu RuboCop findest du in der RuboCop-Dokumentation.

Als Nächstes gibst du die für die grundlegende Funktionalität erforderlichen Parameter an. Du wirst die Überprüfungsausführung jedoch später aktualisieren, wenn du weitere Informationen zur Überprüfungsausführung sammelst. Standardmäßig legt GitHub den auf fest.

Da in GitHub für eine bestimmte Commit-SHA-Komponente eine Überprüfungsausführung erstellt wird, ist ein erforderlicher Parameter. Sie finden die Commit-SHA im Webhook-Payload. Auch wenn du im Moment nur eine Überprüfungsausführung für das Ereignis erstellst, ist es dennoch gut zu wissen, dass der Parameter sowohl im Objekt als auch im Objekt in den Ereignisnutzdaten enthalten ist.

Der obige Code verwendet einen ternären Operator, der wie eine Anweisung funktioniert, um zu überprüfen, ob die Nutzdaten ein Objekt enthalten. Wenn das Objekt enthalten ist, wird der Parameter über das Objekt gelesen, wenn nicht, über das Objekt .

Testen des Codes

In den folgenden Schritten wird gezeigt, wie du testen kannst, ob der Code funktioniert und ob er erfolgreich eine neue Überprüfungsausführung erstellt.

  1. Führe den folgenden Befehl aus, um den Server über dein Terminal neu zu starten. Wenn der Server bereits ausgeführt wird, gib zuerst in dein Terminal ein, um den Server zu beenden, und führe dann den folgenden Befehl aus, um den Server erneut zu starten.

    Shell
    ruby server.rb
    
  2. Erstelle einen Pull Request im Testrepository, das du unter Testen, dass der Server auf deine App lauscht erstellt hast. Dies ist das Repository, auf das du der App Zugriff gewährt hast.

  3. Navigiere im gerade erstellten Pull Request zur Registerkarte Überprüfungen. Dann sollte eine Überprüfungsausführung mit dem Namen „Octo RuboCop“ oder dem Namen angezeigt werden, den du zuvor für die Überprüfung ausgewählt hast.

Wenn auf der Registerkarte Überprüfungen andere Apps angezeigt werden, bedeutet das, dass Sie weitere Apps in Ihrem Repository installiert haben, die Lese- und Schreibzugriff auf Prüfungen haben und für Check-Suite- sowie Check-Run-Ereignisse abonniert sind. Dies kann auch bedeuten, dass du GitHub Actions-Workflows im Repository hast, die durch das - oder -Ereignis ausgelöst werden.

Bisher hast du GitHub angewiesen, eine Überprüfungsausführung zu erstellen. Der Status der Überprüfungsausführung im Pull Request wird in die Warteschlange gesetzt und mit einem gelben Symbol versehen. Im nächsten Schritt wartest du, bis GitHub die Überprüfungsausführung erstellt und den Status aktualisiert hat.

Schritt 1.3. Aktualisieren eines Prüflaufs

Wenn deine -Methode ausgeführt wird, wird GitHub aufgefordert, eine neue Überprüfungsausführung zu erstellen. Sobald GitHub den Prüfungsdurchlauf erstellt hat, erhältst du das Webhook-Ereignis mit der zugehörigen Aktion. Dieses Ereignis ist dein Signal, mit der Ausführung der Überprüfung zu beginnen.

Als Nächstes aktualisierst du den Ereignishandler, um nach der Aktion zu suchen. Beim Aktualisieren des Ereignishandlers kannst du für die Aktion eine Bedingung hinzufügen. Wenn ein einzelner Test in GitHub durch einen Klick auf die Schaltfläche „Erneut ausführen“ erneut ausgeführt wird, wird in GitHub das Ereignis der Überprüfungsausführung an deine App gesendet. Wenn eine Überprüfungsausführung den Status aufweist, beginne von vorn, und erstelle eine neue Überprüfungsausführung. Dazu fügen Sie eine Bedingung für das Ereignis in die Route ein.

Füge in den Codeblock, der mit beginnt, an der Stelle, an der steht, den folgenden Code ein:

Ruby
    when 'check_run'
      # Check that the event is being sent to this app
      if @payload['check_run']['app']['id'].to_s === APP_IDENTIFIER
        case @payload['action']
        when 'created'
          initiate_check_run
        when 'rerequested'
          create_check_run
        # ADD REQUESTED_ACTION METHOD HERE #
        end
      end

In GitHub werden alle Ereignisse für Check-Läufe an alle Apps gesendet, die in einem Repository mit den erforderlichen Prüfberechtigungen installiert sind. Das bedeutet, dass deine App Überprüfungsausführungen empfängt, die von anderen Apps erstellt wurden. Eine Überprüfungsausführung mit dem Status unterscheidet sich ein wenig von einer Überprüfungssammlung mit dem Status oder , die in GitHub nur an Apps gesendet werden, die aufgefordert sind, eine Überprüfung auszuführen. Mit dem obigen Code wird nach der Anwendungs-ID der Überprüfungsausführung gesucht. Dadurch werden alle Überprüfungsausführungen für andere Apps im Repository herausgefiltert.

Als Nächstes schreibst du die -Methode, mit der du den Ausführungsstatus aktualisierst und den Start deines CI-Tests vorbereitest.

In diesem Abschnitt wird der CI-Test noch nicht gestartet. Vielmehr wird hier der Status der Überprüfungsausführung von in und anschließend von in geändert, um den gesamten Ablauf einer Überprüfungsausführung anzuzeigen. Füge in Teil 2: Erstellen des CI-Tests den Code hinzu, mit dem der CI-Test tatsächlich durchgeführt wird.

Zunächst erstellst du die Methode und aktualisierst den Status der Überprüfungsausführung.

Füge in den Codeblock, der mit , wo es heißt , beginnt, den folgenden Code ein.

Ruby
    # Start the CI process
    def initiate_check_run
      # Once the check run is created, you'll update the status of the check run
      # to 'in_progress' and run the CI process. When the CI finishes, you'll
      # update the check run status to 'completed' and add the CI results.

      @installation_client.update_check_run(
        @payload['repository']['full_name'],
        @payload['check_run']['id'],
        status: 'in_progress',
        accept: 'application/vnd.github+json'
      )

      # ***** RUN A CI TEST *****

      # Mark the check run as complete!
      @installation_client.update_check_run(
        @payload['repository']['full_name'],
        @payload['check_run']['id'],
        status: 'completed',
        conclusion: 'success',
        accept: 'application/vnd.github+json'
      )

    end

Mit dem obigen Code wird der Endpunkt mithilfe der Octokit-Methode aufgerufen und aktualisiert die bereits erstellte Überprüfungsausführung. Weitere Informationen zum Endpunkt findest du unter AUTOTITLE.

Und so funktioniert dieser Code. Zunächst wird der Status der Überprüfungsausführung in geändert und die -Zeit auf die aktuelle Uhrzeit festgelegt. In Teil 2 dieses Tutorials fügst du Code hinzu, mit dem unter ein echter CI-Test gestartet wird. Im Moment lässt du diesen Abschnitt als Platzhalter stehen, damit der nachfolgende Code lediglich simuliert, dass der CI-Prozess erfolgreich verläuft und alle Tests bestanden werden. Abschließend wird mit dem Code der Status der Überprüfungsausführung in geändert.

Wenn Sie die REST-API verwenden, um den Status eines Prüflaufs bereitzustellen, sind die Parameter und erforderlich. Unter wird das Ergebnis einer Überprüfungsausführung zusammengefasst, die den Status , , , , , oder aufweisen kann. Lege das Ergebnis („conclusion“) auf , die -Zeit auf die aktuelle Uhrzeit und den Status auf fest.

Du kannst darüber hinaus noch weitere Informationen zur Funktionsweise der Überprüfung bereitstellen. Das wird jedoch erst im nächsten Abschnitt behandelt.

Testen des Codes

In den folgenden Schritten wird gezeigt, wie du testen kannst, ob der Code und die neu erstellte Schaltfläche „Alle erneut ausführen“ funktionieren.

  1. Führe den folgenden Befehl aus, um den Server über dein Terminal neu zu starten. Wenn der Server bereits ausgeführt wird, gib zuerst in dein Terminal ein, um den Server zu beenden, und führe dann den folgenden Befehl aus, um den Server erneut zu starten.

    Shell
    ruby server.rb
    
  2. Erstelle einen Pull Request im Testrepository, das du unter Testen, dass der Server auf deine App lauscht erstellt hast. Dies ist das Repository, auf das du der App Zugriff gewährt hast.

  3. Navigiere im gerade erstellten Pull Request zur Registerkarte Überprüfungen. Die Schaltfläche „Alle erneut ausführen“ sollte angezeigt werden.

  4. Klicke in der oberen rechten Ecke auf die Schaltfläche „Alle erneut ausführen“. Der Test sollte erneut ausgeführt werden und mit enden.

Teil 2: Erstellen eines CI-Tests

Nachdem du die Schnittstelle zum Empfangen von API-Ereignissen und Überprüfungsausführungen erstellt hast, kannst du eine Überprüfungsausführung erstellen, mit der ein CI-Test implementiert wird.

RuboCop ist ein Ruby-Code-Linter und -Formatierer. Damit wird Ruby-Code überprüft, um sicherzustellen, dass er dem Ruby-Styleguide entspricht. Weitere Informationen findest du in der RuboCop-Dokumentation.

RuboCop erfüllt im Wesentlichen drei Funktionen:

  • Linting zur Überprüfung des Code-Stils
  • Codeformatierung
  • Ersetzen der nativen Ruby-Lintfunktionen mithilfe von

Mit deiner App wird RuboCop auf dem CI-Server ausgeführt, und es werden Überprüfungsausführungen (in diesem Fall CI-Tests) erstellt, mit denen die Ergebnisse angezeigt werden, die von RuboCop an GitHub gesendet werden.

Mit der REST-API kannst du umfangreiche Informationen zu den einzelnen Überprüfungsausführungen wie Status, Bilder, Zusammenfassungen, Anmerkungen und angeforderte Aktionen anzeigen.

Anmerkungen sind Informationen zu bestimmten Codezeilen in einem Repository. Mit einer Anmerkung kannst du die Teile des Codes genau festlegen und visualisieren, für die zusätzliche Informationen angezeigt werden sollen. Du kannst diese Informationen beispielsweise als Kommentar, Fehler oder Warnung in einer bestimmten Codezeile anzeigen. In diesem Tutorial werden Anmerkungen zum Visualisieren von RuboCop-Fehlern verwendet.

Um von angeforderten Aktionen zu profitieren, können App-Entwicklerinnen Schaltflächen auf der Registerkarte Prüfungen in Pull Requests erstellen. Wenn jemand auf eine dieser Schaltflächen klickt, wird ein Klickereignis an die GitHub App gesendet. Die von der App verwendete Aktion kann vom App-Entwickler beliebig konfiguriert werden. In diesem Tutorial erfährst du, wie eine Schaltfläche hinzugefügt wird, mit der Benutzerinnen anfordern können, dass mit RuboCop alle gefundenen Fehler behoben werden. In RuboCop wird das automatische Beheben von Fehlern mithilfe einer Befehlszeilenoption unterstützt, und du konfigurierst es so, dass diese Option genutzt werden kann.

Folgende Schritte werden in diesem Abschnitt durchgeführt:

  1. Hinzufügen einer Ruby-Datei
  2. Zulassen, dass RuboCop das Testrepository klonen kann
  3. RuboCop ausführen
  4. RuboCop-Fehler sammeln
  5. Aktualisieren Sie den Prüflauf mit CI-Testergebnissen
  6. Automatisches Beheben von RuboCop-Fehlern

Schritt 2.1. Hinzufügen einer Ruby-Datei

Du kannst einzelne Dateien oder ganze Verzeichnisse zum Überprüfen durch RuboCop übergeben. In diesem Tutorial führst du RuboCop in einem ganzen Verzeichnis aus. RuboCop überprüft nur Ruby-Code. Um deine GitHub App zu testen, musst du in deinem Repository eine Ruby-Datei hinzufügen, die Fehler enthält, damit RuboCop sie finden kann. Nachdem du deinem Repository die folgende Ruby-Datei hinzugefügt hast, aktualisiere deine CI-Überprüfung, um RuboCop für den Code auszuführen.

  1. Navigiere zum Testrepository, das du unter Testen, dass der Server auf deine App lauscht erstellt hast. Dies ist das Repository, auf das du der App Zugriff gewährt hast.

  2. Erstelle eine neue Datei mit dem Namen . Weitere Informationen finden Sie unter AUTOTITLE.

  3. Füge folgenden Inhalt hinzu:

    Ruby
    # frozen_string_literal: true
    
    # The Octocat class tells you about different breeds of Octocat
    class Octocat
      def initialize(name, *breeds)
        # Instance variables
        @name = name
        @breeds = breeds
      end
    
      def display
        breed = @breeds.join("-")
    
        puts "I am of #{breed} breed, and my name is #{@name}."
      end
    end
    
    m = Octocat.new("Mona", "cat", "octopus")
    m.display
    
  4. Wenn du die Datei lokal erstellt hast, stelle sicher, dass du einen Commit ausführst und die Datei auf GitHub in dein Repository pushst.

Schritt 2.2. Zulassen, dass RuboCop das Testrepository klonen kann

RuboCop ist als Befehlszeilen-Hilfsprogramm verfügbar. Wenn du also RuboCop in einem Repository ausführen möchtest, musst deine GitHub App eine lokale Kopie des Repositorys auf den CI-Server klonen, damit RuboCop die Dateien analysieren kann. Dazu muss dein Code Git-Vorgänge ausführen können, und deine GitHub App muss über die richtigen Berechtigungen zum Klonen eines Repositorys verfügen.

Zulassen von Git-Vorgängen

Zum Ausführen von Git-Vorgängen in deiner Ruby-App kannst du das Gem ruby-git verwenden. Die während der Einrichtung erstellte enthält bereits das Gem „ruby-git“. Du hast es beim Ausführen von in „Server starten“ installiert.

Füge nun oben in deiner -Datei unter den anderen -Elementen den folgenden Code hinzu:

Ruby
require 'git'

Aktualisieren deiner App-Berechtigungen

Als Nächstes musst du deine GitHub App-Berechtigungen aktualisieren. Zum Klonen eines Repositorys benötigt die App Leseberechtigungen für „Inhalte“. Später in diesem Tutorial ist die Schreibberechtigung erforderlich, um Inhalte per Push an GitHub zu übertragen. So aktualisierst du die Berechtigungen deiner App:

  1. Wähle auf der Seite der App-Einstellungen die App aus, und klicke in der Seitenleiste auf Berechtigungen und Ereignisse.
  2. Wähle unter „Repositoryberechtigungen“ neben „Inhalte“ die Option Lesen & Schreiben aus.
  3. Klicke unten auf der Seite auf Änderungen speichern.
  4. Wenn du die App in deinem Konto installiert hast, überprüfe deine E-Mail, und folge dem Link, um die neuen Berechtigungen zu akzeptieren. Wenn du die Berechtigungen oder Webhooks deiner App änderst, müssen Benutzer, die die App installiert haben (auch du selbst), die neuen Berechtigungen akzeptieren, bevor die Änderungen wirksam werden. Du kannst die neuen Berechtigungen auch akzeptieren, indem du zur Installationsseite navigierst. Unter dem App-Namen wird ein Link angezeigt, der dich darüber informiert, dass die App andere Berechtigungen erfordert. Klicken Sie zunächst auf Anforderung überprüfen und dann auf Neue Berechtigungen akzeptieren.

Hinzufügen von Code zum Klonen eines Repositorys

Wenn ein Repository geklont werden soll, verwendet der Code die Berechtigungen deiner GitHub App und das Octokit-SDK, um ein Installationstoken für deine App () zu erstellen und es im folgenden Klonbefehl zu verwenden:

git clone https://x-access-token:TOKEN@github.com/OWNER/REPO.git

Mit dem obigen Befehl wird ein Repository über HTTPS geklont. Dazu muss der vollständige Repositoryname angegeben werden, der den Repositorybesitzer (Benutzer oder Organisation) und den Repositorynamen umfasst. Der vollständige Name des Repositorys octocat Hello-World lautet beispielsweise .

Öffne deine -Datei. Füge in den Codeblock, der mit , wo es heißt , beginnt, den folgenden Code ein.

Ruby
    # Clones the repository to the current working directory, updates the
    # contents using Git pull, and checks out the ref.
    #
    # full_repo_name  - The owner and repo. Ex: octocat/hello-world
    # repository      - The repository name
    # ref             - The branch, commit SHA, or tag to check out
    def clone_repository(full_repo_name, repository, ref)
      @git = Git.clone("https://x-access-token:#{@installation_token.to_s}@github.com/#{full_repo_name}.git", repository)
      pwd = Dir.getwd()
      Dir.chdir(repository)
      @git.pull
      @git.checkout(ref)
      Dir.chdir(pwd)
    end

Im obigen Code wird das -Gem zum Klonen des Repositorys mithilfe des Installationstokens der App verwendet. Dadurch wird der Code im selben Verzeichnis wie . geklont. Zum Ausführen von Git-Befehlen im Repository muss der Code in das Repositoryverzeichnis wechseln. Vor dem Wechsel des Verzeichnisses speichert der Code das aktuelle Arbeitsverzeichnis in einer Variablen (), um sich den Rückkehrpunkt zu merken, bevor die Methode beendet wird.

Mit dem Code werden die aktuellen Änderungen aus dem Repositoryverzeichnis abgerufen () und zusammengeführt und die spezifische Git-Referenz ausgecheckt (). Der Code für all diese Aufgaben lässt sich gut in einer eigenen Methode unterbringen. Zum Ausführen dieser Vorgänge muss für die Methode der Name und der vollständige Name des Repositorys und der Referenz angegeben werden, die ausgecheckt werden soll. Bei der Referenz kann es sich um eine Commit-SHA-Komponente, einen Branch oder ein Tag handeln. Wenn dies abgeschlossen ist, ändert der Code das Verzeichnis wieder in das ursprüngliche Arbeitsverzeichnis ().

Nun verfügst du über eine Methode, mit der ein Repository geklont und eine Referenz ausgecheckt wird. Als Nächstes musst du Code hinzufügen, um die erforderlichen Eingabeparameter abzurufen und die neue -Methode aufzurufen.

In den Codeblock, der mit beginnt, füge in der Hilfsmethode an der Stelle, an der es heißt , den folgenden Code ein:

Ruby
    full_repo_name = @payload['repository']['full_name']
    repository     = @payload['repository']['name']
    head_sha       = @payload['check_run']['head_sha']

    clone_repository(full_repo_name, repository, head_sha)

    # ADD CODE HERE TO RUN RUBOCOP #

Der obige Code ruft den vollständigen Repositorynamen und den Head-SHA-Wert des Commits aus dem Webhook-Payload ab.

Schritt 2.3. RuboCop ausführen

Bisher klont dein Code das Repository und erstellt Überprüfungsausführungen mit deinem CI-Server. Jetzt geht es an die Feinheiten des RuboCop-Linters und der Überprüfungsanmerkungen.

Zunächst fügst du Code zum Ausführen von RuboCop hinzu und speicherst die Formatcodefehler im JSON-Format.

Suche im Codeblock, der mit einem bestimmten Zeichen beginnt, nach der Hilfsmethode. Füge in dieser Hilfsmethode unter , an der Stelle, an der steht, den folgenden Code hinzu:

Ruby
        # Run RuboCop on all files in the repository
        @report = `rubocop '#{repository}' --format json`
        logger.debug @report
        `rm -rf #{repository}`
        @output = JSON.parse @report

        # ADD ANNOTATIONS CODE HERE #

Mit dem obigen Code wird RuboCop für alle Dateien im Verzeichnis des Repositorys ausgeführt. Mit der Option kann eine Kopie der Lintingergebnisse in einem Format gespeichert werden, das vom Computer analysiert werden kann. Weitere Informationen und ein Beispiel für das JSON-Format findest du unter JSON-Formatierer in der RuboCop-Dokumentation. Dieser Code parst auch den JSON-Code, sodass du mithilfe der -Variablen ganz einfach auf die Schlüssel und Werte in deiner GitHub App zugreifen kannst.

Nachdem du RuboCop ausgeführt und die Lintingergebnisse gespeichert hast, führt dieser Code den Befehl aus, um den Checkout des Repositorys zu entfernen. Da mit dem Code die RuboCop-Ergebnisse in einer -Variablen gespeichert werden, kann das Auschecken des Repositorys problemlos übersprungen werden.

Der -Befehl kann nicht rückgängig gemacht werden. Um die Sicherheit deiner App zu gewährleisten, überprüft der Code in diesem Tutorial eingehende Webhooks auf eingeschleuste bösartige Befehle, die dazu verwendet werden könnten, ein anderes Verzeichnis zu entfernen, als von deiner App beabsichtigt. Zum Beispiel würde deine App das Stammverzeichnis entfernen, wenn ein böswilliger Akteur einen Webhook mit dem Namen des Repositorys sendet. Die -Methode überprüft den Absender des Webhooks. Der -Ereignishandler überprüft auch, ob der Repositoryname gültig ist. Weitere Informationen findest du unter Definieren eines -Filters.

Testen des Codes

Die folgenden Schritte zeigen dir, wie du testen kannst, ob der Code funktioniert und wie du die von RuboCop gemeldeten Fehler anzeigen kannst.

  1. Führe den folgenden Befehl aus, um den Server über dein Terminal neu zu starten. Wenn der Server bereits ausgeführt wird, gib zuerst in dein Terminal ein, um den Server zu beenden, und führe dann den folgenden Befehl aus, um den Server erneut zu starten.

    Shell
    ruby server.rb
    
  2. Erstelle im Repository, in dem du die -Datei hinzugefügt hast, einen neuen Pull Request.

  3. Auf der Terminalregisterkarte, auf der der Server ausgeführt wird, sollte die Debugausgabe mit Lintingfehlern angezeigt werden. Die Lintingfehler werden ohne Formatierung ausgegeben. Du kannst deine Debugausgabe kopieren und in ein Webtool wie den JSON-Formatierer einfügen, um deine JSON-Ausgabe wie im folgenden Beispiel zu formatieren:

    {
      "metadata": {
        "rubocop_version": "0.60.0",
        "ruby_engine": "ruby",
        "ruby_version": "2.3.7",
        "ruby_patchlevel": "456",
        "ruby_platform": "universal.x86_64-darwin18"
      },
      "files": [
        {
          "path": "Octocat-breeds/octocat.rb",
          "offenses": [
            {
              "severity": "convention",
              "message": "Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.",
              "cop_name": "Style/StringLiterals",
              "corrected": false,
              "location": {
                "start_line": 17,
                "start_column": 17,
                "last_line": 17,
                "last_column": 22,
                "length": 6,
                "line": 17,
                "column": 17
              }
            },
            {
              "severity": "convention",
              "message": "Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.",
              "cop_name": "Style/StringLiterals",
              "corrected": false,
              "location": {
                "start_line": 17,
                "start_column": 25,
                "last_line": 17,
                "last_column": 29,
                "length": 5,
                "line": 17,
                "column": 25
              }
            }
          ]
        }
      ],
      "summary": {
        "offense_count": 2,
        "target_file_count": 1,
        "inspected_file_count": 1
      }
    }
    

Schritt 2.4. RuboCop-Fehler sammeln

Die -Variable enthält die analysierten JSON-Ergebnisse des RuboCop-Berichts. Wie in der Beispielausgabe im vorigen Schritt gezeigt, enthalten die Ergebnisse den Abschnitt , mit dem dein Code schnell ermitteln kann, ob Fehler vorhanden sind. Mit dem folgenden Code wird das Ergebnis der Überprüfungsausführung auf festgelegt, wenn keine Fehler gemeldet werden. RuboCop meldet Fehler für jede Datei im -Array. Wenn Fehler vorhanden sind, musst du einige Daten aus dem Dateiobjekt extrahieren.

Mit den REST-API-Endpunkten zum Verwalten von Überprüfungsausführungen kannst du Anmerkungen für bestimmte Codezeilen erstellen. Wenn du eine Überprüfungsausführung erstellst oder aktualisierst, kannst du Anmerkungen hinzufügen. In diesem Tutorial aktualisieren Sie den Prüfablauf mit Anmerkungen, indem Sie den Endpunkt verwenden. Weitere Informationen zum Endpunkt findest du unter AUTOTITLE.

Bei der API ist die Anzahl der Anmerkungen auf maximal 50 pro Anforderung begrenzt. Wenn du mehr als 50 Anmerkungen erstellen möchtest, musst du mehrere Anforderungen für den Endpunkt „Update a check run“ erstellen. Um beispielsweise 105 Anmerkungen zu erstellen, musst du drei separate Anforderungen an die API stellen. Dabei umfassen die ersten beiden Anforderungen jeweils 50 Anmerkungen, während die dritte Anforderung die fünf verbleibenden Anmerkungen enthält. Jedes Mal, wenn du die Überprüfungsausführung aktualisierst, werden an die für die Überprüfungsausführung bereits vorhandene Liste mit Anmerkungen weitere Anmerkungen angefügt.

Für eine Überprüfungsausführung müssen Anmerkungen in Form von Objektarrays vorliegen. Jedes Anmerkungsobjekt muss , , , und enthalten. RuboCop stellt auch und bereit, sodass du diese optionalen Parameter in die Anmerkung einschließen kannst. In Anmerkungen dürfen die Parameter und nur in einer Zeile verwendet werden. Weitere Informationen finden Sie im Objekt unter AUTOTITLE.

Nun fügst du Code hinzu, um die erforderlichen Informationen aus RuboCop zu extrahieren, die zum Erstellen jeder Anmerkung erforderlich sind.

Füge unter dem Code, den du im vorherigen Schritt hinzugefügt hast, an der Stelle, wo steht, den folgenden Code hinzu:

Ruby
    annotations = []
    # You can create a maximum of 50 annotations per request to the Checks
    # API. To add more than 50 annotations, use the "Update a check run" API
    # endpoint. This example code limits the number of annotations to 50.
    # See /rest/reference/checks#update-a-check-run
    # for details.
    max_annotations = 50

    # RuboCop reports the number of errors found in "offense_count"
    if @output['summary']['offense_count'] == 0
      conclusion = 'success'
    else
      conclusion = 'neutral'
      @output['files'].each do |file|

        # Only parse offenses for files in this app's repository
        file_path = file['path'].gsub(/#{repository}\//,'')
        annotation_level = 'notice'

        # Parse each offense to get details and location
        file['offenses'].each do |offense|
          # Limit the number of annotations to 50
          next if max_annotations == 0
          max_annotations -= 1

          start_line   = offense['location']['start_line']
          end_line     = offense['location']['last_line']
          start_column = offense['location']['start_column']
          end_column   = offense['location']['last_column']
          message      = offense['message']

          # Create a new annotation for each error
          annotation = {
            path: file_path,
            start_line: start_line,
            end_line: end_line,
            start_column: start_column,
            end_column: end_column,
            annotation_level: annotation_level,
            message: message
          }
          # Annotations only support start and end columns on the same line
          if start_line == end_line
            annotation.merge({start_column: start_column, end_column: end_column})
          end

          annotations.push(annotation)
        end
      end
    end

    # ADD CODE HERE TO UPDATE CHECK RUN SUMMARY #

Mit diesem Code wird die Gesamtzahl der Anmerkungen auf 50 beschränkt. Du kannst diesen Code jedoch ändern, sodass die Überprüfungsausführung für alle Batches mit 50 Anmerkungen aktualisiert wird. Der obige Code enthält die Variable, die den Grenzwert auf 50 festlegt, welcher in der Schleife verwendet wird, die durch die Verstöße iteriert.

Wenn null ist, ist der CI-Test ein . Wenn Fehler vorhanden sind, wird das Ergebnis vom Code auf festgelegt, um die strikte Erzwingung von Fehlern über Code-Linter zu verhindern. Du kannst das Ergebnis jedoch in ändern, wenn du sicherstellen möchtest, dass bei der Überprüfungssammlung ein Fehler auftritt, wenn Lintingfehler vorhanden sind.

Wenn Fehler gemeldet werden, iteriert der obige Code durch das Array im RuboCop-Bericht. Für jede Datei wird der Dateipfad extrahiert und die Anmerkungsebene auf festgelegt. Du kannst noch einen Schritt weitergehen und für jeden RuboCop-Cop-Typ eine Warnstufe festlegen. Damit dieses Tutorial jedoch nicht zu kompliziert wird, werden alle Fehler auf ein bestimmtes Niveau festgelegt.

Dieser Code durchläuft darüber hinaus alle Fehler im -Array und erfasst den Ort der Verletzung und die Fehlermeldung. Nach dem Extrahieren der erforderlichen Informationen erstellt der Code eine Anmerkung für jeden Fehler und speichert sie im -Array. Weil Annotationen nur Start- und Endspalten innerhalb derselben Zeile unterstützen, werden die Attribute nur dann zum Objekt hinzugefügt, wenn die Start- und Endzeilenwerte identisch sind.

Dieser Code erstellt noch keine Anmerkung für den Prüflauf. Du wirst diesen Code im nächsten Abschnitt hinzufügen.

Schritt 2.5. Aktualisieren Sie den Prüflauf mit CI-Testergebnissen

Alle Überprüfungsausführungen in GitHub enthalten ein -Objekt, das die Parameter , , , und enthält. und sind die einzigen Parameter, die für das -Objekt erforderlich sind. Diese allein bieten jedoch nicht viele Details. Daher werden in diesem Tutorial auch die Parameter und hinzugefügt.

Für den Parameter werden in diesem Beispiel Zusammenfassungsinformationen von RuboCop verwendet. Zudem wird die Ausgabe durch Hinzufügen einiger neuer Zeilen () formatiert. Alles, was du dem Parameter hinzufügst, kannst du anpassen. In diesem Beispiel wird der Parameter jedoch auf die RuboCop-Version festgelegt. Der folgende Code legt und fest.

Füge unter dem Code, den du im vorherigen Schritt hinzugefügt hast, an der Stelle, wo steht, den folgenden Code hinzu:

Ruby
        # Updated check run summary and text parameters
        summary = "Octo RuboCop summary\n-Offense count: #{@output['summary']['offense_count']}\n-File count: #{@output['summary']['target_file_count']}\n-Target file count: #{@output['summary']['inspected_file_count']}"
        text = "Octo RuboCop version: #{@output['metadata']['rubocop_version']}"

Nun sollte dein Code alle Informationen enthalten, die er zum Aktualisieren der Überprüfungsausführung benötigt. In Schritt 1.3: Aktualisieren einer Überprüfungsausführung hast du Code hinzugefügt, um den Status der Überprüfungsausführung auf festzulegen. Du musst diesen Code aktualisieren, damit die -Variable verwendet wird, die du basierend auf den RuboCop-Ergebnissen (auf oder ) festgelegt hast. Hier siehst du den Code, den du deiner -Datei zuvor hinzugefügt hast:

# Mark the check run as complete!
@installation_client.update_check_run(
  @payload['repository']['full_name'],
  @payload['check_run']['id'],
  status: 'completed',
  conclusion: 'success',
  accept: 'application/vnd.github+json'
)

Ersetze den Code durch den folgenden Code:

Ruby
        # Mark the check run as complete! And if there are warnings, share them.
        @installation_client.update_check_run(
          @payload['repository']['full_name'],
          @payload['check_run']['id'],
          status: 'completed',
          conclusion: conclusion,
          output: {
            title: 'Octo RuboCop',
            summary: summary,
            text: text,
            annotations: annotations
          },
          actions: [{
            label: 'Fix this',
            description: 'Automatically fix all linter notices.',
            identifier: 'fix_rubocop_notices'
          }],
          accept: 'application/vnd.github+json'
        )

Nachdem dein Code basierend auf dem Status des CI-Tests ein Ergebnis festgelegt und die Ausgabe aus den RuboCop-Ergebnissen hinzugefügt hat, hast du einen CI-Test erstellt.

Mit dem obigen Code wird deinem CI-Server das Feature „Angeforderte Aktionen“ über das -Objekt hinzugefügt. Weitere Informationen finden Sie unter Request weitere Aktionen aus einer Überprüfungsausführung. Mit angeforderten Aktionen wird auf der Registerkarte Überprüfungen auf GitHub eine Schaltfläche hinzugefügt, über die angefordert werden kann, dass mit der Überprüfungsausführung eine weitere Aktion durchgeführt wird. Diese zusätzliche Aktion kann von deiner App umfassend konfiguriert werden. Da RuboCop beispielsweise über ein Feature verfügt, um die im Ruby-Code gefundenen Fehler automatisch zu beheben, kann dein CI-Server eine Schaltfläche für angeforderte Aktionen enthalten, damit Benutzer*innen automatische Fehlerkorrekturen anfordern können. Wenn ein Benutzer auf die Schaltfläche klickt, empfängt die App das -Ereignis mit einer -Aktion. Jede angeforderte Aktion weist den Parameter auf, der von der App verwendet wird, um zu ermitteln, auf welche Schaltfläche geklickt wurde.

Mit dem obigen Code werden noch keine RuboCop-Fehler automatisch behoben. Du fügst dies später im Tutorial hinzu.

Testen des Codes

Die folgenden Schritte zeigen dir, wie du testen kannst, ob der Code funktioniert und wie du den gerade erstellten CI-Test anzeigen kannst.

  1. Führe den folgenden Befehl aus, um den Server über dein Terminal neu zu starten. Wenn der Server bereits ausgeführt wird, gib zuerst in dein Terminal ein, um den Server zu beenden, und führe dann den folgenden Befehl aus, um den Server erneut zu starten.

    Shell
    ruby server.rb
    
  2. Erstelle im Repository, in dem du die -Datei hinzugefügt hast, einen neuen Pull Request.

  3. Navigiere im soeben erstellten Pull Request zur Registerkarte Überprüfungen. Für jeden Fehler, den RuboCop gefunden hat, sollten Anmerkungen angezeigt werden. Beachte auch die Schaltfläche „Problem beheben“, die du erstellt hast, indem du eine angeforderte Aktion hinzugefügt hast.

Schritt 2.6. Automatisches Beheben von RuboCop-Fehlern

Bisher hast du einen CI-Test erstellt. In diesem Abschnitt füge ein weiteres Feature hinzu, das RuboCop verwendet, um die gefundenen Fehler automatisch zu beheben. Du hast die Schaltfläche „Fix this“ bereits in Schritt 2.5 hinzugefügt. Aktualisiere den Überprüfungslauf mit den CI-Testergebnissen. Im Folgenden füge den Code hinzu, mit dem das Ereignis der Überprüfungsausführung behandelt wird, das beim Klicken auf die Schaltfläche „Problem beheben“ ausgelöst wird.

Das RuboCop-Tool enthält die Befehlszeilenoption zum automatischen Beheben von gefundenen Fehlern. Weitere Informationen findest du in der RuboCop-Dokumentation unter Autokorrektur von Verstößen. Wenn du das Feature verwendest, werden die Updates auf die lokalen Dateien auf dem Server angewendet. Du musst die Änderungen an GitHub pushen, nachdem RuboCop die Korrekturen vorgenommen hat.

Zum Pushen an ein Repository muss deine App über Schreibberechtigungen für „Inhalte“ in einem Repository verfügen. Du hast diese Berechtigung bereits in „Schritt 2.2.: RuboCop das Klonen des Test-Repositorys erlauben“ auf „Lesen und Schreiben“ festgelegt.

Damit Dateien committet werden können, muss Git wissen, welcher Benutzername und welche E-Mail-Adresse mit dem Commit verknüpft werden muss. Als Nächstes fügst du Umgebungsvariablen hinzu, um den Namen und die E-Mail-Adresse zu speichern, die deine App beim Erstellen von Git-Commits verwendet.

  1. Öffne die zuvor in diesem Tutorial erstellte -Datei.

  2. Füge deiner -Datei die folgenden Umgebungsvariablen hinzu. Ersetze durch den Namen deiner App und durch alle E-Mails, die du für dieses Beispiel verwenden möchtest.

    Shell
    GITHUB_APP_USER_NAME="APP_NAME"
    GITHUB_APP_USER_EMAIL="EMAIL_ADDRESS"
    

Als Nächstes musst du Code hinzufügen, um die Umgebungsvariablen zu lesen und die Git-Konfiguration festzulegen. Diesen Code füge in Kürze hinzu.

Wenn eine Benutzerin auf die Schaltfläche „Problem beheben“ klickt, empfängt deine App den Webhook der Überprüfungsausführung mit dem Aktionstyp .

In „Schritt 1.3. Überprüfungsausführung aktualisieren“ hast du den in deiner -Datei aktualisiert, um nach Aktionen im Ereignis zu suchen. Du verfügst bereits über eine CASE-Anweisung zur Behandlung der Aktionstypen und :

when 'check_run'
  # Check that the event is being sent to this app
  if @payload['check_run']['app']['id'].to_s === APP_IDENTIFIER
    case @payload['action']
    when 'created'
      initiate_check_run
    when 'rerequested'
      create_check_run
    # ADD REQUESTED_ACTION METHOD HERE #
  end
end

Füge nach dem Fall , wo steht, den folgenden Code ein:

Ruby
    when 'requested_action'
      take_requested_action

Mit diesem Code wird eine neue Methode aufgerufen, mit der alle -Ereignisse für deine App verarbeitet werden.

Füge in den Codeblock, der mit beginnt, an der Stelle, an der steht, die folgende Hilfsmethode ein:

Ruby
    # Handles the check run `requested_action` event
    # See /webhooks/event-payloads/#check_run
    def take_requested_action
      full_repo_name = @payload['repository']['full_name']
      repository     = @payload['repository']['name']
      head_branch    = @payload['check_run']['check_suite']['head_branch']

      if (@payload['requested_action']['identifier'] == 'fix_rubocop_notices')
        clone_repository(full_repo_name, repository, head_branch)

        # Sets your commit username and email address
        @git.config('user.name', ENV['GITHUB_APP_USER_NAME'])
        @git.config('user.email', ENV['GITHUB_APP_USER_EMAIL'])

        # Automatically correct RuboCop style errors
        @report = `rubocop '#{repository}/*' --format json --auto-correct`

        pwd = Dir.getwd()
        Dir.chdir(repository)
        begin
          @git.commit_all('Automatically fix Octo RuboCop notices.')
          @git.push("https://x-access-token:#{@installation_token.to_s}@github.com/#{full_repo_name}.git", head_branch)
        rescue
          # Nothing to commit!
          puts 'Nothing to commit'
        end
        Dir.chdir(pwd)
        `rm -rf '#{repository}'`
      end
    end

Mit dem obigen Code wird ein Repository geklont – wie auch mit dem Code, den du in Schritt 2.2.: Zulassen, dass RuboCop das Testrepository klont festgelegt hast. Mit einer -Anweisung wird überprüft, ob der Bezeichner der angeforderten Aktion dem Bezeichner der RuboCop-Schaltfläche () entspricht. Wenn die Bedingungen übereinstimmen, klont der Code das Repository, setzt den Git-Benutzernamen und die E-Mail-Adresse fest und führt RuboCop mit den entsprechenden Optionen aus. Die Änderungen werden mit der Option automatisch auf die lokalen CI-Serverdateien angewendet.

Die Dateien werden lokal geändert. Du musst sie jedoch noch an GitHub pushen. Zum Committen aller Dateien verwendest du das -Gem. Git verfügt über einen Befehl, mit dem alle geänderten oder gelöschten Dateien gestagt und committet werden: . Zum Erledigen derselben Aufgabe mit verwendet der obige Code die Methode . Danach pusht der Code die committeten Dateien mithilfe des Installationstokens in GitHub und verwendet dabei dieselbe Authentifizierungsmethode wie der Git-Befehl . Schließlich entfernt er das Repositoryverzeichnis, um sicherzustellen, dass das Arbeitsverzeichnis für das nächste Ereignis vorbereitet ist.

Der von dir geschriebene Code vervollständigt nun deinen Continuous Integration-Server, den du mithilfe einer GitHub App erstellt hast, und überprüft diesen. Den vollständigen endgültigen Code für deine App findest du unter Vollständiges Codebeispiel.

Testen des Codes

Die folgenden Schritte zeigen dir, wie du testen kannst, ob der Code funktioniert und wie RuboCop die gefundenen Fehler automatisch beheben kann.

  1. Führe den folgenden Befehl aus, um den Server über dein Terminal neu zu starten. Wenn der Server bereits ausgeführt wird, gib zuerst in dein Terminal ein, um den Server zu beenden, und führe dann den folgenden Befehl aus, um den Server erneut zu starten.

    Shell
    ruby server.rb
    
  2. Erstelle im Repository, in dem du die -Datei hinzugefügt hast, einen neuen Pull Request.

  3. Navigiere im neu erstellten Pull Request zur Registerkarte Überprüfungen, und klicke auf die Schaltfläche „Problem beheben“, um von RuboCop gefundene Fehler automatisch zu beheben.

  4. Navigiere zur Registerkarte Commits. Dir wird ein neuer Commit mit dem Benutzernamen angezeigt, den du in deiner Git-Konfiguration festgelegt hast. Möglicherweise musst du den Browser aktualisieren, damit das Update angezeigt wird.

  5. Navigiere zur Registerkarte Prüfungen. Dort sollte eine neue Prüfungsreihe für Octo RuboCop angezeigt werden. Dieses Mal sollte es jedoch keine Fehler geben, da RuboCop sie alle behoben hat.

Vollständiges Codebeispiel

So sollte der endgültige Code in aussehen, nachdem du alle Schritte in diesem Tutorial ausgeführt hast. Es gibt auch Kommentare im gesamten Code, die zusätzlichen Kontext liefern.

Ruby
require 'sinatra/base'  # Use the Sinatra web framework
require 'octokit'       # Use the Octokit Ruby library to interact with GitHub's REST API
require 'dotenv/load'   # Manages environment variables
require 'json'          # Allows your app to manipulate JSON data
require 'openssl'       # Verifies the webhook signature
require 'jwt'           # Authenticates a GitHub App
require 'time'          # Gets ISO 8601 representation of a Time object
require 'logger'        # Logs debug statements

# This code is a Sinatra app, for two reasons:
#   1. Because the app will require a landing page for installation.
#   2. To easily handle webhook events.

class GHAapp < Sinatra::Application

  # Sets the port that's used when starting the web server.
  set :port, 3000
  set :bind, '0.0.0.0'

  # Expects the private key in PEM format. Converts the newlines.
  PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n"))

  # Your registered app must have a webhook secret.
  # The secret is used to verify that webhooks are sent by GitHub.
  WEBHOOK_SECRET = ENV['GITHUB_WEBHOOK_SECRET']

  # The GitHub App's identifier (type integer).
  APP_IDENTIFIER = ENV['GITHUB_APP_IDENTIFIER']

  # Turn on Sinatra's verbose logging during development
  configure :development do
    set :logging, Logger::DEBUG
  end

  # Executed before each request to the `/event_handler` route
  before '/event_handler' do
    get_payload_request(request)
    verify_webhook_signature

    # If a repository name is provided in the webhook, validate that
    # it consists only of latin alphabetic characters, `-`, and `_`.
    unless @payload['repository'].nil?
      halt 400 if (@payload['repository']['name'] =~ /[0-9A-Za-z\-\_]+/).nil?
    end

    authenticate_app
    # Authenticate the app installation in order to run API operations
    authenticate_installation(@payload)
  end

  post '/event_handler' do

    # Get the event type from the HTTP_X_GITHUB_EVENT header
    case request.env['HTTP_X_GITHUB_EVENT']

    when 'check_suite'
      # A new check_suite has been created. Create a new check run with status queued
      if @payload['action'] == 'requested' || @payload['action'] == 'rerequested'
        create_check_run
      end

    when 'check_run'
      # Check that the event is being sent to this app
      if @payload['check_run']['app']['id'].to_s === APP_IDENTIFIER
        case @payload['action']
        when 'created'
          initiate_check_run
        when 'rerequested'
          create_check_run
        when 'requested_action'
          take_requested_action
        end
      end
    end

    200 # success status
  end

  helpers do

    # Create a new check run with status "queued"
    def create_check_run
      @installation_client.create_check_run(
        # [String, Integer, Hash, Octokit Repository object] A GitHub repository.
        @payload['repository']['full_name'],
        # [String] The name of your check run.
        'Octo RuboCop',
        # [String] The SHA of the commit to check
        # The payload structure differs depending on whether a check run or a check suite event occurred.
        @payload['check_run'].nil? ? @payload['check_suite']['head_sha'] : @payload['check_run']['head_sha'],
        # [Hash] 'Accept' header option, to avoid a warning about the API not being ready for production use.
        accept: 'application/vnd.github+json'
      )
    end

    # Start the CI process
    def initiate_check_run
      # Once the check run is created, you'll update the status of the check run
      # to 'in_progress' and run the CI process. When the CI finishes, you'll
      # update the check run status to 'completed' and add the CI results.

      @installation_client.update_check_run(
        @payload['repository']['full_name'],
        @payload['check_run']['id'],
        status: 'in_progress',
        accept: 'application/vnd.github+json'
      )

      full_repo_name = @payload['repository']['full_name']
      repository     = @payload['repository']['name']
      head_sha       = @payload['check_run']['head_sha']

      clone_repository(full_repo_name, repository, head_sha)

      # Run RuboCop on all files in the repository
      @report = `rubocop '#{repository}' --format json`
      logger.debug @report
      `rm -rf #{repository}`
      @output = JSON.parse @report

      annotations = []
      # You can create a maximum of 50 annotations per request to the Checks
      # API. To add more than 50 annotations, use the "Update a check run" API
      # endpoint. This example code limits the number of annotations to 50.
      # See /rest/reference/checks#update-a-check-run
      # for details.
      max_annotations = 50

      # RuboCop reports the number of errors found in "offense_count"
      if @output['summary']['offense_count'] == 0
        conclusion = 'success'
      else
        conclusion = 'neutral'
        @output['files'].each do |file|

          # Only parse offenses for files in this app's repository
          file_path = file['path'].gsub(/#{repository}\//,'')
          annotation_level = 'notice'

          # Parse each offense to get details and location
          file['offenses'].each do |offense|
            # Limit the number of annotations to 50
            next if max_annotations == 0
            max_annotations -= 1

            start_line   = offense['location']['start_line']
            end_line     = offense['location']['last_line']
            start_column = offense['location']['start_column']
            end_column   = offense['location']['last_column']
            message      = offense['message']

            # Create a new annotation for each error
            annotation = {
              path: file_path,
              start_line: start_line,
              end_line: end_line,
              start_column: start_column,
              end_column: end_column,
              annotation_level: annotation_level,
              message: message
            }
            # Annotations only support start and end columns on the same line
            if start_line == end_line
              annotation.merge({start_column: start_column, end_column: end_column})
            end

            annotations.push(annotation)
          end
        end
      end

      # Updated check run summary and text parameters
      summary = "Octo RuboCop summary\n-Offense count: #{@output['summary']['offense_count']}\n-File count: #{@output['summary']['target_file_count']}\n-Target file count: #{@output['summary']['inspected_file_count']}"
      text = "Octo RuboCop version: #{@output['metadata']['rubocop_version']}"

      # Mark the check run as complete! And if there are warnings, share them.
      @installation_client.update_check_run(
        @payload['repository']['full_name'],
        @payload['check_run']['id'],
        status: 'completed',
        conclusion: conclusion,
        output: {
          title: 'Octo RuboCop',
          summary: summary,
          text: text,
          annotations: annotations
        },
        actions: [{
          label: 'Fix this',
          description: 'Automatically fix all linter notices.',
          identifier: 'fix_rubocop_notices'
        }],
        accept: 'application/vnd.github+json'
      )
    end

    # Clones the repository to the current working directory, updates the
    # contents using Git pull, and checks out the ref.
    #
    # full_repo_name  - The owner and repo. Ex: octocat/hello-world
    # repository      - The repository name
    # ref             - The branch, commit SHA, or tag to check out
    def clone_repository(full_repo_name, repository, ref)
      @git = Git.clone("https://x-access-token:#{@installation_token.to_s}@github.com/#{full_repo_name}.git", repository)
      pwd = Dir.getwd()
      Dir.chdir(repository)
      @git.pull
      @git.checkout(ref)
      Dir.chdir(pwd)
    end

    # Handles the check run `requested_action` event
    # See /webhooks/event-payloads/#check_run
    def take_requested_action
      full_repo_name = @payload['repository']['full_name']
      repository     = @payload['repository']['name']
      head_branch    = @payload['check_run']['check_suite']['head_branch']

      if (@payload['requested_action']['identifier'] == 'fix_rubocop_notices')
        clone_repository(full_repo_name, repository, head_branch)

        # Sets your commit username and email address
        @git.config('user.name', ENV['GITHUB_APP_USER_NAME'])
        @git.config('user.email', ENV['GITHUB_APP_USER_EMAIL'])

        # Automatically correct RuboCop style errors
        @report = `rubocop '#{repository}/*' --format json --auto-correct`

        pwd = Dir.getwd()
        Dir.chdir(repository)
        begin
          @git.commit_all('Automatically fix Octo RuboCop notices.')
          @git.push("https://x-access-token:#{@installation_token.to_s}@github.com/#{full_repo_name}.git", head_branch)
        rescue
          # Nothing to commit!
          puts 'Nothing to commit'
        end
        Dir.chdir(pwd)
        `rm -rf '#{repository}'`
      end
    end

    # Saves the raw payload and converts the payload to JSON format
    def get_payload_request(request)
      # request.body is an IO or StringIO object
      # Rewind in case someone already read it
      request.body.rewind
      # The raw text of the body is required for webhook signature verification
      @payload_raw = request.body.read
      begin
        @payload = JSON.parse @payload_raw
      rescue => e
        fail 'Invalid JSON (#{e}): #{@payload_raw}'
      end
    end

    # Instantiate an Octokit client authenticated as a GitHub App.
    # GitHub App authentication requires that you construct a
    # JWT (https://jwt.io/introduction/) signed with the app's private key,
    # so GitHub can be sure that it came from the app and not altered by
    # a malicious third party.
    def authenticate_app
      payload = {
          # The time that this JWT was issued, _i.e._ now.
          iat: Time.now.to_i,

          # JWT expiration time (10 minute maximum)
          exp: Time.now.to_i + (10 * 60),

          # Your GitHub App's identifier number
          iss: APP_IDENTIFIER
      }

      # Cryptographically sign the JWT.
      jwt = JWT.encode(payload, PRIVATE_KEY, 'RS256')

      # Create the Octokit client, using the JWT as the auth token.
      @app_client ||= Octokit::Client.new(bearer_token: jwt)
    end

    # Instantiate an Octokit client, authenticated as an installation of a
    # GitHub App, to run API operations.
    def authenticate_installation(payload)
      @installation_id = payload['installation']['id']
      @installation_token = @app_client.create_app_installation_access_token(@installation_id)[:token]
      @installation_client = Octokit::Client.new(bearer_token: @installation_token)
    end

    # Check X-Hub-Signature to confirm that this webhook was generated by
    # GitHub, and not a malicious third party.
    #
    # GitHub uses the WEBHOOK_SECRET, registered to the GitHub App, to
    # create the hash signature sent in the `X-HUB-Signature` header of each
    # webhook. This code computes the expected hash signature and compares it to
    # the signature sent in the `X-HUB-Signature` header. If they don't match,
    # this request is an attack, and you should reject it. GitHub uses the HMAC
    # hexdigest to compute the signature. The `X-HUB-Signature` looks something
    # like this: 'sha1=123456'.
    def verify_webhook_signature
      their_signature_header = request.env['HTTP_X_HUB_SIGNATURE'] || 'sha1='
      method, their_digest = their_signature_header.split('=')
      our_digest = OpenSSL::HMAC.hexdigest(method, WEBHOOK_SECRET, @payload_raw)
      halt 401 unless their_digest == our_digest

      # The X-GITHUB-EVENT header provides the name of the event.
      # The action value indicates the which action triggered the event.
      logger.debug "---- received event #{request.env['HTTP_X_GITHUB_EVENT']}"
      logger.debug "----    action #{@payload['action']}" unless @payload['action'].nil?
    end

  end

  # Finally some logic to let us run this server directly from the command line,
  # or with Rack. Don't worry too much about this code. But, for the curious:
  # $0 is the executed file
  # __FILE__ is the current file
  # If they are the same—that is, we are running this file directly, call the
  # Sinatra run method
  run! if __FILE__ == $0
end

Nächste Schritte

Du solltest jetzt eine App haben, die API-Ereignisse empfängt, Überprüfungsausführungen erstellt, RuboCop verwendet, um Ruby-Fehler zu finden, Anmerkungen in einem Pull Request erstellt und automatisch Linterfehler behebt. Als Nächstes kannst du den Code deiner App erweitern, die App bereitstellen und sie öffentlich machen.

Wenn Sie Fragen haben, beginnen Sie eine GitHub Community-Diskussion in der API- und Webhooks-Kategorie.

Ändern des App-Codes

In diesem Tutorial wurde gezeigt, wie du die Schaltfläche „Problem beheben“ erstellst, die immer in Pull Requests im Repository angezeigt wird. Versuche, den Code so zu aktualisieren, dass die Schaltfläche „Problem beheben“ nur angezeigt wird, wenn RuboCop Fehler findet.

Wenn Dateien von RuboCop nicht direkt in den Haupt-Branch eingepflegt werden sollen, können Sie den Code so aktualisieren, dass stattdessen ein Pull Request mit einem neuen Branch erstellt wird, der auf dem Haupt-Branch basiert.

Bereitstellen Ihrer App

In diesem Tutorial wurde gezeigt, wie du deine App lokal entwickelst. Wenn du bereit bist, deine App bereitzustellen, musst du Änderungen vornehmen, um deine App zu bedienen und die Anmeldeinformationen deiner App zu schützen. Welche Schritte du ausführst, hängt vom verwendeten Server ab, aber die folgenden Abschnitte enthalten allgemeine Anleitungen.

Hosten deiner App auf einem Server

In diesem Tutorial wurde dein Computer oder Codespace als Server verwendet. Sobald die App für die Verwendung in der Produktion bereit ist, solltest du deine App auf einem dedizierten Server bereitstellen. Sie können z. B. Azure App Service verwenden.

Aktualisieren der Webhook-URL

Sobald du über einen Server verfügst, der für den Empfang von Webhookdatenverkehr von GitHub eingerichtet ist, aktualisiere die Webhook-URL in deinen App-Einstellungen. Du solltest „Smee.io“ nicht verwenden, um deine Webhooks in der Produktion weiterzuleiten.

Aktualisieren der Einstellung

Wenn du deine App bereitstellst, solltest du den Port ändern, auf den dein Server lauscht. Der Code weist deinen Server bereits an, auf alle verfügbaren Netzwerkschnittstellen zu lauschen, indem auf festgelegt wird.

Beispielsweise kannst du eine Variable in der Konfigurationsdatei auf deinem Server festlegen, um den Port anzugeben, an dem dein Server empfangen soll. Anschließend kannst du die Stelle aktualisieren, wo dein Code die Konstanten festlegt, sodass dein Server auf deinen Bereitstellungsport lauscht:

Ruby
set :port, ENV['PORT']

Schütze die Anmeldeinformationen deiner App

Du solltest niemals den privaten Schlüssel deiner App oder das Webhookgeheimnis veröffentlichen. In diesem Tutorial wurden die Anmeldeinformationen deiner App in einer von Git ignorierten -Datei gespeichert. Wenn du deine App bereitstellst, solltest du eine sichere Methode zum Speichern der Anmeldeinformationen auswählen und deinen Code aktualisieren, um den Wert entsprechend abzurufen. Beispielsweise können Sie die Anmeldeinformationen mit einem Geheimverwaltungsdienst wie Azure Key Vault speichern. Wenn deine App ausgeführt wird, kann sie die Anmeldeinformationen abrufen und in Umgebungsvariablen auf dem Server speichern, auf dem deine App bereitgestellt wird.

Weitere Informationen finden Sie unter AUTOTITLE.

Teilen Sie Ihre App

Wenn du deine App für andere Benutzer und Organisationen freigeben möchtest, mache deine App öffentlich. Weitere Informationen finden Sie unter AUTOTITLE.

Bewährte Methode befolgen

Du solltest bewährten Methoden für deine GitHub App folgen. Weitere Informationen finden Sie unter AUTOTITLE.