Badoo Jira API Client: Magie in Jira in PHP

Wenn Sie bei Habré „Jira Badoo“ in den Suchtext eingeben, wird das Ergebnis mehr als eine Seite umfassen: Wir erwähnen es fast überall, da es eine wichtige Rolle in unseren Prozessen spielt. Und jeder von uns möchte ein bisschen anders als sie.



Der Entwickler, der die Aufgabe für die Überprüfung erhalten hat, erwartet, dass in der Aufgabe ein Zweig angegeben ist, Links zu diff und das Änderungsprotokoll vorhanden sind. Der Entwickler, der den Code geschrieben hat, erwartet, dass nach der Überprüfung Kommentare in Jira angezeigt werden. Der Tester, der die Aufgabe erhält, möchte die Testergebnisse sehen und die erforderlichen Baugruppen ausführen können, ohne zu anderen Schnittstellen zu wechseln. Produktmanager möchten in der Regel zehn Entwicklungsaufgaben gleichzeitig auf Knopfdruck erstellen.

Und das alles ist heute verfügbar und geschieht automatisch. Wir haben den größten Teil der Magie in PHP implementiert, indem wir die sich ständig weiterentwickelnde Jira-API und ihren Webhook verwendet haben . Und heute möchten wir der Community unsere Version des Clients für diese API mitteilen.

Zuerst wollten wir nur über die Ideen und Ansätze sprechen, die wir verwenden, und stellten dann fest, dass es aus Gründen der Klarheit definitiv nicht genug Code für einen solchen Artikel gibt. Es gab also eine Open-Source-Version von Badoo Jira PHP Client . Vielen Dank an ShaggyRatte für ihre Hilfe bei der Beschreibung. Und willkommen bei kat!

Weitere Details und Kontext.
Wenn Sie weitere Informationen über unsere Arbeit mit Jira benötigen, finden Sie diese in unseren anderen Artikeln:

habr.com/de/company/badoo/blog/169417
habr.com/de/company/badoo/blog/433540
habr.com/de/company/badoo/blog/424655

Was kann er tun


Tatsächlich besteht Badoo Jira PHP Client aus einer Reihe vorgefertigter Wrapper-Klassen für Jira API-Antworten, von denen sich die meisten wie ActiveRecord verhalten können: Sie wissen, wie sie Daten über sich selbst abrufen und auf dem Server aktualisieren, verzögerte Initialisierung und Daten-Caching auf der Ebene unterstützen Code. Alle Jira-Entitäten, mit denen Sie ständig arbeiten müssen, werden umbrochen: Problem, Status, Priorität, Änderungsprotokoll, Benutzer, Version, Komponente usw. (fast alles, was Sie in der Benutzeroberfläche sehen).

Zusätzlich bietet Badoo Jira PHP Client eine einzige Klassenhierarchie für alle benutzerdefinierten Jira-Felder und kann Klassendefinitionen für jedes von Ihnen benötigte benutzerdefinierte Feld generieren.

$Issue = new \Badoo\Jira\Issue('SMPL-1'); $Issue->addComment('Sample comment text'); $Issue->attachFile('kitten.jpeg', 'pretty!', 'image/jpeg'); if ($Issue->getStatus()->getName() === 'Open') { $Issue->step('In Progress'); } 

 $DeveloperField = new \Example\CustomFields\Developer($Issue); $DeveloperField->setValue('username')->save(); 

 $User = \Badoo\Jira\User::get('username'); $User->watchIssue('SMPL-1'); $User->assign('SMPL-2'); 

Dadurch wird die Interaktion mit der API von PHP einfacher und bequemer, und die Dokumentation für Ihren Jira wechselt direkt in den Code, sodass Sie die automatische Vervollständigung in der IDE für viele Standardaktionen verwenden können.

Aber das Wichtigste zuerst.

API-Funktionen, auf die wir gestoßen sind


Als wir damit begannen, die Jira-API aktiv zu nutzen, war sie nur über das SOAP-Protokoll verfügbar. Die REST-Version erschien später, und wir waren unter den ersten Benutzern. Zu dieser Zeit gab es nur sehr wenige öffentlich verfügbare REST-Clients, die in PHP geschrieben waren. Es war noch schwieriger, etwas zu finden, das sich leicht in unsere Codebasis integrieren ließ, und schrittweise von SOAP zu REST überzugehen. Wir hatten also keine andere Wahl: Wir beschlossen, unseren eigenen Kunden weiterzuentwickeln.

Wir lebten also davon, alle möglichen Hacks und Krücken vom SOAP-Client zu ziehen und abzulegen und aufgrund der Besonderheiten von REST neue zu beschaffen. Infolgedessen haben wir einige sehr kühne Klassen mit einem Haufen duplizierten Codes erweitert, und es besteht die Notwendigkeit, dieses Durcheinander zu beseitigen.

Benutzerdefinierte Felder waren für uns schon immer die schmerzlichste Stelle: Wir haben mehr als 300 davon (zum Zeitpunkt des Schreibens dieses Artikels - 338), und diese Zahl wächst langsam.

Seltsame Fehlermeldungen


In der langen Geschichte der Interaktion mit der API haben wir viele verschiedene Dinge gesehen. Die meisten Fehlermeldungen sind ausreichend, aber es gibt solche, bei denen Sie Ihr Gehirn stark belasten müssen.

Wenn Jira beispielsweise plötzlich einen Roboter in Ihrem Benutzer erkennt, zeigt sie ihm ein Captcha. In diesem Fall ignoriert es beim Zugriff auf die API schamlos den Header Accept-Encoding: application / json und gibt HTML aus. Natürlich ist der Client, der auf JSON wartet, möglicherweise nicht bereit für dieses "Hallo".

Und hier ist ein Beispiel für die Arbeit mit einem benutzerdefinierten Feld:



Wenn Sie Code schreiben und "jetzt testen", ist es sehr einfach zu verstehen, dass customfield_12664 Entwickler ist . Und wenn ein solcher Fehler irgendwo in der Produktion auftritt (z. B. weil jemand die Konfiguration geändert und die Liste der zulässigen Werte für das Select-Feld geändert hat), besteht die einzige Möglichkeit, das Feld zu identifizieren, darin, in Jira nach dem Namen zu suchen. Darüber hinaus werden in der Benutzeroberfläche keine IDs angezeigt, sondern nur Namen.

Es stellt sich heraus, dass Sie den Namen des Feldes, das zum Fehler geführt hat, herausfinden und dessen Konfiguration korrigieren möchten, indem Sie entweder eine Anforderung an die API senden oder andere nicht offensichtliche Methoden anwenden: Durchsuchen Sie den Quellcode der Seite und öffnen Sie die Einstellungen für ein beliebiges Feld und Korrigieren der URL in der Adressleiste usw. Dieser Vorgang kann nicht als bequem bezeichnet werden, und jedes Mal dauert es zu lange, bis eine so einfache Aufgabe erledigt ist.

Obskure Feldnamen sind jedoch nicht auf Probleme beschränkt. So sieht die Interaktion mit der API aus, wenn Sie in der Datenstruktur einen Fehler beim Aktualisieren des Felds machen:




Viele verschiedene Datenformate


Und vergessen Sie nicht, dass für die Aktualisierung von Feldern unterschiedlichen Typs unterschiedliche Datenstrukturen erforderlich sind.

 $Jira->issue()->edit( 'SMPL-1', [ 'customfield_10200' => ['name' => 'denkoren'], 'customfield_10300' => ['value' => 'PHP'], 'customfield_10400' => [['value' => 'Android'], ['value' => 'iOS']], 'security' => ['id' => 100500], 'description' => 'Just text', ], ); 

Die API-Antworten für sie sind natürlich auch unterschiedlich.

Dies kann nur berücksichtigt werden, wenn Sie ständig mit der Jira-API arbeiten und nicht lange durch die Lösung anderer Probleme abgelenkt werden. Andernfalls gehen diese Funktionen innerhalb weniger Wochen verloren. Darüber hinaus müssen Sie sich den Typ des Feldes merken, den Sie benötigen, um es mit der richtigen Struktur zu „füttern“. Wenn Sie Hunderte von benutzerdefinierten Feldern haben, müssen Sie entweder im Code nachsehen, wo er noch verwendet wurde, oder Sie müssen in das Jira-Administrationsfenster wechseln.

Bevor wir unseren Kunden schrieben, waren Stack Overflow und Atlassian Community meine besten Freunde bei der Aktualisierung benutzerdefinierter Felder. Diese Informationen lassen sich jetzt einfach und schnell googeln, aber wir haben zu der REST-API gewechselt, als sie noch recht neu und aktiv war: Es dauerte zehn Minuten, bis eine geeignete cURL-Anforderung in Google gefunden wurde, und dann mussten Sie diese Klammern mit Ihren Augen analysieren und konvertieren in die richtige Struktur für PHP, die beim ersten Versuch oft nicht funktionierte.

Im Allgemeinen ist die Interaktion mit benutzerdefinierten Feldern der Prozess, dessen Reorganisation an erster Stelle erforderlich war.

Woraus besteht der Kunde?


Klassen für die Arbeit mit benutzerdefinierten Feldern


Zunächst wollten wir uns nicht mehr an Datenstrukturen für die Interaktion mit der API erinnern und lesbare Feldnamen abrufen, wenn Fehler auftraten.

Aus diesem Grund haben wir für alle benutzerdefinierten Felder eine einzige Klassenhierarchie erstellt. Es stellte sich heraus, drei Schichten:

  1. Ein gemeinsames abstraktes übergeordnetes Element für alle Benutzer : \ Badoo \ Jira \ CustomFields \ CustomField .
  2. Durch eine abstrakte Klasse für jeden Feldtyp : SelectField, UserField, TextField usw.
  3. Nach Klasse für jedes bestimmte Feld: z. B. Entwickler oder Prüfer .

Diese Klassen können unabhängig voneinander geschrieben oder mithilfe eines speziellen Skriptgenerators automatisch erstellt werden (wir werden darauf zurückkommen).


Dank dieser Struktur genügt es, eine von SelectField geerbte PHP-Klasse zu erstellen, um dem Code beizubringen, den Wert Ihres benutzerdefinierten Felds vom Typ Select List (Multiple Choice) zu aktualisieren . Tatsächlich wird jedes benutzerdefinierte Jira-Feld zu einem regulären ActiveRecord in PHP-Code.

 namespace \Example\CustomFields; class Developer extends \Badoo\Jira\CustomFields\SingleUserField { const ID = 'customfield_10200'; const NAME = 'Developer'; } // ,  ,  ! 


In derselben Klasse speichern wir Informationen über das Feld: Standardmäßig ist dies eine ID, der Name des Felds und eine Liste der verfügbaren Werte, sofern diese begrenzt sind (z. B. für Kontrollkästchen und Auswählen ).

Beispiele für Felder in der Jira-Oberfläche und der zugehörigen Klasse


 class IssueFor extends \Badoo\Jira\CustomFields\SingleSelectField { const ID = 'customfield_10662'; const NAME = 'Issue for'; /* Available field values. */ const VALUE_BI = 'BI'; const VALUE_C_C = 'C\C++'; const VALUE_HTML_CSS = 'HTML\CSS'; const VALUE_JS = 'JS'; const VALUE_OTHER = 'Other'; const VALUE_PHP = 'PHP'; const VALUE_TRANSLATION = 'Translation'; const VALUES = [ self::VALUE_BI, self::VALUE_C_C, self::VALUE_HTML_CSS, self::VALUE_JS, self::VALUE_OTHER, self::VALUE_PHP, self::VALUE_TRANSLATION, ]; public function getItemsList() : array { return static::VALUES; } } 


Es stellt sich heraus, dass diese Art von Dokumentation für Ihren Jira ist und sich direkt im PHP-Code befindet. Wenn es so nah ist, ist es sehr praktisch und beschleunigt die Entwicklung erheblich, während die Anzahl der Fehler verringert wird.

Außerdem werden Fehlermeldungen deutlicher: Anstatt nichts zu sagen, stürzt 'customfield_12664' beispielsweise folgendermaßen ab:

 Uncaught Badoo\Jira\Exception\CustomField: User 'asdkljfh' not found in Jira. Can't change 'Developer' field value. 

Klassen zum Arbeiten mit Systemobjekten


Jira hat viele Daten mit einer komplexen Struktur: zum Beispiel die Felder Status und Sicherheitssystem , Verknüpfungen zwischen Aufgaben, Benutzern, Versionen, Anhängen (Dateien).

Wir haben sie auch in Klassen eingepackt:

 //   $Status = $Issue->getStatus(); $Status->getName(); $Status->getId(); 

 // changelog  $History = \Badoo\Jira\Issue\History::forIssue('SMPL-1'); $seconds_in_status = $History->getTimeInStatus('Open'); 

 //  Jira $User = new \Badoo\Jira\User('sampleuser'); $User->assign('SMPL-1'); 

Mit solchen Wrappern kann Ihre IDE erkennen, welche Daten verfügbar sind, und Sie können die Funktionsschnittstellen in Ihrem Code streng formalisieren. Wir verwenden aktiv Typdeklarationen. Dank der Hervorhebung der IDE können wir fast immer einen Fehler sehen, auch wenn wir Code schreiben. Und wenn Sie den Fehler dennoch übersehen haben, wird er genau an der Stelle ausgegeben, an der er zuerst aufgetreten ist, und nicht an der Stelle, an der Sie den Code endgültig abgelegt haben.

Es gibt immer noch statische Methoden, mit denen Sie ein Objekt anhand einiger Kriterien schnell ermitteln können:

 $users = \Badoo\Jira\User::search('<pattern>'); //    login, email  display name $Version = \Badoo\Jira\Version::byName('<project>', '<version name>'); //        $components = \Badoo\Jira\Component::forProject('<project>'); //      

Diese Methoden befolgen die allgemeinen Regeln, damit sie leicht zu finden sind:
  • :: search () , wenn Sie Objekte nach mehreren Feldern suchen müssen: \ Badoo \ Jira \ Issue :: search () sucht mit JQL nach Tasks, in denen Sie viele Suchkriterien angeben können, und \ Badoo \ Jira \ User :: search () sucht den Benutzer gleichzeitig nach 'Name' (Login), 'E-Mail' und 'displayName' (dem Namen, der im Web angezeigt wird);
  • :: by * () , wenn Sie das Objekt nicht nach ID, sondern nach einem anderen Kriterium abrufen müssen: \ Badoo \ Jira \ User :: byEmail () sucht einen Benutzer anhand seiner E-Mail-Adresse;
  • :: for * () sucht nach allen Objekten, die mit etwas verbunden sind: \ Badoo \ Jira \ Version :: forProject
    gibt alle Versionen aus einem bestimmten Projekt an;
  • :: fromStdClass () erstellt ein Objekt aus Rohdaten mit einer geeigneten Struktur, die jedoch nicht von der API, sondern beispielsweise vom Webhook empfangen werden : Im Hauptteil der POST-Anforderung sendet Jira JSON verschiedene Informationen zum Ereignis, einschließlich des Hauptteils der Aufgabe einschließlich aller Felder. Anhand dieser Daten können Sie das Objekt \ Badoo \ Jira \ Issue erstellen und wie gewohnt verwenden.

Class \ Badoo \ Jira \ Issue


Es scheint mir, dass der folgende Screenshot von PhpStorm an sich ziemlich beredt ist:



Im Wesentlichen bindet das \ Badoo \ Jira \ Issue- Objekt alles, was oben beschrieben wurde, in ein einziges System. Es speichert alle Informationen über die Aufgabe, verfügt über Methoden für den schnellen Zugriff auf die am häufigsten verwendeten Daten, zum Übertragen von Aufgaben zwischen Status usw.

Um im einfachsten Fall ein Objekt zu erstellen, genügt es, nur den Schlüssel der Aufgabe zu kennen.

Erstellen Sie ein Objekt mit nur einem Aufgabenschlüssel in Ihrer Tasche
 $Issue = new \Badoo\Jira\Issue('SMPL-1'); 


Sie können auch jeden fragmentierten Datensatz verwenden. Beispielsweise enthält die Verknüpfungsinformation zwischen Aufgaben, die von der API ankommen, nur einige Felder: ID, Zusammenfassung, Status, Priorität und Ausgabetyp. Mit \ Badoo \ Jira \ Issue können Sie ein Objekt aus diesen Daten sammeln, damit es sofort zurückgegeben werden kann, und im Übrigen auf die API zugreifen.

Erstellen Sie ein Objekt und speichern Sie Werte für einige Felder
  $IssueFromLink = \Badoo\Jira\Issue::fromStdClass( $LinkInfo, [ 'id', 'key', 'summary', 'status', 'priority', 'issuetype', ] ); 


Dies wird durch verzögerte Initialisierung und Zwischenspeicherung von Daten im Code erreicht. Dieser Ansatz ist besonders praktisch, da Sie nur \ Badoo \ Jira \ Issue- Objekte in Ihrem Code austauschen können, unabhängig davon, mit welchen Feldern sie erstellt wurden.

Holen Sie sich die fehlenden Aufgabendaten
 $IssueFromLink->getSummary(); //    API,    $IssueFromLink->getDescription(); //  API    description 


Wie wir zur API gehen
In der Jira-API können nicht alle Felder für eine Aufgabe abgerufen werden, sondern nur die Felder, die derzeit benötigt werden, z. B. nur Schlüssel und Zusammenfassung. Wir gehen jedoch absichtlich nicht für nur ein Feld im Getter nach Jira. Im obigen Beispiel aktualisiert getDescription () Informationen zu allen Feldern gleichzeitig. Da \ Badoo \ Jira \ Issue nicht die geringste Ahnung hat, was Sie als Nächstes benötigen, ist es rentabler, alles sofort von der API abzurufen, da wir sowieso dorthin gegangen sind. Ja, die Abfrage "Nur Beschreibung abrufen" und die Abfrage "Standardmäßig alle Felder abrufen" für ein paar Hundert Tickets dauert unterschiedlich lange, aber für ein Ticket ist dieser Unterschied nicht so auffällig.

 //Time for single field: 0.40271635055542 (second) //Time for all default fields: 0.84159119129181 (second) 

Aus den Zahlen geht klar hervor, dass es rentabler ist, wenn nur drei Felder (eines in der Anfrage) empfangen werden, alles auf einmal abzurufen, anstatt für jedes die API aufzurufen. Das Ergebnis dieser Messung hängt in der Tat von der Konfiguration von Jira und dem Server ab, auf dem es ausgeführt wird. Von Aufgabe zu Aufgabe und von Messung zu Messung ändern sich die Zahlen, und die Zeit für alle Standardfelder beträgt stabil weniger als drei Zeit für ein einzelnes Feld und häufig sogar weniger als zwei.

Bei der Arbeit mit einer großen Anzahl von Aufgaben kann die Differenz jedoch in Sekunden gemessen werden. Wenn Sie wissen, dass Sie nur Schlüssel und Beschreibung für 500 Tickets benötigen, bleibt die Möglichkeit, diese mit einer effektiven Abfrage abzurufen, in den Methoden \ Badoo \ Jira \ Issue :: search () und \ Badoo \ Jira \ Issue :: byKeys () erhalten .


\ Badoo \ Jira \ Issue - im Allgemeinen über Aufgaben in einem abstrakten Jira. Aber Ihre (wie unsere) Jira ist nicht abstrakt - sie verfügt über eine Reihe von benutzerdefinierten Feldern und einen eigenen Workflow. Du benutzt einige der Felder und Übergänge verdammt oft, deshalb ist es nicht sehr bequem, sie alle weit zu verfolgen. Daher kann \ Badoo \ Jira \ Issue problemlos mit eigenen Methoden erweitert werden, die für eine bestimmte Jira-Konfiguration spezifisch sind.

Ein Beispiel für eine Klassenerweiterung durch eine Methode zum schnellen Abrufen eines benutzerdefinierten Felds
 namespace \Deploy; class Issue extends \Badoo\Jira\Issue { // … /** * Get 'Developer' custom field as object */ function getDeveloperField() : \Deploy\CustomFields\Developer { return $this->getCustomField(\Deploy\CustomFields\Developer::class); } // ... } 



Erstellen Sie die Anforderung


Das Erstellen einer Aufgabe in Jira ist ein ziemlich komplizierter Vorgang. Wenn Sie dies über die Webschnittstelle tun, wird ein spezieller Bildschirm (Bildschirm erstellen) mit einer Reihe von Feldern angezeigt. Einige davon können Sie einfach ausfüllen, weil Sie möchten, und andere sind als obligatorisch gekennzeichnet. Gleichzeitig kann Create Screen für jedes Projekt und sogar für verschiedene Aufgabentypen in einem Projekt eindeutig sein. Es gibt also alle möglichen Einschränkungen hinsichtlich der Feldwerte und der Möglichkeit, den Feldwert beim Erstellen der Aufgabe festzulegen.

Das Unangenehmste für Entwickler in dieser Situation ist, dass diese Einschränkungen für die API gelten. Letzteres hat eine spezielle Anforderung ( create-meta ist in der REST-API seit Version 5.0 verfügbar), mit der Sie eine Liste der Feldeinstellungen abrufen können, die beim Erstellen einer Aufgabe verfügbar sind. Ein Entwickler, der "im Moment nur eine einfache Sache machen" muss, wird sich jedoch höchstwahrscheinlich nicht darum kümmern.

Infolgedessen ist es so gekommen: Da die Anforderung zum Erstellen einer Aufgabe sehr umfangreich sein kann, haben wir ihr häufig nach und nach Daten hinzugefügt, und beim Versuch, alles an Jira zu senden, ist ein Fehler aufgetreten. Danach musste ich im Code nach allen Stellen suchen, an denen sich etwas in der Anfrage geändert hatte, und nach einem langen und mühsamen Versuch, zu verstehen, was genau schief gelaufen war.

Daher haben wir \ Badoo \ Jira \ Issue \ CreateRequest . Sie können den Fehler früher sehen, genau an der Stelle, an der Sie versuchen, etwas falsches zu machen: Geben Sie dem Feld einen gekrümmten Wert oder ändern Sie das nicht verfügbare Feld. Wenn Sie beispielsweise versuchen, einer Aufgabe eine Komponente mitzuteilen, die nicht im Projekt vorhanden ist, stürzt die Ausnahme an der Stelle ab, an der Sie sie ausgeführt haben, und nicht an der Stelle, an der Sie die Anforderung letztendlich an die API gesendet haben.

Der Arbeitsfluss mit CreateRequest sieht ungefähr so ​​aus
 $Request = new \Badoo\Jira\Issue\CreateRequest('DD', 'Task', $Client); $Request ->setSummary('summary') ->setDescription('description') ->setFieldValue('For QA', 'custom field with some comments for QA who will check the issue'); $Request->send(); 


Arbeiten Sie direkt mit der API


Die oben beschriebenen Klassen decken die meisten Anforderungen ab. Wir sind uns jedoch bewusst, dass die Mehrheit weit von allem entfernt ist. Daher haben wir auch einen kleinen Client für die direkte Arbeit mit der API - \ Badoo \ Jira \ REST \ Client .

Anwendungsfall für Kunden
 $Jira = \Badoo\Jira\REST\Client::instance(); $Jira->setJiraUrl('https://jira.example.com/'); $Jira->setAuth('user', 'password') $IssueInfo = $Jira->issue()->get('SMPL-1'); 


Klassengenerator für benutzerdefinierte Felder


Um die Arbeit mit benutzerdefinierten Feldern zu vereinfachen, muss jedes Feld eine eigene Klasse im Code haben. Wir haben sie bei Bedarf manuell erstellt, aber vor dem Veröffentlichen des Clients entschieden wir, dass dieser Ansatz für neue Benutzer möglicherweise nicht sehr praktisch ist. Aus diesem Grund haben wir einen speziellen Generator erstellt, mit dem Sie in der Jira-API eine Liste der benutzerdefinierten Felder anzeigen und Vorlagenklassen für die bekannten Feldtypen erstellen können.

Wir glauben, dass es für die meisten Aufgaben ausreicht, das bin / generate- CLI-Skript aus unserem Repository zu verwenden. Sie können ihn bitten, mit der Option --help / -h etwas über sich zu erzählen:

 ./bin/generate --help 

Im einfachsten Fall reicht es für die Generierung aus, die URL Ihres Jira, den Benutzer, sein Passwort, den Namespace für die Klassen und das Verzeichnis anzugeben, in dem der Code abgelegt werden soll:

 ./bin/generate -u user -p password --jira-url https://jira.mlan --target-dir custom-fields --namespace CustomFields 

Wir haben auch die Möglichkeit implementiert, eigene Vorlagen hinzuzufügen und Klassen für einzelne Felder zu generieren. Dies finden Sie in der Dokumentation .

Fazit


Wir mögen was wir haben. Mit diesem Konzept - unseren eigenen Klassen für benutzerdefinierte Felder, Wrappern für Status, Versionen, Benutzer usw. - leben wir seit mehr als einem Jahr und fühlen uns großartig. Vor der Veröffentlichung des Codes haben wir sogar die Funktionalität erweitert und wundervolle Dinge hinzugefügt, die lange Zeit nicht in Ihre Hände kamen, um den Client zu verwenden. So haben wir beispielsweise die Möglichkeit hinzugefügt, mehrere Felder in Issue in einer Anfrage zu aktualisieren, und einen Klassengenerator für benutzerdefinierte Felder geschrieben.

Unserer Meinung nach hat es sich als eine gute Sache erwiesen, die auf jeden Fall verstanden werden sollte, ob sie Ihren Aufgaben und Anforderungen entspricht. Unter unserer - einfach fit.

Link nochmal: github.com/badoo/jira-client .

Vielen Dank für das Lesen bis zum Ende. Wir hoffen, dass dieser Code jetzt nicht nur für uns von Nutzen ist und Zeit spart.

Source: https://habr.com/ru/post/de475840/


All Articles