Je suis développeur Android et je n'aimais pas faire de travail manuel.

Quand je me suis installé à Skyeng, le soleil brillait un peu plus, l'herbe n'était pas plus verte (c'était le même début de printemps) et le chef d'équipe m'a demandé d'écrire à Jira combien de temps a été consacré au codage, et combien de discussions et de révisions. Au moins une fois toutes les deux semaines.


"Sur la base de ces données, nous essayons de comprendre s'il est nécessaire d'ajuster les estimations et s'il y a des problèmes de communication dans l'équipe", ont-ils déclaré. Mais à qui une telle «babayka» n'a-t-elle jamais été révélée? .

Puisque nous sommes tous des travailleurs à distance, l'idée semblait raisonnable. Et il est devenu intéressant pour moi où ces huit heures étaient passées: les voilà, mais pour quoi exactement? Cependant, l'exploitation forestière était inhabituelle. Et dans la paresse générale. J'ai alors décidé de chercher quelque chose qui continuerait à fonctionner pour moi. Et en cours de recherche, je me suis un peu emporté et j'ai écrit mon plugin pour IntelliJ IDEA.

Vous trouverez ci-dessousexamen subjectif des outils finis et de mon vélo (avec source).

J'étudie les solutions que l'équipe utilise


La première chose que j'ai faite a été d'aller me renseigner auprès de mes collègues qui utilisent quoi. Les options sont approximativement les suivantes:

1. Clockify - un bouton pour tout contrôler


Avez-vous besoin de temps pour coder ou écrire des quais? Le plugin ajoutera un bouton (un pacman gris assez discret) presque n'importe où.


Il regarde donc dans Google Docs


Et sur GitHub,

vous pouvez admirer Natrekannyi sur un tableau de bord, ou vous pouvez importer dans une table et le déposer dans Jira.


L'intégration dans Jira est fournie séparément, également par extension de navigateur

, mais il est possible de télécharger un tableau avec les journaux de travail obtenus de Clockify dans votre calendrier de travail. Et pour le suivi du temps hors ligne, il existe des applications de bureau pour Windows, Linux et Mac. Des applications mobiles aussi. La fonctionnalité principale est gratuite, mais il existe plusieurs plans tarifaires avec des goodies comme la confidentialité, des rappels et des modèles de projets.

2. Toggl , juste Toggl


Tout est à peu près la même chose, mais un peu plus de goodies - par exemple, dans une application de bureau, vous pouvez vous définir des rappels sur la journalisation du temps, activer le mode pomodoro, il y a même la possibilité de lier une application spécifique à un projet spécifique et de configurer le suivi automatique.


Mais il y a une nuance: le premier jour d'utilisation j'ai été étonné par cette fenêtre et les notifications avec rappels. Bien que la théorie semblait cool)

3. Script Toggl + Python : quand un simple bouton ne suffit plus


L'invention de mon collègue. D'une manière ou d'une autre, il a décidé de réduire les gestes pour exporter des tables vers Jira et a déplacé le déchargement de la taxation dans Toggl vers un script. Vous pouvez mettre un cron et profiter de la vie.

4. Wakatime - où nous allons, aucun bouton nécessaire


Enregistre tout lui-même. Par conséquent, la première chose à retenir lors de la connexion de son extension de navigateur est la liste noire.

En plus des extensions, il fournit plusieurs intégrations et un nombre décent de plugins pour les IDE et les éditeurs les plus courants.


Les plugins pour l'IDE suivent le temps passé à la fois dans une branche git spécifique et dans un fichier spécifique. A l'écran, la liste des disponibles est très impressionnante. Serenyk - «dans les plans», pour leur mise en œuvre rapide, vous pouvez voter. Certains plugins dans un abonnement payant pour 9 $ par mois.

De plus, sur le tableau de bord, vous pouvez voir combien de temps est consacré en pourcentage à l'écriture de code dans différentes langues: si vous vous souvenez qu'un projet Android régulier implique l'utilisation de Kotlin, Java, Groovy et xml - cela a du sens pour lui-même). Et si vous travaillez avec le plugin installé pendant un certain temps, vous remarquerez qu'il est plutôt impitoyable: le tableau de bord obtient le temps de lire et d'écrire du code. Et coller ne pénètre pas dans le moniteur avec un aspect de verre. Inutile de dire, un amateur.

Hmm, le code source de WakaTime est ouvert: vous pouvez essayer de comprendre comment cela fonctionne ...
, ? IDE JetBrains.

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

Écrire votre vélo par analogie


Un pistolet à pommes de terre serait peut-être plus utile, mais vous ne ferez rien à des fins de recherche. Après avoir médité sur les sources WakaTime, j'ai décidé de créer mon propre plug-in qui peut suivre l'activité dans l'IDE, enregistrer le temps d'écriture et l'envoyer à Jira. (dans notre flux, les branches sont nommées d'après les tâches dans Jira, donc cela semble assez réaliste).

Et afin de ne pas remplir le serveur de requêtes pendant que vous travaillez sur le code, nous enverrons les journaux lorsque Android Studio sera fermé, et jusqu'à ce moment, stockez-le localement.

1. Quelles entités pouvons-nous trouver dans le code source du plugin (et les utiliser dans les nôtres)?


Nous n'utilisons pas de composants (c'est Legacy ) , qui étaient auparavant les principales unités structurelles du plugin. Peut être au niveau de l'application, au niveau du projet ou au niveau du module. Il existe un ApplicationComponent dans la source WakaTime, mais ils le peuvent, le code source a déjà cinq ans et il devrait conserver une compatibilité descendante. Les composants sont liés au cycle de vie du niveau auquel ils sont associés. Ainsi, par exemple, ApplicationComponent est chargé au démarrage de l'EDI. Lorsqu'ils sont utilisés, ils empêcheront le plugin de redémarrer sans redémarrer l'IDE et se comporteront généralement de manière désagréable. Par conséquent, il est préférable d'utiliser des services à la place.

Nous utilisons les services- principales unités structurelles actuelles. Ils sont divisés en les mêmes niveaux de l'application, du projet et du module, ils nous aideront à encapsuler la logique aux niveaux appropriés et à stocker l'état du plugin.

Contrairement aux composants, les services doivent être chargés seuls à l'aide de la méthode ServiceManager.getService (). La plateforme garantit que chaque service est un singleton.

Ajouter des actions - elles peuvent être un raccourci, un élément de menu supplémentaire - en un mot, elles sont responsables de tout ce qui affecte en quelque sorte les actions des utilisateurs dans l'EDI.

Nous utilisons des extensions - toute extension de fonctionnalité qui sera plus compliquée que les actions: par exemple, connectez-vous au cycle de vie IDE et faites quelque chose tout en affichant un écran de démarrage ou avant de quitter.

Tout cela doit être déclaré dans le fichier /META_INF/plugin.xml.

2. Plugin.xml et build.gradle



Fenêtre de création de projet. Nous allons écrire notre plugin dans Kotlin, et utiliser Gradle pour l'assemblage.C'est

la première chose que nous voyons après avoir créé le plugin vierge dans IDEA (Fichier -> Nouveau -> Projet ... -> Gradle -> IntelliJ Platform Plugin). Il contient des informations sur les dépendances du plugin et sa brève description. Il doit déclarer les composants du plug-in - les composants, services, actions et extensions mentionnés précédemment. Il n'y aura pas de point d'entrée spécifique - il s'agira d'une action personnalisée ou d'un événement de cycle de vie IDE, selon nos besoins.

Nous aurons besoin de ces dépendances - après tout, nous voulons écrire un plugin pour le studio et pour qu'il puisse fonctionner avec Git.

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

Git4Idea est un plug-in pour le système de fichiers virtuel (VCS) et fournit des rubriques, grâce auxquelles nous pourrons plus tard écouter les événements git - comme les extractions, par exemple.

Puisque nous voulons également que le plugin puisse fonctionner avec Jira, nous allons connecter via le gradle une bibliothèque aimablement fournie avec un client de repos. Pour ce faire, ajoutez-y le référentiel Atlassian maven:

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

Et en fait les bibliothèques:

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"
   }
}

Ici, nous déterminons la version de l'IDE qui nous intéresse et le chemin vers celui-ci (oh, si le vrai Android Studio a démarré et travaillé aussi vite que sa version légère pour le débogage des plugins):

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

Et ici, peut-être, un jour, nous écrirons sur une nouvelle fonctionnalité améliorée. Mais pas maintenant.

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

3. Création d'une interface utilisateur


Pour insérer quelque chose dans Jira, vous devez d'abord vous connecter. Il est logique de le faire juste après l'ouverture du projet. Il semble que nous ayons besoin d'une extension, et nous n'hésiterons pas à la déclarer dans plugin.xml:

<postStartupActivity implementation="Heartbeat"/>

et montrer le dialogue en elle.

Les composants de l'interface utilisateur sont principalement des composants de Swing avec quelques extensions de la plate-forme sdk. Tout cela a récemment été enveloppé dans du kotlin ui dsl. Au moment de la rédaction, la documentation a noté que dsl peut changer beaucoup entre les versions principales, nous l'utilisons donc avec une légère crainte:


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()
       }
   }
}

Nous avons créé un dialogue, l'avons montré, reçu des lettres de créance de Jira. Maintenant, nous devons les sauvegarder, et de préférence en toute sécurité, autant que possible. PersistingStateComponent viendra à la rescousse.

4. Dispositif PersistingStateComponent (pas très compliqué)


PersistingStateComponent peut faire deux choses - saveState et loadState: sérialiser et enregistrer l'objet qui lui est transmis et le récupérer du stockage.

Où exactement il doit enregistrer les données, il apprend de l'annotation State. Deux options les plus simples sont mentionnées dans la documentation - spécifiez votre fichier ou stockez tout dans les paramètres de l'espace de travail:

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

Comme nous avons un cas particulier, nous nous tournons vers la documentation pour le stockage des données sensibles.

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)
}

Un autre PersistingStateComponent traitera du stockage de l'heure enregistrée pour différentes branches.

Jira a trouvé la connexion. Avec le stockage des données utilisateur également. Vous devez maintenant suivre en quelque sorte l'événement de paiement sur la succursale pour démarrer le compte à rebours.

5. Abonnez-vous aux événements


La plate-forme IntelliJ offre la possibilité de suspendre Observer sur des événements qui nous intéressent en souscrivant à leurs sujets dans le messageBus du niveau souhaité. Voici le quai , c'est assez intéressant.

Un sujet est un certain point final, une représentation d'un événement. Tout ce que vous avez à faire est de vous abonner et d'implémenter un écouteur qui devrait gérer ce qui se passe.

Par exemple, je dois écouter les extractions dans Git ...

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

... fermeture de l'application (pour se mettre en gage joyeusement) ...

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

... et la sauvegarde des documents (juste pour que ce soit le cas).

subscribeToAppTopic(AppTopics.FILE_DOCUMENT_SYNC) {
    CustomSaveListener()
}

En principe, cela suffit déjà (sinon, vous pouvez toujours écrire le vôtre). Mais que se passe-t-il si nous voulons entendre le moindre mouvement de défilement et de souris?

6. EditorEventMulticaster


Il collecte tout ce qui se passe dans les fenêtres de l'éditeur ouvert - édition, modification de la zone visible, mouvements de la souris - et vous permet de vous y abonner en un seul endroit et immédiatement.

Maintenant, nous avons tout ce dont nous avons besoin. Nous pouvons extraire le nom de la tâche dans Jira de la branche actuelle (si elle existe), calculer le temps passé à travailler dessus et quitter immédiatement le studio pour l'ajouter à la tâche.

7. Code et détails ici


Pour fonctionner, vous avez besoin de la dernière version d'Android Studio (3.6.1).
Pour tester les performances - git et une branche avec un nom qui est au moins similaire à distance à la tâche dans Jira.
Pour que le plug-in ne se contente pas de générer du temps sur la console, il le suive - décommentez la ligne correspondante dans Heartbeat.kt.

8. Liens utiles



PS Et qu'avez-vous finalement choisi?


- Merde, c'est un peu trop mal. Et si je n'écris pas de code? Et si je prends mon nez et essaie de comprendre ce qui s'y passe? Dans le code, au sens de. Après tout, cela prend la plupart du temps.

- Ensuite, faites-le au moins défiler.

- Ce n'est donc pas loin de simuler une activité violente. Et puis, je ne peux pas fermer le studio pendant des semaines et ne pas redémarrer. Peut-être que nous n'avons pas besoin d'un tel bonheur?

"Certainement pas nécessaire." Ensuite, une autre raison est nécessaire, sinon j'ai aimé écrire des plugins. Et je ne comprenais toujours pas vraiment VCS.

"L'utilisez-vous vous-même?"

- Nan. J'ai en quelque sorte appris à me connecter avec mes mains, imperceptiblement pour moi.

All Articles