Наш Jira-плагин Timesheets by Appforest централизовал учёт времени в Testlify, но разработчикам всё равно приходилось останавливаться и переключаться между инструментами, чтобы вручную записать часы. Appforest Timetracker закрывает этот разрыв. Это расширение для VS Code, которое отслеживает активность программирования прямо в редакторе и превращает запись времени в быстрое действие, так что инженеры могут фиксировать время в Timesheets, не покидая IDE. Я вёл его полностью самостоятельно, от идеи до сборки и публикации в Visual Studio Marketplace.
Что я сделал
- Ядро расширения: построено на официальном VS Code Extension API. Слушатели изменений документа, сохранения и выделения сбрасывают метку времени активности, которая сверяется с опросом состояния фокуса окна раз в секунду, чтобы незаметно отличать активное время от простоя, не отвлекая разработчика.
- Учёт времени с учётом Git: расширение считывает текущую ветку Git и автоматически извлекает из неё идентификатор тикета Jira, так что записанное время сразу привязывается к нужной задаче без ручного поиска тикета и перепечатывания.
- Полный жизненный цикл: отвечал за безопасное хранение токена через SecretStorage API VS Code, сборку пакета и ручную публикацию в Visual Studio Marketplace.
Почему это было важно
Автоматическое сопоставление тикета по контексту Git-ветки убрало ручные шаги при заполнении табеля, сократило ошибки в отчётности и дало руководству более чистые данные для планирования спринтов и выставления счетов клиентам.
В одиночку, скромно, по-настоящему
Я единственный контрибьютор, 32 коммита с апреля 2025 года. Это небольшой внутренний инструмент личного масштаба, сделанный, чтобы устранить конкретное ежедневное неудобство, а не крупный продукт.
Куда на самом деле уходит записанное время
Расширение не обращается к REST API Jira напрямую. Оно отправляет данные на собственный бэкенд Timesheets by Appforest, тот же удалённый сервис, который Forge-приложение объявляет в своём манифесте и которое затем само берёт на себя работу с Jira. Оба проекта построены так, чтобы общаться друг с другом, а не с Jira по отдельности, поэтому среди резолверов Forge-приложения есть функции специально для очистки предложений, пришедших из VS Code, после того как их записали.
Как на самом деле работает отслеживание активности и определение тикета
Определение Git-ветки напрямую вызывает git rev-parse --abbrev-ref HEAD во внешнем процессе вместо того, чтобы подключать git-библиотеку, разумное решение для чтения одного значения вместо того, чтобы тащить за собой весь API-поверхность зависимости. Имя ветки проверяется по /^[A-Z]+-\d+$/ перед любой синхронизацией, поэтому фиче-ветка, не соответствующая формату тикета (например, ABC-123), молча пропускается, а не записывается на неверную задачу и не вызывает ошибку. Отслеживание активности не имеет гранулярности «на каждое переключение файла»: это опрос состояния фокуса окна раз в секунду вместе со слушателями изменения документа и сохранения, с порогом простоя в 10 секунд и льготным периодом в 60 секунд, прежде чем сессия считается приостановленной. Прогресс сохраняется в globalState VS Code каждую секунду и восстанавливается при перезапуске, с проверкой самовосстановления: если при восстановлении счётчик последней синхронизации почему-то опережает отслеживаемый счётчик, признак того, что синхронизация была прервана на середине записи, он подтягивается обратно в соответствие вместо того, чтобы расхождение росло дальше.
Аутентификация построена через команды, а не через настройки: отдельные команды (authenticateToken, deleteToken, updateToken, syncNow, resetTime) управляют жизненным циклом токена через диалоги ввода, именно поэтому в расширении вообще нет UI настроек, это осознанный выбор, а не недостающая функция.
Модель данных и масштаб
Здесь нечему масштабироваться за пределы сессии редактора одного разработчика: один индикатор в строке состояния (время по тикету и дневной итог), одна конечная машина состояний простой/активность, одна ежедневная задача сброса в полночь. Более тяжёлая модель данных при таком масштабе не нужна, и её создание означало бы решать проблему, которой у этого инструмента нет.
Своё решение или готовое
Вызов бинарника git во внешнем процессе вместо библиотеки вроде simple-git или isomorphic-git: чтение одного значения (текущей ветки) не оправдывает зависимость, построенную для полного набора Git-операций. Собственный SecretStorage API VS Code вместо самодельного хранилища токенов в зашифрованном файле: платформа уже решает безопасное хранение учётных данных именно для этого случая.
Стек
VS Code Extension API, TypeScript, встроенный в Node child_process для доступа к Git, SecretStorage API VS Code для хранения токена, опубликовано в Visual Studio Marketplace.