# Durchführung von Bereitstellungen

Mithilfe der REST-API für Bereitstellungen kannst du benutzerdefinierte Tools erstellen, die mit deinem Server und einer Drittanbieter-App interagieren.

Sie können die REST-API verwenden, um Ihre Projekte bereitzustellen, die auf GitHub einem Server gehostet werden, den Sie besitzen. Weitere Informationen zu den Endpunkten zum Verwalten von Bereitstellungen und Statusinformationen findest du unter [REST-API-Endpunkte für Bereitstellungen](/de/enterprise-server@3.22/rest/deployments). Du kannst auch die REST-API verwenden, um deine Bereitstellungen in dem Moment zu koordinieren, in dem dein Code im Standardzweig eintrifft. Weitere Informationen finden Sie unter [Erstellen eines CI-Servers](/de/enterprise-server@3.22/rest/guides/building-a-ci-server).

In diesem Leitfaden wird die REST-API verwendet, um ein Setup zu veranschaulichen, das du verwenden kannst.
In unserem Szenario werden wir Folgendes tun:

* Einen Pull Request zusammenführen.
* Wenn die CI abgeschlossen ist, legen wir den Status des Pull Requests entsprechend fest.
* Wenn der „Pull Request“ zusammengeführt wurde, starten wir die Bereitstellung auf unserem Server.

Unser CI-System und der Hostserver sind Produkte unserer Vorstellungskraft. Dabei könnte es sich um Heroku, Amazon oder etwas ganz anderes handeln. Im Mittelpunkt dieses Leitfadens steht die Einrichtung und Konfiguration des Servers, der die Kommunikation verwaltet.

Wenn du den [Download von `ngrok`](https://ngrok.com/) noch nicht durchgeführt hast, solltest du dies tun und den [Umgang damit lernen](https://ngrok.com/docs/getting-started/). Dieses Tool ist sehr nützlich, um lokale Anwendungen im Internet zugänglich zu machen.

Hinweis: Du kannst den vollständigen Quellcode für dieses Projekt [aus dem Repository mit den Plattformbeispielen](https://github.com/github/platform-samples/tree/master/api/ruby/delivering-deployments) herunterladen.

## Schreiben des Servers

Wir schreiben eine einfache Sinatra-App, um zu zeigen, dass unsere lokalen Verbindungen funktionieren.
Beginnen wir hiermit:

```ruby
require 'sinatra'
require 'json'

post '/event_handler' do
  payload = JSON.parse(params[:payload])
  "Well, it worked!"
end
```

(Wenn du nicht mit der Funktionsweise von Sinatra vertraut bist, solltest du den [Sinatra-Leitfaden](http://www.sinatrarb.com/) lesen.)

Starte diesen Server. Sinatra wird standardmäßig auf Port `4567` gestartet. Daher solltest du `ngrok` so konfigurieren, dass es ebenfalls auf diesen Port lauscht.

Damit dieser Server funktioniert, müssen wir ein Repository mit einem Webhook einrichten. Dieser Webhook sollte so konfiguriert werden, dass er ausgelöst wird, wenn ein Pull Request erstellt oder zusammengeführt wird.

Erstelle nun ein Repository, mit dem du experimentieren kannst. Dürfen wir Ihnen das von [@octocat vorgeschlagene Spoon/Knife-Repository](https://github.com/octocat/Spoon-Knife) präsentieren?

Danach erstellst du einen neuen Webhook in deinem Repository, fügst die von `ngrok` bereitgestellte URL hinzu und wählst `application/x-www-form-urlencoded` als Inhaltstyp aus.

Klicke auf **Webhook aktualisieren**. Der Antworttext `Well, it worked!` sollte angezeigt werden.
Sehr gut! Klicke auf **Individuelle Ereignisse auswählen**, und wähle Folgendes aus:

* Bereitstellung
* Bereitstellungsstatus
* Pull-Anforderung

Dies sind die Ereignisse GitHub , die an unseren Server gesendet werden, wenn die entsprechende Aktion auftritt. Wir konfigurieren unseren Server so, dass er *nur* Verarbeitungen durchführt, wenn Pull Requests sofort zusammengeführt werden:

```ruby
post '/event_handler' do
  @payload = JSON.parse(params[:payload])

  case request.env['HTTP_X_GITHUB_EVENT']
  when "pull_request"
    if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
      puts "A pull request was merged! A deployment should start now..."
    end
  end
end
```

Woran liegt das? Jedes von GitHub gesendete Ereignis enthält den HTTP-Header `X-GitHub-Event`. Wir kümmern uns jetzt nur um die PR-Veranstaltungen. Wenn ein Pull Request zusammengeführt wird (der Status lautet `closed`, und `merged` ist `true`), starten wir eine Bereitstellung.

Nimm einige Änderungen in einem Branch deines Testrepositorys vor, öffne einen Pull Request, und merge sie, um diesen Proof of Concept zu testen. Dein Server sollte entsprechend reagieren.

## Arbeiten mit Bereitstellungen

Sobald unser Server eingerichtet ist, der Code überprüft und unser Pull Request zusammengeführt wurde, möchten wir unser Projekt bereitstellen.

Zunächst ändern wir unseren Ereignislistener so, dass er Pull Requests verarbeitet, wenn sie zusammengeführt werden, und beginnen, auf Bereitstellungen zu reagieren:

```ruby
when "pull_request"
  if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
    start_deployment(@payload["pull_request"])
  end
when "deployment"
  process_deployment(@payload)
when "deployment_status"
  update_deployment_status
end
```

Anhand der Informationen aus dem Pull Request beginnen wir mit dem Ausfüllen der `start_deployment`-Methode:

```ruby
def start_deployment(pull_request)
  user = pull_request['user']['login']
  payload = JSON.generate(:environment => 'production', :deploy_user => user)
  @client.create_deployment(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], {:payload => payload, :description => "Deploying my sweet branch"})
end
```

Bereitstellungen können mit Metadaten in Form von `payload` und `description` versehen sein. Auch wenn diese Werte optional sind, ist es hilfreich, sie zum Protokollieren und Darstellen von Informationen zu verwenden.

Wenn eine neue Bereitstellung erstellt wird, wird ein völlig separates Ereignis ausgelöst. Daher haben wir einen neuen `switch`-Fall im Ereignishandler für `deployment`. Du kannst diese Informationen verwenden, um benachrichtigt zu werden, wenn eine Bereitstellung ausgelöst wurde.

Bereitstellungen können eine lange Zeit dauern. Daher sollten wir auf verschiedene Ereignisse lauschen, z. B. wann die Bereitstellung erstellt wurde und in welchem Zustand sie sich befindet.

Lass uns eine Bereitstellung simulieren, die einige Aufgaben ausführt, und beobachten, wie sich dies auf die Ausgabe auswirkt. Zunächst sollten wir unsere `process_deployment`-Methode abschließen:

```ruby
def process_deployment
  payload = JSON.parse(@payload['payload'])
  # you can send this information to your chat room, monitor, pager, etc.
  puts "Processing '#{@payload['description']}' for #{payload['deploy_user']} to #{payload['environment']}"
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'pending')
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'success')
end
```

Schließlich simulieren wir das Speichern der Statusinformationen als Konsolenausgabe:

```ruby
def update_deployment_status
  puts "Deployment status for #{@payload['id']} is #{@payload['state']}"
end
```

Lass uns aufschlüsseln, was gerade passiert. Eine neue Bereitstellung wird von `start_deployment` erstellt, wodurch das `deployment`-Ereignis ausgelöst wird. Anschließend rufen wir `process_deployment` auf, um andauernde Prozesse zu simulieren. Während dieser Verarbeitung rufen wir ebenfalls `create_deployment_status` auf, wodurch wir einen Empfänger über den Stand der Dinge informieren, während wir den Status auf `pending` festlegen.

Nach Abschluss der Bereitstellung legen wir den Status auf `success` fest.

## Schlussbemerkung

Seit Jahren verwenden wir bei GitHub eine Version von `Heaven`, um unsere Bereitstellungen zu verwalten. Der allgemeine Ablauf ist im Wesentlichen derselbe wie bei dem Server, den wir oben erstellt haben:

* Warte auf eine Antwort auf den Status der CI-Überprüfungen (Erfolg oder Fehler).
* Wenn die erforderlichen Überprüfungen erfolgreich waren, führe den Pull Request zusammen.
* `Heaven` verwendet den zusammengeführten Code und stellt ihn auf Staging- und Produktionsservern bereit.
* In der Zwischenzeit benachrichtigt `Heaven` auch alle über den Build, mittels [Hubot](https://github.com/github/hubot), der in unseren Chat-Räumen sitzt.

Das ist alles! Um dieses Beispiel zu verwenden, musst du kein eigenes Bereitstellungssetup kompilieren.
Sie können sich jederzeit auf [GitHub Integrationen](https://github.com/integrations) verlassen.