我是一名Android开发人员,我不喜欢做手工工作。

当我在Skyeng定居时,阳光明媚一点,草不绿(那是早春的那一天),团队负责人要我写信给Jira,花了多少时间进行编码,花了多少时间进行演讲和复习。每两周至少一次。


他们说:“基于这些数据,我们试图了解是否有必要调整估算值,以及团队沟通中是否存在问题。”但是从来没有告诉过谁这样的“ babayka”。

由于我们都是远程工作者,所以这个想法听起来很合理。这八个小时过去了,这让我感到很有趣:它们在这里,但是究竟是什么呢?但是,日志记录是不寻常的。和一般的懒惰。然后,我决定寻找可以继续为我工作的东西。在研究过程中,我有些不高兴,为IntelliJ IDEA编写了插件。

在下面你会发现对成品工具和我的自行车的主观评价(含资料)。

我研究团队使用的解决方案


我要做的第一件事就是去找我同事使用什么。这些选项大致如下:

1. Clockify-一键统治一切


您需要时间编码或编写码头吗?该插件将在几乎任何地方添加一个按钮(一个相当醒目的灰色pacman)。


因此,它看起来在Google文档中


在GitHub上,

您可以在仪表板上欣赏Natrekannyi,也可以导入表格并将其放入Jira。


可以通过浏览器扩展单独提供与Jira的集成,

但是可以将包含从Clockify获得的工作日志的表上传到您的工作日历。为了离线跟踪时间,有适用于Windows,Linux和Mac的桌面应用程序。移动应用程序也是如此。主要功能是免费的,但是有一些收费计划,其中包括隐私,提醒和项目模板之类的好东西。

2. 切换,仅切换


一切都差不多,但还有更多好处-例如,在桌面应用程序中,您可以设置提醒自己有关时间记录的信息,打开pomodoro模式,甚至有机会将特定的应用程序链接到特定的项目并设置自动跟踪。


但是有一个细微差别:在使用的第一天,我对这个窗口和带有提醒的通知感到惊讶。虽然理论听起来很酷)

3. Toggl + Python脚本:当仅一个按钮不再足够时


我同事的发明。不知何故,他决定减少将表导出到Jira的手势,并将Toggl中税收的卸载转移到脚本中。您可以放一个cron,享受生活。

4. Wakatime-我们去的地方,无需任何按钮


自己记录所有内容。因此,连接其浏览器扩展时要记住的第一件事是黑名单。

除了扩展之外,它还为最常见的IDE和编辑器提供了一些集成和相当数量的插件。


IDE插件跟踪在特定git分支和特定文件中花费的时间。在屏幕上,可用列表非常令人印象深刻。 Serenyk-“在计划中”,对于其快速实施,您可以投票。付费订阅中的某些插件每月收费9美元。

此外,在仪表板上,您可以看到以百分比表示的用不同语言编写代码所花费的时间:如果您还记得一个常规的android项目涉及到Kotlin,Java,Groovy和xml的使用-这本身就很有意义)。而且,如果您使用已安装的插件一段时间,您会发现它相当残酷:仪表板获得了主动读写代码的时间。而且玻璃表面不会粘住显示器。不用说,一个业余爱好者。

嗯,WakaTime的源代码是开放的:您可以尝试了解它的工作原理...
, ? IDE JetBrains.

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

打个比方写你的自行车


也许用马铃薯枪更有用,但是您不会做任何研究用途。在思考WakaTime来源之后,我决定创建自己的插件,该插件可以跟踪IDE中的活动,记录编写时间并将其全部发送给Jira (在我们的流程中,分支是根据Jira中的任务命名的,因此看起来很现实)。

并且为了避免在处理代码时向服务器发送请求,我们将在Android Studio关闭时发送日志,直到此刻将其存储在本地。

1.我们可以在插件的源代码中找到哪些实体(并在我们自己的实体中使用)?


我们不使用Components(这是Legacy,它以前是插件的主要结构单元。可以是应用程序级别,项目级别或模块级别。 WakaTime源代码中有一个ApplicationComponent,但是可以,源代码已经使用了五年,它应保持向后兼容性。组件取决于与其关联的级别的生命周期。因此,例如,IDE启动时将加载ApplicationComponent。使用它们时,它们将阻止重新启动插件而不重新启动IDE,并且通常会令人不快。因此,最好改用服务。

我们使用服务-当前的主要结构单元。它们分为应用程序,项目和模块的相同级别,它们将帮助我们在适当的级别上封装逻辑并存储插件的状态。

与组件不同,必须使用ServiceManager.getService()方法自行加载服务。该平台确保每个服务都是单例。

总之添加操作 -它们可以是快捷方式,也可以是其他菜单项-它们负责在某种程度上影响IDE中用户操作的所有内容。

我们使用扩展 -比操作要复杂的任何功能扩展:例如,连接到IDE生命周期并在显示初始屏幕时或退出之前执行某些操作。

所有这些都应该在文件/META_INF/plugin.xml中声明。

2. Plugin.xml和build.gradle



项目创建窗口。我们将使用Kotlin编写插件,并使用Gradle进行组装,

这是在IDEA中创建插件空白(文件->新建->项目...-> Gradle-> IntelliJ平台插件)后看到的第一件事。它包含有关插件依赖性及其简短描述的信息。它应该声明插件组件-前面提到的组件,服务,操作和扩展。没有具体的入口点-这将是自定义操作或IDE生命周期事件,具体取决于我们的需求。

我们将需要这些依赖关系-毕竟,我们想为studio编写一个插件,以便它可以与Git一起使用。

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

Git4Idea是虚拟文件系统(VCS)的插件,并提供主题,借助这些主题,我们以后可以收听git事件-例如,检出。

由于我们还希望该插件能够与Jira一起使用,因此我们将通过gradle将一个提供良好的库与rest客户端连接。为此,在此处添加Atlassian Maven存储库:

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

实际上是库:

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

在这里,我们确定使我们感兴趣的IDE的版本以及它的路径(哦,如果真正的Android Studio启动并以与调试插件的轻量级版本一样快的速度运行):

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

在这里,也许有一天,我们将撰写有关改进的新功能的文章。但是不是现在。

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

3.创建一个UI


要将某些内容推送到Jira中,您首先需要登录。在项目开始后立即这样做是合乎逻辑的。看起来我们需要扩展,并且我们会毫不犹豫地在plugin.xml中声明它:

<postStartupActivity implementation="Heartbeat"/>

并在其中显示对话。

UI组件主要是来自Swing的组件以及来自平台sdk的一些扩展。这一切最近都包装在kotlin ui dsl中。在撰写本文时,文档指出dsl在主要版本之间可能会有很大的变化,因此我们在使用它时会有些担心:


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

我们创建了一个对话,展示了该对话,并从Jira获得了凭据。现在我们需要保存它们,最好是安全保存。PersistingStateComponent将会解救。

4. PersistingStateComponent设备(不是很复杂)


PersistingStateComponent可以做两件事-saveState和loadState:序列化并保存传递给它的对象,然后从存储中检索它。

他从State批注中学到了确切的数据保存位置。文档中提到了两个最简单的选项-指定文件或将所有内容存储在工作区设置中:

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

由于我们有特殊情况,因此我们转向用于存储敏感数据的文档。

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

另一个PersistingStateComponent将处理存储不同分支记录的时间。

Jira想出了登录名。随着用户数据的存储。现在,您需要以某种方式跟踪分支上的checkout事件以开始倒计时。

5.订阅事件


通过在所需级别的messageBus中订阅观察者的主题,IntelliJ平台可以使观察者关注我们感兴趣的事件。这是码头,这很有趣。

主题是某个端点,是事件的表示。您需要做的就是订阅并实现一个监听器,该监听器应该处理正在发生的事情。

例如,我需要在Git中收听结帐...

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

...关闭应用程序(以愉快的典当时间)...

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

...并保存文档(正是如此)。

subscribeToAppTopic(AppTopics.FILE_DOCUMENT_SYNC) {
    CustomSaveListener()
}

原则上,这已经足够了(如果没有,您可以随时编写自己的代码)。但是,如果我们想听到一点滚动和鼠标移动怎么办?

6. EditorEventMulticaster


它收集在打开的编辑器窗口中发生的所有事件-编辑,更改可见区域,鼠标移动-并允许您在一个位置立即订阅。

现在我们有了所需的一切。我们可以从当前分支(如果有)中选择Jira中的任务名称,计算花费在该任务上的时间,然后立即退出工作室以将其添加到任务中。

7.代码和详细信息在这里


要运行,您需要使用最新的Android Studio(3.6.1)。
为了测试性能-git和一个分支,其名称至少与Jira中的任务在远程相似。
这样,该插件不仅可以将时间输出到控制台,还可以对其进行跟踪-取消对Heartbeat.kt中相应行的注释。

8.有用的链接



PS,您最后选择了什么?


-该死,这太邪恶了。如果我不写代码?如果我if之以鼻并努力了解其中正在发生什么?在代码意义上。毕竟,这花费了大部分时间。

-然后至少滚动它。

-因此,模拟暴力活动不远。然后,我不能关闭工作室数周,也无法重新启动。也许我们不需要这种幸福?

“绝对没有必要。” 然后需要另一个原因,否则我喜欢编写插件。而且我仍然不太了解VCS。

“你自己用吗?”

- 不。我以某种方式学会了用手记录日志,这对我来说是潜移默化的。

All Articles