Soy desarrollador de Android y no me gustaba hacer trabajo manual.

Cuando me instalé en Skyeng, el sol brillaba un poco más brillante, el césped no era más verde (era lo mismo a principios de la primavera), y el líder del equipo me pidió que escribiera en Jira cuánto tiempo se dedicaba a la codificación, y cuánto hablaba y revisaba. Al menos una vez cada dos semanas.


"En base a estos datos, estamos tratando de entender si es necesario ajustar las estimaciones y si hay problemas de comunicación en el equipo", dijeron. Pero a quién nunca se le dijo tal "babayka". .

Como todos somos trabajadores remotos, la idea sonaba razonable. Y me pareció interesante dónde habían ido estas ocho horas: aquí estaban, pero ¿para qué exactamente? Sin embargo, el registro fue inusual. Y en general pereza. Entonces decidí buscar algo que siguiera funcionando para mí. Y en el proceso de investigación me dejé llevar y escribí mi plugin para IntelliJ IDEA.

Abajo encontrarásrevisión subjetiva de herramientas terminadas y mi bicicleta (con fuente).

Estudio las soluciones que usa el equipo.


Lo primero que hice fue averiguar por mis colegas quién usa qué. Las opciones son aproximadamente las siguientes:

1. Clockify : un botón para gobernar todo


¿Necesita tiempo para codificar o escribir muelles? El complemento agregará un botón (un pacman gris bastante discreto) casi en cualquier lugar.


Así se ve en Google Docs


Y en GitHub

puedes admirar a Natrekannyi en un tablero, o puedes importarlo en una tabla y soltarlo en Jira.


La integración en Jira se proporciona por separado, también por extensión del navegador

, sin embargo, es posible cargar una tabla con registros de trabajo obtenidos de Clockify a su calendario de trabajo. Y para el seguimiento del tiempo fuera de línea hay aplicaciones de escritorio para Windows, Linux y Mac. Aplicaciones móviles también. La funcionalidad principal es gratuita, pero hay varios planes de tarifas con beneficios como privacidad, recordatorios y plantillas para proyectos.

2. Toggl , solo Toggl


Todo es casi igual, pero un poco más: por ejemplo, en una aplicación de escritorio, puede configurar recordatorios sobre el registro del tiempo, activar el modo pomodoro, incluso existe la oportunidad de vincular una aplicación específica a un proyecto específico y configurar el seguimiento automático.


Pero hay un matiz: el primer día de uso me sorprendió esta ventana y las notificaciones con recordatorios. Aunque la teoría sonaba genial)

3. Script Toggl + Python : cuando solo un botón ya no es suficiente


La invención de mi colega. De alguna manera, decidió reducir los gestos para exportar tablas a Jira y cambió la descarga de impuestos en Toggl a un guión. Puedes poner un cron y disfrutar de la vida.

4. Wakatime : donde vamos, no se necesitan botones


Registra todo por sí mismo. Por lo tanto, lo primero que debe recordar al conectar su extensión de navegador es la lista negra.

Además de las extensiones, proporciona varias integraciones y un número decente de complementos para los IDE y editores más comunes.


Los complementos para el IDE rastrean el tiempo pasado tanto en una rama específica de git como en un archivo específico. En la pantalla, la lista de los disponibles es muy impresionante. Serenyk - "en los planes", por su rápida implementación, puede votar. Algunos complementos en una suscripción paga por $ 9 por mes.

Además, en el panel de control, puede ver cuánto tiempo se dedica en términos porcentuales a escribir código en diferentes idiomas: si recuerda que un proyecto normal de Android implica el uso de Kotlin, Java, Groovy y xml, esto tiene sentido para sí mismo). Y si trabaja con el complemento instalado durante un tiempo, notará que es bastante despiadado: el tablero de instrumentos entra en el momento de la lectura activa y la escritura del código. Y pegarse no entra en el monitor con un aspecto de cristal. No hace falta decir que es un aficionado.

Hmm, el código fuente de WakaTime está abierto: puedes intentar entender cómo funciona ...
, ? IDE JetBrains.

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

Escribiendo tu bicicleta por analogía


Quizás una pistola de papa sería más útil, pero no harás nada con fines de investigación. Después de meditar en las fuentes de WakaTime, decidí crear mi propio complemento que pueda rastrear la actividad en el IDE, registrar el tiempo para escribir y enviarlo todo a Jira (en nuestro flujo, las ramas llevan el nombre de las tareas en Jira, por lo que parece bastante realista).

Y para no llenar el servidor con solicitudes mientras se trabaja en el código, enviaremos los registros cuando Android Studio esté cerrado, y hasta ese momento lo almacenaremos localmente.

1. ¿Qué entidades podemos encontrar en el código fuente del complemento (y usar en el nuestro)?


No utilizamos componentes (esto es heredado ) , que anteriormente eran las principales unidades estructurales del complemento. Puede ser nivel de aplicación, nivel de proyecto o nivel de módulo. Hay un componente de aplicación en la fuente WakaTime, pero pueden hacerlo, el código fuente ya tiene cinco años y debería mantener la compatibilidad con versiones anteriores. Los componentes están vinculados al ciclo de vida del nivel con el que están asociados. Entonces, por ejemplo, ApplicationComponent se carga cuando se inicia el IDE. Cuando se usan, bloquearán el reinicio del complemento sin reiniciar el IDE y, en general, se comportarán de manera desagradable. Por lo tanto, es mejor usar servicios en su lugar.

Usamos servicios- Unidades estructurales principales actuales. Se dividen en los mismos niveles de la aplicación, el proyecto y el módulo, nos ayudarán a encapsular la lógica en los niveles apropiados y almacenar el estado del complemento.

A diferencia de los componentes, los Servicios deben cargarse por sí solos utilizando el método ServiceManager.getService (). La plataforma asegura que cada servicio sea un singleton.

Agregar acciones : pueden ser un acceso directo, un elemento de menú adicional; en una palabra, son responsables de todo lo que de alguna manera afecta las acciones del usuario en el IDE.

Usamos Extensiones : cualquier extensión de funcionalidad que será más complicada que las Acciones: por ejemplo, conectarse al ciclo de vida IDE y hacer algo mientras muestra una pantalla de bienvenida o antes de salir.

Todo esto debe declararse en el archivo /META_INF/plugin.xml.

2. Plugin.xml y build.gradle



Ventana de creación de proyectos. Escribiremos nuestro complemento en Kotlin y usaremos Gradle para el ensamblado.

Esto es lo primero que vemos después de crear el complemento en blanco en IDEA (Archivo -> Nuevo -> Proyecto ... -> Gradle -> IntelliJ Platform Plugin). Contiene información sobre las dependencias del complemento y su breve descripción. Debe declarar los componentes del complemento: los componentes, servicios, acciones y extensiones mencionados anteriormente. No habrá un punto de entrada específico: será una acción personalizada o un evento de ciclo de vida IDE, según nuestras necesidades.

Necesitaremos estas dependencias; después de todo, queremos escribir un complemento para el estudio y que pueda funcionar con Git.

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

Git4Idea es un complemento para el sistema de archivos virtual (VCS) y proporciona temas, gracias a los cuales luego podemos escuchar eventos de git, como los pagos, por ejemplo.

Como también queremos que el complemento pueda funcionar con Jira, conectaremos a través de Gradle la biblioteca amablemente proporcionada con el resto del cliente. Para hacer esto, agregue el repositorio Maven de Atlassian allí:

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

Y en realidad las bibliotecas:

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

Aquí determinamos la versión del IDE que nos interesa y la ruta a ella (oh, si el verdadero Android Studio comenzó y funcionó tan rápido como su versión liviana para depurar complementos):

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

Y aquí, quizás, algún día escribiremos sobre una funcionalidad nueva y mejorada. Pero no ahora.

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

3. Crear una IU


Para insertar algo en Jira, primero debe iniciar sesión. Es lógico hacer esto justo después de la apertura del proyecto. Parece que necesitamos una extensión, y no dudaremos en declararla en plugin.xml:

<postStartupActivity implementation="Heartbeat"/>

y muestra el diálogo en él.

Los componentes de la interfaz de usuario son principalmente componentes de Swing con algunas extensiones de la plataforma SDK. Todo esto ha sido recientemente envuelto en kotlin ui dsl. Al momento de escribir, la documentación señalaba que dsl puede cambiar mucho entre las versiones principales, por lo que lo usamos con un poco de miedo:


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

Creamos un diálogo, lo mostramos, recibimos credenciales de Jira. Ahora necesitamos guardarlos, y preferiblemente de forma segura, tanto como sea posible. PersistingStateComponent vendrá al rescate.

4. Dispositivo PersistingStateComponent (no muy complicado)


PersistingStateComponent puede hacer dos cosas: saveState y loadState: serializar y guardar el objeto que se le pasó y recuperarlo del almacenamiento.

Donde exactamente debe guardar los datos, aprende de la anotación del Estado. En la documentación se mencionan dos opciones más simples: especifique su archivo o almacene todo en la configuración del espacio de trabajo:

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

Dado que tenemos un caso especial, recurrimos a la documentación para el almacenamiento de datos confidenciales.

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

Otro PersistingStateComponent se ocupará del almacenamiento del tiempo registrado para diferentes ramas.

Jira descubrió el inicio de sesión. Con el almacenamiento de datos del usuario, también. Ahora debe realizar un seguimiento del evento de pago en la sucursal para iniciar la cuenta regresiva.

5. Suscríbase a eventos


La plataforma IntelliJ brinda la oportunidad de colgar a Observer en los eventos que nos interesan suscribiéndose a sus temas en el mensaje del nivel deseado. Aquí está el muelle , es bastante interesante.

Un tema es un determinado punto final, una representación de un evento. Todo lo que necesita hacer es suscribirse e implementar un escucha que debe manejar lo que está sucediendo.

Por ejemplo, necesito escuchar los pagos en Git ...

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

... cerrando la aplicación (felizmente empeñando el tiempo) ...

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

... y guardar documentos (solo para que así fuera).

subscribeToAppTopic(AppTopics.FILE_DOCUMENT_SYNC) {
    CustomSaveListener()
}

Esto, en principio, ya es suficiente (si no, siempre puedes escribir el tuyo). Pero, ¿qué pasa si queremos escuchar el más mínimo movimiento de desplazamiento y mouse?

6. EditorEventMulticaster


Recopila todo lo que sucede en las ventanas abiertas del editor (edición, cambio del área visible, movimientos del mouse) y le permite suscribirse en un solo lugar e inmediatamente.

Ahora tenemos todo lo que necesitamos. Podemos seleccionar el nombre de la tarea en Jira desde la rama actual (si está allí), calcular el tiempo dedicado a trabajar en ella e inmediatamente salir del estudio para agregarla a la tarea.

7. Código y detalles aquí


Para ejecutar, necesita la última versión de Android Studio (3.6.1).
Para probar el rendimiento: git y una rama con un nombre que sea al menos remotamente similar a la tarea en Jira.
Para que el complemento no solo envíe tiempo a la consola, sino que lo rastree, elimine el comentario de la línea correspondiente en Heartbeat.kt.

8. Enlaces útiles



PD: ¿Y qué elegiste al final?


- Maldición, es demasiado malvado. ¿Y si no escribo código? ¿Y si me toco la nariz y trato de entender lo que está pasando? En el código, en el sentido de. Después de todo, esto lleva la mayor parte del tiempo.

- Entonces al menos desplácese.

- Entonces no está lejos de simular actividad violenta. Y luego, no puedo cerrar el estudio durante semanas y no reiniciar. ¿Quizás no necesitamos tanta felicidad?

"Definitivamente no es necesario". Entonces se necesita otra razón, de lo contrario me gustó escribir complementos. Y todavía no entendía realmente VCS.

"¿Lo usas tú mismo?"

- No De alguna manera aprendí a iniciar sesión con mis manos, imperceptiblemente para mí.

All Articles