Ich bin ein Android-Entwickler und wollte keine manuelle Arbeit leisten.

Als ich mich in Skyeng niederließ, schien die Sonne etwas heller, das Gras war nicht grüner (es war der gleiche frühe Frühling), und der Teamleiter bat mich, Jira zu schreiben, wie viel Zeit für das Codieren aufgewendet wurde und wie viel geredet und überprüft wurde. Mindestens alle zwei Wochen.


"Basierend auf diesen Daten versuchen wir zu verstehen, ob es notwendig ist, die Schätzungen anzupassen und ob es Kommunikationsprobleme im Team gibt", sagten sie. Aber wer so ein "Babayka" war, wurde nie erzählt. .

Da wir alle Fernarbeiter sind, klang die Idee vernünftig. Und es wurde für mich interessant, wohin diese acht Stunden gegangen waren: hier waren sie, aber wofür genau? Die Protokollierung war jedoch ungewöhnlich. Und im Allgemeinen Faulheit. Dann beschloss ich, nach etwas zu suchen, das für mich weiterarbeiten würde. Und während der Recherche wurde ich ein wenig mitgerissen und schrieb mein Plugin für IntelliJ IDEA.

Unten finden Siesubjektive Überprüfung der fertigen Werkzeuge und meines Fahrrads (mit Quelle).

Ich studiere die Lösungen, die das Team verwendet


Das erste, was ich tat, war, von meinen Kollegen herauszufinden, wer was verwendet. Die Optionen sind ungefähr die folgenden:

1. Clockify - eine Taste, um alles zu regieren


Benötigen Sie Zeit zum Codieren oder Schreiben von Docks? Das Plugin fügt fast überall einen Button hinzu (ein ziemlich unauffälliger grauer Pacman).


So sieht es in Google Text & Tabellen aus


Und auf GitHub können

Sie Natrekannyi auf einem Dashboard bewundern oder in eine Tabelle importieren und in Jira ablegen.


Die Integration in Jira wird separat bereitgestellt, auch über die Browsererweiterung.

Es ist jedoch möglich, eine Tabelle mit von Clockify erhaltenen Arbeitsprotokollen in Ihren Arbeitskalender hochzuladen. Und für die Offline-Zeiterfassung gibt es Desktop-Anwendungen für Windows, Linux und Mac. Auch mobile Apps. Die Hauptfunktionalität ist kostenlos, es gibt jedoch mehrere Tarifpläne mit Extras wie Datenschutz, Erinnerungen und Vorlagen für Projekte.

2. Toggl , nur Toggl


Alles ist ungefähr gleich, aber ein bisschen mehr Extras - in einer Desktop-Anwendung können Sie beispielsweise Erinnerungen an die Zeiterfassung festlegen, den Pomodoro-Modus aktivieren und sogar eine bestimmte Anwendung mit einem bestimmten Projekt verknüpfen und die automatische Nachverfolgung einrichten.


Aber es gibt eine Nuance: Am ersten Tag des Gebrauchs war ich von diesem Fenster und Benachrichtigungen mit Erinnerungen begeistert. Obwohl die Theorie cool klang)

3. Toggl + Python-Skript : Wenn nur eine Schaltfläche nicht mehr ausreicht


Die Erfindung meines Kollegen. Irgendwie beschloss er, die Gesten für den Export von Tabellen nach Jira zu reduzieren und verlagerte das Entladen der Steuern in Toggl auf ein Skript. Sie können in einen Cron setzen und das Leben genießen.

4. Wakatime - wohin wir gehen, keine Knöpfe benötigt


Protokolliert alles selbst. Daher ist das erste, woran Sie beim Verbinden der Browsererweiterung denken müssen, die Blacklist.

Zusätzlich zu den Erweiterungen bietet es mehrere Integrationen und eine anständige Anzahl von Plugins für die gängigsten IDEs und Editoren.


Plugins für die IDE verfolgen die Zeit, die sowohl in einem bestimmten Git-Zweig als auch in einer bestimmten Datei verbracht wurde. Auf dem Bildschirm ist die Liste der verfügbaren sehr beeindruckend. Serenyk - "in den Plänen", für ihre schnelle Umsetzung können Sie abstimmen. Einige Plugins in einem kostenpflichtigen Abonnement für 9 US-Dollar pro Monat.

Darüber hinaus können Sie im Dashboard sehen, wie viel Zeit in Prozent für das Schreiben von Code in verschiedenen Sprachen aufgewendet wird: Wenn Sie sich daran erinnern, dass bei einem regulären Android-Projekt Kotlin, Java, Groovy und XML verwendet werden, ist dies für sich selbst sinnvoll. Und wenn Sie eine Weile mit dem installierten Plugin arbeiten, werden Sie feststellen, dass es ziemlich rücksichtslos ist: Das Dashboard erhält die Zeit zum aktiven Lesen und Schreiben von Code. Und das Kleben gelangt nicht mit einer Glasoptik in den Monitor. Unnötig zu sagen, ein Amateur.

Hmm, der Quellcode für WakaTime ist offen: Sie können versuchen zu verstehen, wie es funktioniert ...
, ? IDE JetBrains.

. WakaTime.java. , , Heartbeat (), WakaTime CLI . , , , .

Schreiben Sie Ihr Fahrrad analog


Vielleicht wäre eine Kartoffelpistole nützlicher, aber Sie werden nichts für Forschungszwecke tun. Nachdem ich über die WakaTime-Quellen meditiert hatte, entschied ich mich, ein eigenes Plug-In zu erstellen, mit dem Aktivitäten in der IDE verfolgt, die Zeit zum Schreiben protokolliert und alles an Jira gesendet werden kann (In unserem Ablauf sind die Zweige nach den Aufgaben in Jira benannt, daher sieht es ziemlich realistisch aus.)

Und um den Server während der Arbeit am Code nicht mit Anfragen zu füllen, senden wir die Protokolle, wenn Android Studio geschlossen ist, und speichern sie bis zu diesem Moment lokal.

1. Welche Entitäten können wir im Quellcode des Plugins finden (und in unserem eigenen verwenden)?


Wir verwenden keine Komponenten (dies ist Legacy ) , die zuvor die Hauptstruktureinheiten des Plugins waren. Kann Anwendungsebene, Projektebene oder Modulebene sein. Es gibt eine ApplicationComponent in der WakaTime-Quelle, aber sie können, der Quellcode ist bereits fünf Jahre alt und sollte die Abwärtskompatibilität beibehalten. Komponenten sind an den Lebenszyklus der Ebene gebunden, mit der sie verknüpft sind. So wird beispielsweise ApplicationComponent beim Start der IDE geladen. Bei Verwendung blockieren sie den Neustart des Plugins, ohne die IDE neu zu starten, und verhalten sich im Allgemeinen unangenehm. Daher ist es besser, stattdessen Dienste zu verwenden.

Wir nutzen Dienstleistungen- aktuelle Hauptstruktureinheiten. Sie sind in die gleichen Ebenen der Anwendung, des Projekts und des Moduls unterteilt. Sie helfen uns, die Logik auf den entsprechenden Ebenen zu kapseln und den Status des Plugins zu speichern.

Im Gegensatz zu Komponenten müssen Services mithilfe der ServiceManager.getService () -Methode eigenständig geladen werden. Die Plattform stellt sicher, dass jeder Dienst ein Singleton ist.

Aktionen hinzufügen - sie können eine Verknüpfung oder ein zusätzlicher Menüpunkt sein - kurz gesagt, sie sind für alles verantwortlich, was sich irgendwie auf Benutzeraktionen in der IDE auswirkt.

Wir verwenden Erweiterungen - jede Erweiterung der Funktionalität, die komplizierter als Aktionen ist: Stellen Sie beispielsweise eine Verbindung zum IDE-Lebenszyklus her und führen Sie etwas aus, während Sie einen Begrüßungsbildschirm anzeigen oder bevor Sie das Programm beenden.

All dies sollte in der Datei /META_INF/plugin.xml deklariert werden.

2. Plugin.xml und build.gradle



Projekterstellungsfenster. Wir werden unser Plugin in Kotlin schreiben und Gradle für die Assembly verwenden.

Dies ist das erste, was wir sehen, nachdem wir das Plugin-Leerzeichen in IDEA erstellt haben (Datei -> Neu -> Projekt ... -> Gradle -> IntelliJ Platform Plugin). Es enthält Informationen zu den Abhängigkeiten des Plugins und dessen kurze Beschreibung. Es sollte Plug-In-Komponenten deklarieren - die zuvor genannten Komponenten, Dienste, Aktionen und Erweiterungen. Es wird keinen bestimmten Einstiegspunkt geben - es wird je nach unseren Anforderungen eine benutzerdefinierte Aktion oder ein IDE-Lebenszyklusereignis sein.

Wir werden diese Abhängigkeiten brauchen - schließlich wollen wir ein Plugin für das Studio schreiben, damit es mit Git funktioniert.

<depends>Git4Idea</depends>
<depends>com.intellij.modules.androidstudio</depends>

Git4Idea ist ein Plug-In für das virtuelle Dateisystem (VCS) und bietet Themen, dank derer wir später Git-Ereignisse abhören können - wie zum Beispiel Checkouts.

Da wir auch möchten, dass das Plugin mit Jira funktioniert, werden wir über den Gradle eine freundlicherweise zur Verfügung gestellte Bibliothek mit einem Rest-Client verbinden. Fügen Sie dazu dort das Atlassian Maven-Repository hinzu:

repositories {
   mavenCentral()
   maven {
       url "https://packages.atlassian.com/maven/repository/public"
   }
}

Und eigentlich die Bibliotheken:

implementation "joda-time:joda-time:2.10.4"
implementation("com.atlassian.jira:jira-rest-java-client-core:4.0.0") {
   exclude group: 'org.slf4j'
   dependencies {
       implementation "com.atlassian.fugue:fugue:2.6.1"
   }
}

Hier definieren wir die Version der IDE, die uns interessiert, und den Weg dorthin (oh, wenn das echte Android Studio so schnell gestartet und funktioniert hat wie seine leichtgewichtige Version zum Debuggen von Plugins):

intellij {
   version '2019.1'
   plugins 'git4idea'
   alternativeIdePath 'E:\\Android Studio'
}

Und hier werden wir vielleicht eines Tages über eine neue, verbesserte Funktionalität schreiben. Aber nicht jetzt.

patchPluginXml {
   changeNotes """
     Add change notes here.<br>
     <em>most HTML tags may be used</em>"""
}

3. Erstellen einer Benutzeroberfläche


Um etwas in Jira zu pushen, müssen Sie sich zuerst anmelden. Es ist logisch, dies direkt nach der Eröffnung des Projekts zu tun. Es sieht so aus, als ob wir eine Erweiterung benötigen, und wir werden nicht zögern, sie in plugin.xml zu deklarieren:

<postStartupActivity implementation="Heartbeat"/>

und zeigen Sie den Dialog darin.

UI-Komponenten sind hauptsächlich Komponenten von Swing mit einigen Erweiterungen von Platform SDK. All dies wurde kürzlich in kotlin ui dsl eingewickelt. Zum Zeitpunkt des Schreibens wurde in der Dokumentation festgestellt, dass sich dsl zwischen den Hauptversionen sehr stark ändern kann. Daher verwenden wir es mit einer leichten Angst:


override fun createCenterPanel(): JComponent? {

   title = "Jira credentials"
   setOKButtonText("Save")

   return panel {
       row {
           JLabel("Jira hostname")()
           hostname = JTextField("https://")
           hostname()
       }
       row {
           JLabel("Username:")()
           username = JTextField()
           username()
       }
       row {
           JLabel("Password:")()
           password = JPasswordField()
           password()
       }
   }
}

Wir haben einen Dialog erstellt, ihn gezeigt und von Jira Anmeldeinformationen erhalten. Jetzt müssen wir sie so gut wie möglich und vorzugsweise sicher speichern. PersistingStateComponent wird zur Rettung kommen.

4. PersistingStateComponent-Gerät (nicht sehr kompliziert)


PersistingStateComponent kann zwei Dinge tun - saveState und loadState: serialisieren und speichern Sie das übergebene Objekt und rufen Sie es aus dem Speicher ab.

Wo genau er die Daten speichern soll, erfährt er aus der staatlichen Anmerkung. In der Dokumentation werden zwei einfachste Optionen erwähnt: Geben Sie Ihre Datei an oder speichern Sie alles in den Arbeitsbereichseinstellungen:

@Storage("yourName.xml")
@Storage(StoragePathMacros.WORKSPACE_FILE) 
@State(
   name = "JiraSettings",
   storages = [
       Storage("trackerSettings.xml")
   ])

Da wir einen Sonderfall haben, wenden wir uns der Dokumentation zur Speicherung sensibler Daten zu.

override fun getState(): Credentials? {
   if (credentials == null)  {
       val credentialAttributes = createCredentialAttributes()
       credentials = PasswordSafe.instance.get(credentialAttributes)
   }
   return credentials
}
override fun loadState(state: Credentials) {
   credentials = state
   val credentialAttributes = createCredentialAttributes()
   PasswordSafe.instance.set(credentialAttributes, credentials)
}

Eine andere PersistingStateComponent übernimmt das Speichern der für verschiedene Zweige protokollierten Zeit.

Jira hat den Login herausgefunden. Auch bei der Speicherung von Benutzerdaten. Jetzt müssen Sie das Checkout-Ereignis in der Filiale irgendwie verfolgen, um den Countdown zu starten.

5. Abonnieren Sie Veranstaltungen


Die IntelliJ-Plattform bietet die Möglichkeit, Observer an Ereignisse zu binden, die für uns von Interesse sind, indem sie ihre Themen im messageBus der gewünschten Ebene abonnieren. Hier ist das Dock , es ist ziemlich interessant.

Ein Thema ist ein bestimmter Endpunkt, eine Darstellung eines Ereignisses. Alles, was Sie tun müssen, ist, einen Listener zu abonnieren und zu implementieren, der das Geschehen handhaben soll.

Zum Beispiel muss ich mir Kassen in Git anhören ...

subscribeToProjectTopic(project, GitRepository.GIT_REPO_CHANGE) {
    GitRepositoryChangeListener {
        currentBranch = it.currentBranch
    }
}

... die Anwendung schließen (um die Zeit glücklich zu verpfänden) ...

subscribeToAppTopic(AppLifecycleListener.TOPIC) {
    object: AppLifecycleListener {
        override fun appWillBeClosed(isRestart: Boolean) {
            if (!isRestart) {
                JiraClient.logTime(entry.key, DateTime.now(), entry.value)
            }
        }
    }
}

... und Dokumente speichern (nur damit es so war).

subscribeToAppTopic(AppTopics.FILE_DOCUMENT_SYNC) {
    CustomSaveListener()
}

Dies ist im Prinzip bereits ausreichend (wenn nicht, können Sie immer Ihre eigenen schreiben). Aber was ist, wenn wir die geringste Scroll- und Mausbewegung hören wollen?

6. EditorEventMulticaster


Es sammelt alles, was in den geöffneten Editorfenstern passiert - Bearbeiten, Ändern des sichtbaren Bereichs, Mausbewegungen - und ermöglicht es Ihnen, es an einem Ort und sofort zu abonnieren.

Jetzt haben wir alles was wir brauchen. Wir können den Namen der Aufgabe in Jira aus dem aktuellen Zweig auswählen (falls vorhanden), die Arbeitszeit berechnen und das Studio sofort verlassen, um sie der Aufgabe hinzuzufügen.

7. Code und Details hier


Zum Ausführen benötigen Sie das neueste Android Studio (3.6.1).
Um die Leistung zu testen - git und ein Zweig mit einem Namen, der der Aufgabe in Jira zumindest im entferntesten ähnlich ist.
Damit das Plugin die Zeit nicht nur an die Konsole ausgibt, sondern verfolgt - kommentieren Sie die entsprechende Zeile in Heartbeat.kt aus.

8. Nützliche Links



PS Und was hast du am Ende gewählt?


- Verdammt, es ist irgendwie zu böse. Und wenn ich keinen Code schreibe? Und wenn ich meine Nase nehme und mich bemühe zu verstehen, was darin passiert? Im Code im Sinne von. Immerhin dauert dies die meiste Zeit.

- Dann scrollen Sie wenigstens.

- Es ist also nicht weit davon entfernt, gewalttätige Aktivitäten zu simulieren. Und dann kann ich das Studio wochenlang nicht herunterfahren und nicht neu starten. Vielleicht brauchen wir kein solches Glück?

"Auf keinen Fall notwendig." Dann ist noch ein Grund nötig, sonst habe ich gerne Plugins geschrieben. Und ich habe VCS immer noch nicht wirklich verstanden.

"Benutzt du es selbst?"

- Nein. Ich habe irgendwie gelernt, mit meinen Händen zu loggen, unmerklich für mich.

All Articles