Sou desenvolvedor do Android e não gostava de trabalhar manualmente.

Quando me acomodei em Skyeng, o sol estava brilhando um pouco mais, a grama não estava mais verde (era o mesmo início da primavera), e o líder da equipe me pediu para escrever para Jira quanto tempo era gasto em codificação e quanto conversas e críticas. Pelo menos uma vez a cada duas semanas.


"Com base nesses dados, estamos tentando entender se é necessário ajustar as estimativas e se há problemas de comunicação na equipe", disseram eles. Mas quem nunca disse a essa babayka? .

Como somos todos trabalhadores remotos, a ideia parecia razoável. E ficou interessante para mim onde foram essas oito horas: ali estavam elas, mas exatamente o quê? No entanto, o registro era incomum. E, em geral, preguiça. Então decidi procurar algo que continuasse funcionando para mim. E no processo de pesquisa, fiquei um pouco empolgado e escrevi meu plugin para o IntelliJ IDEA.

Abaixo você encontrarárevisão subjetiva de ferramentas prontas e minha bicicleta (com fonte).

Eu estudo as soluções que a equipe usa


A primeira coisa que fiz foi descobrir com meus colegas quem usa o quê. As opções são aproximadamente as seguintes:

1. Clockify - um botão para governar tudo


Você precisa de tempo para codificar ou escrever estações? O plugin adicionará um botão (um pacman cinza bastante discreto) em quase qualquer lugar.


Assim, parece no Google Docs


E no GitHub,

você pode admirar Natrekannyi em um painel, ou pode importar para uma tabela e soltá-la no Jira.


A integração ao Jira é fornecida separadamente, também por extensão do navegador

, mas é possível fazer upload de uma tabela com os logs de trabalho obtidos do Clockify no seu calendário de trabalho. E para rastrear o tempo offline, existem aplicativos de desktop para Windows, Linux e Mac. Aplicativos móveis também. A principal funcionalidade é gratuita, mas existem vários planos tarifários com brindes, como privacidade, lembretes e modelos para projetos.

2. Toggl , apenas Toggl


Tudo é o mesmo, mas um pouco mais de vantagens - por exemplo, em um aplicativo de desktop, você pode definir lembretes sobre o registro de horas, ativar o modo pomodoro, até a oportunidade de vincular um aplicativo específico a um projeto específico e configurar o rastreamento automático.


Mas há uma nuance: no primeiro dia de uso, fiquei impressionado com esta janela e notificações com lembretes. Embora a teoria parecesse legal)

3. Script Toggl + Python : quando apenas um botão não é mais suficiente


A invenção do meu colega. De alguma forma, ele decidiu reduzir os gestos para exportar tabelas para Jira e mudou o descarregamento de impostos em Toggl para um script. Você pode colocar um cron e aproveitar a vida.

4. Wakatime - para onde vamos, sem necessidade de botões


Registra tudo sozinho. Portanto, a primeira coisa a lembrar ao conectar sua extensão do navegador é a lista negra.

Além das extensões, fornece várias integrações e um número decente de plug-ins para os IDEs e editores mais comuns.


Os plug-ins para o IDE controlam o tempo gasto em uma ramificação git específica e em um arquivo específico. Na tela, a lista de disponíveis é muito impressionante. Serenyk - “nos planos”, para sua rápida implementação, você pode votar. Alguns plug-ins em uma assinatura paga por US $ 9 por mês.

Além disso, no painel, você pode ver quanto tempo é gasto como porcentagem na escrita de código em diferentes idiomas: se você se lembra de que um projeto Android normal envolve o uso de Kotlin, Java, Groovy e xml - isso faz sentido para si mesmo). E se você trabalhar com o plug-in instalado por um tempo, perceberá que é bastante implacável: o painel obtém o tempo de leitura e gravação de código ativas. E a aderência não entra no monitor com uma aparência de vidro. Escusado será dizer que um amador.

Hmm, o código fonte do WakaTime está aberto: você pode tentar entender como ele funciona ...
, ? IDE JetBrains.

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

Escrevendo sua bicicleta por analogia


Talvez uma arma de batata seja mais útil, mas você não fará nada para fins de pesquisa. Depois de meditar nas fontes do WakaTime, decidi criar meu próprio plug-in que pode rastrear a atividade no IDE, registrar o tempo para escrever e enviar tudo para Jira (em nosso fluxo, os ramos são nomeados após as tarefas em Jira, por isso parece bastante realista).

E para não preencher solicitações ao servidor enquanto estiver trabalhando no código, enviaremos os logs quando o Android Studio for fechado e, até esse momento, armazená-lo localmente.

1. Quais entidades podemos encontrar no código fonte do plugin (e usá-lo por conta própria)?


Não usamos Componentes (este é Legado ) , que anteriormente eram as principais unidades estruturais do plug-in. Pode ser o nível do aplicativo, do projeto ou do módulo. Há um ApplicationComponent na fonte WakaTime, mas eles podem, o código fonte já tem cinco anos e deve manter a compatibilidade com versões anteriores. Os componentes estão vinculados ao ciclo de vida do nível ao qual estão associados. Portanto, por exemplo, ApplicationComponent é carregado quando o IDE é iniciado. Quando usados, eles impedem que o plug-in seja reiniciado sem reiniciar o IDE e geralmente se comportam de maneira desagradável. Portanto, é melhor usar serviços.

Usamos Serviços- principais unidades estruturais atuais. Eles são divididos nos mesmos níveis do aplicativo, projeto e módulo, eles nos ajudarão a encapsular a lógica nos níveis apropriados e armazenar o estado do plug-in.

Diferentemente dos componentes, os Serviços devem ser carregados por conta própria usando o método ServiceManager.getService (). A plataforma garante que todo serviço seja um singleton.

Adicionar ações - eles podem ser um atalho, um item de menu adicional - em uma palavra, eles são responsáveis ​​por tudo o que de alguma forma afeta as ações do usuário no IDE.

Usamos Extensões - qualquer extensão de funcionalidade que será mais complicada que Ações: por exemplo, conecte-se ao ciclo de vida do IDE e faça alguma coisa enquanto mostra uma tela inicial ou antes de sair.

Tudo isso deve ser declarado no arquivo /META_INF/plugin.xml.

2. Plugin.xml e build.gradle



Janela de criação do projeto. Escreveremos nosso plug-in no Kotlin e usaremos o Gradle na montagem.Esta

é a primeira coisa que vemos após criar o plug-in em branco no IDEA (Arquivo -> Novo -> Projeto ... -> Gradle -> IntelliJ Platform Plugin). Ele contém informações sobre as dependências do plug-in e sua breve descrição. Ele deve declarar componentes de plug-in - os componentes, serviços, ações e extensões mencionados anteriormente. Não haverá ponto de entrada específico - será uma ação personalizada ou um evento do ciclo de vida do IDE, dependendo de nossas necessidades.

Nós precisaremos dessas dependências - afinal, queremos escrever um plugin para o estúdio e para que ele possa trabalhar com o Git.

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

O Git4Idea é um plug-in para o sistema de arquivos virtual (VCS) e fornece tópicos, graças aos quais podemos ouvir mais tarde eventos git - como checkouts, por exemplo.

Como também queremos que o plug-in possa trabalhar com o Jira, conectaremos através do gradle uma biblioteca gentilmente fornecida com um cliente restante. Para fazer isso, adicione o repositório Atlassian maven lá:

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

E, na verdade, as 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"
   }
}

Aqui, determinamos a versão do IDE que nos interessa e o caminho para ele (ah, se o Android Studio real fosse iniciado e funcionasse tão rápido quanto a sua versão leve para plug-ins de depuração):

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

E aqui, talvez, algum dia escreveremos sobre uma nova funcionalidade aprimorada. Mas agora não.

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

3. Criando uma interface do usuário


Para inserir algo no Jira, primeiro você precisa fazer login. É lógico fazer isso logo após a abertura do projeto. Parece que precisamos de uma extensão e não hesitaremos em declará-la no plugin.xml:

<postStartupActivity implementation="Heartbeat"/>

e mostre o diálogo nele.

Os componentes da interface do usuário são principalmente componentes do Swing com algumas extensões da plataforma sdk. Tudo isso foi envolvido recentemente no kotlin ui dsl. No momento da redação deste documento, a documentação observava que o dsl pode mudar muito entre as versões principais, então o usamos com um leve medo:


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

Criamos um diálogo, mostramos, recebemos credenciais de Jira. Agora precisamos salvá-los e, de preferência com segurança, o máximo possível. PersistingStateComponent virá para o resgate.

4. Dispositivo PersistingStateComponent (não muito complicado)


PersistingStateComponent pode fazer duas coisas - saveState e loadState: serialize e salve o objeto passado a ele e recupere-o do armazenamento.

Onde exatamente ele deve salvar os dados, ele aprende com a anotação do Estado. Duas opções mais simples são mencionadas na documentação - especifique seu arquivo ou armazene tudo nas configurações da área de trabalho:

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

Como temos um caso especial, recorremos à documentação para o armazenamento de dados confidenciais.

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

Outro PersistingStateComponent tratará de armazenar o tempo registrado para diferentes ramificações.

Jira descobriu o login. Com o armazenamento de dados do usuário também. Agora, você precisa acompanhar de alguma forma o evento de checkout na filial para iniciar a contagem regressiva.

5. Assine eventos


A plataforma IntelliJ oferece uma oportunidade de travar o Observer em eventos de nosso interesse, assinando seus tópicos no messageBus do nível desejado. Aqui está a doca , é bem interessante.

Um tópico é um determinado ponto final, uma representação de um evento. Tudo que você precisa fazer é se inscrever e implementar um ouvinte que deve lidar com o que está acontecendo.

Por exemplo, preciso ouvir check-out no Git ...

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

... fechando o aplicativo (para tempo de penhor feliz) ...

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

... e salvando documentos (exatamente como eram).

subscribeToAppTopic(AppTopics.FILE_DOCUMENT_SYNC) {
    CustomSaveListener()
}

Isso, em princípio, já é suficiente (se não, você sempre pode escrever o seu próprio). Mas e se quisermos ouvir o menor movimento de rolagem e mouse?

6. EditorEventMulticaster


Ele coleta tudo o que acontece nas janelas abertas do editor - edição, alteração da área visível, movimentos do mouse - e permite que você se inscreva em um local e imediatamente.

Agora temos tudo o que precisamos. Podemos extrair o nome da tarefa no Jira da ramificação atual (se houver), calcular o tempo gasto trabalhando nela e sair imediatamente do estúdio para adicioná-lo à tarefa.

7. Código e detalhes aqui


Para executar, você precisa do Android Studio (3.6.1) mais recente.
Para testar o desempenho - git e um ramo com um nome que seja pelo menos remotamente semelhante à tarefa em Jira.
Para que o plug-in não apenas produza tempo para o console, mas o rastreie - remova o comentário da linha correspondente em Heartbeat.kt.

8. Links úteis



PS E o que você escolheu no final?


- Droga, é meio ruim demais. E se eu não escrever código? E se eu cutucar meu nariz e tentar entender o que está acontecendo nele? No código, no sentido de. Afinal, isso leva a maior parte do tempo.

- Então, pelo menos, role-o.

- Portanto, não está longe de simular atividades violentas. E então, não consigo desligar o estúdio por semanas e não reiniciar. Talvez não precisemos de tanta felicidade?

"Definitivamente não é necessário." Em seguida, é necessário outro motivo, caso contrário, gostei de escrever plugins. E eu ainda não entendi o VCS.

"Você usa você mesmo?"

- Não. De alguma forma, aprendi a fazer logon com minhas mãos, imperceptivelmente para mim.

All Articles