Визуализация данных, Разработка ПО
0,0
рейтинг
11 февраля 2011 в 08:02

Управление → Git + TrackStudio — автоматизация разработки tutorial

Это статья о том, как с помощью TrackStudio и Git можно организовать удобный процесс разработки ПО. В стать рассмотрен вариант для ОC Windows. Но при желании не сложно все сделать и для других OC.
Для этого нам понадобиться:
  1. TrackStudio — универсальная система управления задачами.
  2. Git — VCS.
  3. Blat — Маленькая (70kB) open source консольная программа под Windows, которая позволяет отправлять e-Mail по SMTP протоколу из командной строки, с приложенными файлами.
  4. STunnel — Программа, которая позволяет вам зашифровать произвольные TCP подключения внутри SSL. Инструмент доступен для Unix и Windows.
    Нужен если вы используете gmail.com, как почтовый сервис. Так как blat напрямую работать с gmail не может.
Задача:
Организовать рабочий процесс таким образом, что бы при коммите в git, автоматически в TrackStudio задаче добавлялся комментарии с различными типами сообщения и текстом этого комментария был текст сообщения коммита.

Установка

TrackStudio

Делаем все как написано здесь
Установка всех остальных приложении очень проста, замечу только одно, что blat надо положить в папку с git.exe (у меня С:/Program files/Git/bin), или папку, в которой находится blat добавить в PATH.


Настройка

TrackStudio

TrackStudio умеет забирать письма из email и импортировать их как задачи.
Для настройки этого процесса необходимо в файле TS_HOME\etc\trackstudio.mail.properties (если у вас его нет создайте) прописать параметры сбора почты:
mail.pop3.apop.enable=\
mail.store.forward=отправлять не распознанные письма на email
mail.store.fwdaddress=email куда отправлять не распознанные письма
mail.store.host=pop сервер
mail.store.password=ваш пароль
mail.store.port=порт
mail.store.protocol=протокол
mail.store.user=учетная запись, email, с которого импортировать 
trackstudio.emailSubmission=yes
trackstudio.mailimport.interval=интервал проверки почты
вот пример для gmail.com:
mail.pop3.apop.enable=\
mail.store.forward=yes
mail.store.fwdaddress=mymail@gmail.com
mail.store.host=pop.gmail.com
mail.store.password=password
mail.store.port=995
mail.store.protocol=pop3s
mail.store.user=srvmail@gmail.com
Более подробно все описано в документации.


Скрипт для создания правила импорта

Теперь в TS для предка каждой задачи с типом категории «Изменение» или «Ошибка» надо создать правило импорта и желательно, чтобы они создавались от имени администратора. Но каждый раз делать, это ручками накладно — решаем эту проблему написание плагина. В папке TS_HOME\plugins\scripts\after_create_task (в ней размещаются скрипты, которые выполняются после создания задач) создаем файл createRuleImport.bsh со следующим кодом:
  1. /**
  2. * Скрипт создает правило импорта для задачи предка, при создании дочерней задачи.
  3. */
  4. import com.trackstudio.app.adapter.AdapterManager;
  5. import com.trackstudio.exception.GranException;
  6. import com.trackstudio.secured.*;
  7. import com.trackstudio.securedkernel.SecuredMailImportAdapterManager;
  8. import com.trackstudio.securedkernel.SecuredStepAdapterManager;
  9. import java.util.*;
  10. import com.trackstudio.secured.SecuredUserBean;
  11. import com.trackstudio.app.session.*;
  12. import com.trackstudio.app.csv.CSVImport;
  13.  
  14. try {
  15.     //объек для работы с правилами импорта почтовых сообщений
  16.     SecuredMailImportAdapterManager mam = AdapterManager.getInstance()
  17.         .getSecuredMailImportAdapterManager();
  18.         
  19.     //содержит методы для работы с типами сообщений
  20.     SecuredStepAdapterManager sam = AdapterManager.getInstance()
  21.         .getSecuredStepAdapterManager();
  22.         
  23.     //список доступных типов сообщений для задачи и текущего пользователя
  24.     ArrayList arrMS = sam.getAvailableMstatusList(task.getSecure(), task.getId());
  25.     
  26.     //тип сообщения
  27.     SecuredMstatusBean curMS = null;            
  28.          
  29.     String pefixStr = «new»;    
  30.     /**
  31.      * Проверяем тип категории создаваемой задачи.
  32.      * Если категория задачи равна «Ошибка» = наименование категории в TS
  33.      */
  34.     if(task.getCategory().getName().equals(«Ошибка»))
  35.         pefixStr = «bug»;
  36.     
  37.     /**
  38.      * Формируем ключ для импорта сообщений текущей задачи:
  39.      * префик + номер родительской задачи + # + номер задачи
  40.      * этот ключ должен встречаться в теме письма
  41.      * например:
  42.      * new759#2845 любой текст, все равно он будет проигнорирован при добавлении сообщеиня.
  43.      */
  44.     String mailimKey = pefixStr + task.getParent().getNumber() + "#" + task.getNumber();     
  45.     
  46.     /**
  47.      * Надо ли создавать правило.
  48.      * Так как задача предок может иметь несколько подзадач,
  49.      * то необходимо проверять существование правила импорта,
  50.      * что бы не плодить их.
  51.      */
  52.     boolean found = false;
  53.     
  54.     for (int i = 0; i < arrMS.size(); i++) { 
  55.         curMS = (SecuredMstatusBean) arrMS.get(i);
  56.         
  57.           msn = curMS.getName();
  58.         
  59.         //«Комментрарий» или «Комментировать» это наименования типа сообщения        
  60.         if(msn.compareToIgnoreCase(«Комментарий») == 0 || msn.compareToIgnoreCase(«Комментировать») == 0) {
  61.             //Получаем данные по пользователю root
  62.             SecuredUserBean adminUser = new SecuredUserBean(CSVImport.findUserIdByLogin(«root»), sc);
  63.             //Текущий контекст пользователя
  64.             SessionContext needSc = task.getSecure();
  65.             //проверяем авторизировался ли root
  66.             if(SessionManager.getInstance().existUserSession(adminUser.getUser())) {
  67.                 for(SessionContext curSc: SessionManager.getInstance().getSessions()) {
  68.                     if(curSc.getUser().getLogin().equals(«root»)) {
  69.                         //если да то получаем его контекст
  70.                         needSc = curSc;
  71.                         break;
  72.                     }
  73.                 }
  74.             }
  75.             else {
  76.                 //если нет, то создаем его контекст
  77.                 needSc = SessionManager.getInstance().getSessionContext(
  78.                     SessionManager.getInstance().create(adminUser.getUser()));
  79.             }
  80.             
  81.             if(!found)
  82.                 for (SecuredMailImportBean curMailS: mam.getAllAvailableMailImportList(needSc, task.getParentId())) {            
  83.                     // Ищем правило импорта новых задачь у предка.                    
  84.                     found = curMailS.getKeywords().equals(pefixStr + task.getParent().getNumber());
  85.                     if(found)                        
  86.                         break;
  87.                 }
  88.             
  89.             if(!found) {         
  90.                 /**
  91.                  * если не нашли, то создаем новое правило импорта для предка
  92.                  * от имени root, так как TS поддерживает возможность создания
  93.                  * пользователями индивидуальных правил импорта почты, необходимо
  94.                  * что бы это правило было видно всем.
  95.                  */
  96.                 mam.createMailImport(needSc, pefixStr + task.getParent().getNumber(),
  97.                     task.getParentId(), pefixStr + task.getParent().getNumber(), 1, i,
  98.                     task.getCategoryId(), curMS.getId(), "", true, false);                    
  99.                 found = true;
  100.             }
  101.         }        
  102.      }         
  103.     //Добавляем значение для UDF поля с наименование «Имя ветви в git».
  104.     AdapterManager.getInstance().getSecuredUDFAdapterManager().setTaskUDFValueSimple(
  105.         task.getSecure(),task.getId(),«Имя ветви в git», mailimKey);
  106. }
  107. catch(GranException e) {
  108.     throw new com.trackstudio.exception.UserMessageException(e.getMessage());
  109. }
  110. return task;

Скрипт создали, теперь в TS выбираем в меню «Управление задачами -> Категории»,
щелкаем сначала по категории с наименование «Изменение»,

открываем вкладку «Триггеры» и в списке «AFTER Триггер» отмечаем триггер, который называется createRuleImport.bsh.

Проделываем тоже самое и для категории «Ошибка».

Если все сделано правильно, то при создании новой задачи у ПРЕДКА появится правило импорта newНОМЕР_ПРЕДКА или bugНОМЕР_ПРЕДКА. При отправки письма на email, с которого импортируется почта, с темой «newНОМЕР_ПЕРЕДКА новая задача», TS создаст задачу в ПРЕДКЕ с наименование, которое равно теме письма. А если отправить письмо в теме, которого есть ключ newНОМЕР_ПЕРЕДКА#НОМЕР_ЗАДАЧИ (при этом задача существует), то TS импортирует письмо, как комментарии к задаче и сообщение комментария будет тело письма. При чем если к письму прикрепить файл, то TS прикрепит его к задаче.


Каким образом добавить UDF поле

Для этого в TS верхнем меню выбрать «Управление задачами -> Процессы», открыть интересующий вас процесс и во вкладке «Дополнительные поля» кликнуть по кнопке «Строка».

В названии указать нужное вам имя, в нашем случае «Имя ветви в git», и нажать кнопку Сохранить. Но это все лишь для того, что бы скопировать и быстро вставить в sh при создании новой ветки в git, типа удобно.


Скрипт для обработки сообщении полученных через почту

TS уже умеет из писем создавать сообщения с типом «Комментарии» к задачам.
Теперь нам необходимо сделать, чтобы TS изменил типа сообщения на «Завершить» или «Исправить» для категории «Изменение» или «Ошибка» соответственно («Комментарии», «Завершить», «Изменение» и «Ошибка» — наименования типа сообщения и категорий, они зависят от того как вы настроите свой workflow в TS; если вы используете демонстрационную русскую бд, то они будут именно такими). Нам нужно создать скрипт, который будет искать в теле сообщения, какой нибудь ключ, который будет сообщать TS, что необходимо поменять тип сообщения. Я предлагаю использовать конструкцию [new_state=done], но это уже на ваше усмотрение. Создадим в папке TS_HOME\plugins\scripts\before_add_message, в которой размещаются скрипты, выполняемые до добавления сообщения, файл changeType.bsh с кодом:
  1. /**
  2. * Скритп изменяет тип импортируемого сообщения если находит в теле сообщения
  3. * конструкуцию [new_state=type], где type может быть done или start
  4. */
  5. import java.util.*;
  6. import java.util.regex.*;
  7. import java.io.*;
  8.  
  9. try {
  10.     if(message.description != null)
  11.     { 
  12.         String[] tempArr = null;
  13.         //Ищем нужную нам конструкцию в сообщение        
  14.         String pattern = ".*\\[(\\w*)=(\\w*)\\].*";
  15.         Pattern p = Pattern.compile(pattern, Pattern.MULTILINE);
  16.         Matcher m = p.matcher(message.description);
  17.         if (m.find())
  18.              tempArr = new String[]{m.group(1), m.group(2)};        
  19.         //проеряем ялсяется ли первый параметер директивой к смене типа сообщения
  20.         if(tempArr != null && tempArr[0].toLowerCase().equals(«new_state»)) {
  21.             //определяем на какой тип изменить текущий тип сообщения
  22.             if(tempArr[1].toLowerCase().equals(«done»)) {                
  23.                 //Удаляем из сообщения директиву
  24.                 message.description = message.description.replaceFirst("\\[new_state=done\\]", "");
  25.                 //проверяем задаче какой категории принадлежит
  26.                 if(message.getTask().getCategory().getName().equals(«Изменение»))
  27.                     //устанавливаем новый тип сообщения по его наименованию
  28.                     message.setMstatus(«Завершить»);
  29.                 if(message.getTask().getCategory().getName().equals(«Ошибка»))
  30.                     message.setMstatus(«Исправить»);
  31.             }
  32.             if(tempArr[1].toLowerCase().equals(«start»)) {
  33.                 message.description = message.description.replaceFirst("\\[new_state=start\\]", "");
  34.                 if(message.getTask().getCategory().getName().equals(«Изменение») ||
  35.                   message.getTask().getCategory().getName().equals(«Ошибка»))
  36.                     message.setMstatus(«Начать работу»);
  37.             }
  38.         }
  39.     }
  40. }
  41. catch(Exception e) {
  42.     throw new com.trackstudio.exception.UserMessageException(e.printStackTrace());
  43. }
  44. return message;
Скрипт создали, теперь в TS выбираем в меню «Управление задачами -> Процессы», щелкаем сначала по процессу с наименование «Изменение», затем выбираем вкладку типы операции и кликнем по операции с наименованием «Комментарий»,

открываем вкладку «Триггеры» и в списке «BEFORE Триггер» отмечаем триггер, который называется changeType.bsh.

Проделываем тоже самое и для процесса «Ошибка».

Вроде все, можно пробовать.
Создаем задачу -> копируем из поля «Имя ветви в git» значение ->

создаем письмо с темой, в которую вставляем скопированное значение -> затем в теле письма пишем любой текст и добавляем директиву [new_state=done].

По идее после импорта письма у задачи измениться состояние она должна перейти в состояние завершена и сообщением к этому состоянию будет тело письма.


Итог

Мы расширили способности TS, теперь она умеет:
  • Автоматически создавать правила импорта для создания новых сообщении и задач.
  • Менять статус сообщения в зависимости от найденной в теле письма директивы.
  • Прикреплять файлы к задаче, если они прикреплены к письму.
    Этой способностью TS наделили разработчики, но она нам понадобиться в дальнейшем.

STunnel

Если вы не используете gmail.com как почтовый сервер, то пропустите этот пункт!
В папке куда вы установил stunnel находим файл stunnle.conf (C:\Program Files\stunnel\stunnel.conf). Меняем его содержимое на следующее:
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
 
debug = 7
output = stunnel.log
 
client = yes
 
[ssmtp]
accept = 127.0.0.1:465
connect = smtp.gmail.com:465
И для того, чтобы stunnel запускался как служба автоматически выполняем в командной строке:
«C:\Program Files\stunnel\stunnel.exe» –install
источник: Отправка писем из командной строки Windows используя аккаунт GMail


Git

Все что связано с TS производилось на стороне сервера. А теперь все настройки будут на конкретном рабочем месте.
Для того чтобы настроить поведение git при совершении коммита, нам надо изменить 2 хука первый post-commit и prepare-commit-msg, первый выполняется в момент коммита, второй когда формируется сообщение коммита. Файлы хуков лежат в директории DIR_YOUR_REPO/.git/hooks.
  • В файле prepare-commit-msg генерацию шапки сообщения.
    #!/bin/sh
    case "$2,$3" in
      merge,)
        perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/… /#/; print' "$1" ;;
      *) ;;
    esac

    if [ "`git branch | grep -e "^\*.\(new\|bug\)[0-9]\+#[0-9]\+" | cut -f2 -d ' '`" != "" ]; then
        #Помещаем в начало файла с сообщением ключи для отправки письма.
        echo «sendmail» > temp_msg
        echo «to= srvemail@gmail.com» >> temp_msg
        echo "[new_state=done]" >> temp_msg
        cat $1 >> temp_msg
        cat temp_msg > $1
        rm temp_msg
    fi
  • В файле post-commit настроим сбор информации о изменения и отправку почты.
    #!/bin/sh
    # получаем из переменной GIT_AUTHOR_IDENT майл текущего коммитера
    sender=`git var GIT_COMMITTER_IDENT | cut -f1 -d '>' | cut -f 2 -d '<'`

    #проверяем наличие в первой строке сообщения коммита текста sendmail
    if [ `git log -1 | sed «s/[ ]*//g» | grep -e "^sendmail$"` == «sendmail» ]; then

        #формируем тему сообщения, которая берется из названия ветви
        #но это пожеланию, можно сделать чтоб тема была взята из первой строчки основного текста сообщения
        subject=`git branch | grep -e "^\*.\(new\|bug\)[0-9]\+#[0-9]\+" | cut -f2 -d ' '`
        if [ "`git log -1 | sed "s/[]*//g" | gre grep -e "^newroot\=" | cut -f2 -d '='`" != "" ]; then
            subject=`git log -1 | sed «s/[ ]*//g» | grep -e "^newroot\=" | cut -f2 -d '=' | cut -f1 -d '#'`
            subject="$subject#`git branch | grep -e "^\*.\(new\|bug\)[0-9]\+#[0-9]\+" | cut -f2 -d '#'`"

        fi

        #определяем из третей строчки сообщения коммита майл,
        #на который необходимо отправить письмо,
        #по-умолчанию ставиться майл текущего коммитера.
        to=$sender
        if [ "`git log -1 | sed «s/[ ]*//g» | grep -e "^[Tt][Oo]\=" | cut -f2 -d '='`" != "" ]; then
            to=`git log -1 | sed «s/[ ]*//g» | grep -e "^[Tt][Oo]\=" | cut -f2 -d '='"`
        fi

        #формируем имя патчфайла
        patchname="$(date +%j%H%M%s).patch"

        # сохраняем diff соверщеного комита,
        (git diff-index -p -M HEAD^) > $patchname

        #берем из лога git последние сообщение за исключениием управляющего текста
        git log -1 | grep -v "^Date:" | grep -v "^commit " | grep -v "^Author:" | grep -v " *Signed-off-by: " | grep -v "^[ ]*sendmail[ ]*$" | grep -v "^[ ]*newroot\=" | grep -v "^[ ]*[Tt][Oo]\=" | grep -v ".*$subject.*" | sed -e "/^[ ]*$/d" -e "/^$/d" >> temp.tmp
        echo «shortstat» >> temp.tmp
        git diff-index --stat HEAD^ >> temp.tmp

        #отправляем по средствам blat
        blat -charset «utf-8» -f $sender -server localhost -port 465 -u useremail@gmail.com -pw password -to $to -bodyF temp.tmp -subject $subject -base64 -attach $patchname > logSendMail.log

        rm $patchname
        rm temp.tmp
        edit logSendMail.log
        sleep 2s
        rm logSendMail.log
    fi
Эти файлы должны лежать у всех программистов работающих над проектом.


Как это работает

Самое важно, при начале работы над новой задаче, необходимо в оперативном репозитории текущего программиста, создать ветвь с именем, которое создала TS при формировании задачи.
Хук prepare-commit-msg вставляет в начало сообщения коммита параметры отправки письма, такие как:
  • sendmail — отправлять ли письмо. Если в сообщении нет строчки содержащей только это слово, то письмо отправлено не будет.
  • to — на какой email отправить. Если его нет то письмо будет отправлено отправителю.
  • [new_state=done] — директива для TS, что необходимо присвоить новому сообщению тип «Завершен» или «Исправлено».
    Этот параметр можно не указывать, тогда TS будет добавлять новые сообщения с типом «Комментарий».
  • newroot — этот параметр обозначает, надо переделать тему письма. В TS есть возможность перемещать подзадачи из одной задачи в другую, так вот чтоб не создавать новой ветки можно просто указать нового родителя текущей задачи.
    Например, вы создали подзадачу (номер 2084, номер предка 754, ключ new754#2084) и начали над ней работу, а потом поняли, что подзадача должна принадлежать другой родительской задаче (с номером 458, новый ключ new458#2084) и переместили ее к ней. Для того, чтобы в git не заводит новую ветку, можно в сообщении коммита добавляем следующий код
    newroot=new458
    Важно: каждый параметр должен находиться в отдельной строке, количество пробелов или знаков табуляции не влияют на его обнаружение.
Хук post-commit проверяет сообщение коммита на наличие параметров отправки. формирует patch файл с совершенными изменениями и письмо, за тем отправляет письмо от имени коммитера, на указанный в параметре «to» email.Вот пример примениния измениний:
Вводим в командную строку
$ git add --all & git gui


Затем нажимаем Ctrl + Enter и через интервал, который вы установли сборщику почты в TS, провермяем состояние задачи.

Здесь комментарий оформлен html, но это тема отдельного поста.

Заключение

Стандартный рабочий процесс состоит из 4 основных этапов:
  1. Постановка задачи в TS и копировании имени ветви для git.
  2. Создание ветви в git и переход на нее.
    Можно выполнить одной командой:
    $ git checkout -b имя_ветви
  3. Выполнение задачи.
  4. Завершение работы над задачей в TS, совершением коммита в git.
Этап 3 можно расширить промежуточными коммитами в сообщении, которых не будет директивы [new_state=done] — TS будет добавлять комментарии к задаче.


Почему используется именно такой механизм

Причина в том, что у TS пока нет интеграции с SCM GIT.
Да и когда появиться, не понятно каким образом будет реализована работа с распределенными репозиториями.
А данное решение позволяет работать над задачей нескольким программистам, у которых свой зоопарк репозиториях. А потом объединять их в один центральный, в котором порядок и чистота.
К тому же, очень удобно работать не имея прямого доступа до TS.
Создавать задачи может руководитель проекта и назначать на них ответственными конкретных людей. К ним на почту будут приходить письма о том, что создана задача или, что его назначили ответственным. Он в сообщении письма видит какая поставлена задача и имя ветви для git, начинает работу над задачей. По окончанию работы, спокойно делает коммит в репозитории и может уже не волноваться о том, что задачу надо завершить. Причем он также может удаленно создавать подзадачи зная ключ задачи предка, отправляя письма на email, с которого импортируется почта в TS с темой, в которой присутствует нужный ключ. В ответ также будут приходить письма о том, что он создал задачу.

Источники

Артем Зубков @artzub
карма
64,2
рейтинг 0,0
Визуализация данных, Разработка ПО
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Управление

Комментарии (49)

  • +4
    Вопрос не по теме интеграции, а по постановке задачи.

    > что бы при коммите в git, автоматически в TrackStudio задача получала статус завершена

    А разве коммит в систему контроля версий означает, что задача закрыта?

    Коммит — это лишь внесение дельты под контроль версий. В моём понимании задача закрыта тогда, когда вносимые изменения протестированы и кто-то, выполняющий роль проверяющего, посчитал, что по задаче больше не надо ничего делать и её можно закрыть.

    Поправьте, плз, если я недопонял постановку задачи или логику работы TrackStudio.

    А за техническое решение — мой плюс.

    • +3
      да согласен коммит — это всего лишь применение изменений.
      Я лучше напишу так:
      что бы при коммите в git, автоматически в TrackStudio задаче добавлялся комментарии с различными типами сообщения.
      • +4
        Зачтено, давай зачётку. :)
    • +2
      В Redmine можно указать просто номер задачи в commit message #146 и коммит будет виден из задачи. А можно написать что-то типа fixes #146 и состояние задачи будет изменено. То есть, задача не обязательно будет закрыта, а, например, помечена разработчиком, как реализованная — в противном случае разработчику пришлось бы делать это отдельно в баг-трекере. Конечно, совершенству нет предела — неплохо бы и затраченное время заполнять автоматом, но такого, вроде, нет.
      • 0
        Да, Редмайн весьма продвинут, в том числе и в этом вопросе. Но, повторюсь, автоматическое закрытие записи — это не есть хорошо. Только человек и только после детального разбора результатов работы.
      • 0
        В TS вообще есть интеграция с многими SCM, и она работает по тому принципу что вы описали.
        Но пока они не хотят реализовывать интеграцию с Git, но мне это не мешает.
        • 0
          Максим Крамаренко в своем блоге уже сказал, что интеграция с git скоро будет.
          • 0
            ну вот и хорошо!
            • 0
              Да, не ожидал что тема интеграции с git будет настолько популярна :-)

              Про Git/Mercurial спрашивали буквально пару раз, а про bazaar никто не спрашивал, но мы сделали т.к. сами его используем.
  • +1
    Замечание по поводу скрипта, создающего правило импорта: гораздо проще создать одно правило вручную и написать простенький скрипт Create Task/Before Trigger (а возможно InsteadOf Trigger), который будет разбирать название создаваемой задачи (которое суть поле subject письма) и описание задачи (которое формируется из тела письма), вырезать нужное-ненужное и создавать хоть 100500 задач в нужных местах.
    • 0
      приведи пример!

      У меня то подразумевается в первую очередь добавление комментариев к существующим задачам. А сама возможность создания задач по средствам импорта писем это уже побочное действие TS (но уж очень удобное)
      • +1
        Ну комментарии к существующим задачам создаются непосредственно из писем с решеткой и номером задачи в subject. Нужно только правило создания повыше засунуть, в корень проекта (не корень TS)
        • 0
          То есть как я понял, если в корневую папку всех существующих проектов положить правило, которое будет создавать сообщение с типом комментарии, то если в subject будет #номер_задачи TS создаст сообщение в нужном месте?
          • +2
            если через условия правила пролезает и категория совпадает — создаст.
    • 0
      а как же объяснить TS что надо создать задачу именно в нужном проекте, если правило будет висеть в корне.
      То есть перемещать в нужное место так?
  • 0
    У утилиты №3 говорящее название :-)
  • 0
    зачем надо было «так» замазывать artzub@gmail.com если оно отлично читается? :)
    • 0
      вообще хз, зачем я замазал мыло! gmail и так спам фильтрует, да и не думаю что здесь кто-то этим заниматься будет.
  • 0
    а как оно если сравнить с git + trac vs git + TrackStudio?
    • +1
      если четно меня trac не привлекает.
      По этой причине его не пробовал и соответственно ни чего не могу сказать по поводу сравнения.
    • 0
      Абсолютно так же как и git + MantisBT или git + Redmine. Все умеют работать с git.
      Кому как больше нравится.
  • 0
    А я почту так шлю:

    #!/usr/bin/python
    # -*- coding: utf8 -*-
    MAILSERVER='10.0.0.5'
    FROM = 'dem@nospam.ru'
    import smtplib
    from email.MIMEMultipart import MIMEMultipart
    from email.MIMEBase import MIMEBase
    from email.MIMEText import MIMEText
    from email.Utils import COMMASPACE, formatdate
    from email import Encoders
    import os

    def sendMail(to, subject, text, files=[],server=MAILSERVER):
    assert type(to)==list
    assert type(files)==list
    fro = FROM

    msg = MIMEMultipart()
    msg['From'] = fro
    msg['To'] = COMMASPACE.join(to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject
    text_message = MIMEText(text)
    text_message.set_charset('UTF-8')
    msg.attach( text_message )

    for file in files:
    part = MIMEBase('application', «octet-stream»)
    part.set_payload( open(file,«rb»).read() )
    Encoders.encode_base64(part)
    part.add_header('Content-Disposition', 'attachment; filename="%s"'
    % os.path.basename(file))
    msg.attach(part)

    smtp = smtplib.SMTP(server)
    smtp.sendmail(fro, to, msg.as_string() )
    smtp.close()

    sendMail(
    [«dem@nospam.ru»],
    «test»,«Проверка»
    )
    #[«photo.jpg»,«memo.sxw»]
    • +1
      Парсер гад:

      #!/usr/bin/python
      # -*- coding: utf8 -*-
      MAILSERVER='10.0.0.5'
      FROM = 'dem@nospam.ru'
      import smtplib
      from email.MIMEMultipart import MIMEMultipart
      from email.MIMEBase import MIMEBase
      from email.MIMEText import MIMEText
      from email.Utils import COMMASPACE, formatdate
      from email import Encoders
      import os
      
      
      
      def sendMail(to, subject, text, files=[],server=MAILSERVER):
          assert type(to)==list
          assert type(files)==list
          fro = FROM
      
          msg = MIMEMultipart()
          msg['From'] = fro
          msg['To'] = COMMASPACE.join(to)
          msg['Date'] = formatdate(localtime=True)
          msg['Subject'] = subject
          text_message = MIMEText(text)
          text_message.set_charset('UTF-8')
          msg.attach( text_message )
      
          for file in files:
              part = MIMEBase('application', "octet-stream")
              part.set_payload( open(file,"rb").read() )
              Encoders.encode_base64(part)
              part.add_header('Content-Disposition', 'attachment; filename="%s"'
                             % os.path.basename(file))
              msg.attach(part)
      
          smtp = smtplib.SMTP(server)
          smtp.sendmail(fro, to, msg.as_string() )
          smtp.close()
      
      
      sendMail(
              ["dem@nospam.ru"],
              "test","Проверка"
          )
      #["photo.jpg","memo.sxw"]    
      
      • 0
        и на gmail хорошо отправляет!
        если да, то такой вариант более удобен, 2 связки сразу уходят.
        • +1
          Да вот такая версия отправила на раз:

          #!/usr/bin/python
          # -*- coding: cp1251 -*-
          MAILSERVER='gmail-smtp-in.l.google.com'
          FROM = 'dem@nospam.ru'
          import smtplib
          from email.MIMEMultipart import MIMEMultipart
          from email.MIMEBase import MIMEBase
          from email.MIMEText import MIMEText
          from email.Utils import COMMASPACE, formatdate
          from email import Encoders
          import os
          
          
          
          def sendMail(to, subject, text, files=[],server=MAILSERVER):
              assert type(to)==list
              assert type(files)==list
              fro = FROM
          
              msg = MIMEMultipart()
              msg['From'] = fro
              msg['To'] = COMMASPACE.join(to)
              msg['Date'] = formatdate(localtime=True)
              msg['Subject'] = subject
              text_message = MIMEText(text)
              text_message.set_charset('UTF-8')
              msg.attach( text_message )
          
              for file in files:
                  part = MIMEBase('application', "octet-stream")
                  part.set_payload( open(file,"rb").read() )
                  Encoders.encode_base64(part)
                  part.add_header('Content-Disposition', 'attachment; filename="%s"'
                                 % os.path.basename(file))
                  msg.attach(part)
          
              smtp = smtplib.SMTP(server)
              smtp.sendmail(fro, to, msg.as_string() )
              smtp.close()
          
          
          sendMail(
                  ["NOSPAM@gmail.com"],
                  "test","Testing"
              )
          #["photo.jpg","memo.sxw"]    
          


          Только учтите у меня IP соответсвует домену моему и я из него и отправляю хотя на адрес гугловского сервера. Если что шлите через SMTP своего провайдера.
      • 0
        и на gmail хорошо отправляет? это вопрос опечатался.
  • 0
    А чем не устраивает входящий в комплект msmtp.exe? Умеет слать и через gmail тоже.
    В папке профиля создается файл msmtprc.txt с таким содержимым — все прекрасно работает
    # setup some defaults
    defaults
    tls_trust_file C:/Git/bin/curl-ca-bundle.crt
    logfile ~/.msmtp.log

    # create an account called «default»
    account default

    # setup server host and port
    host smtp.gmail.com
    port 587

    # enable TLS
    tls on

    # set FROM address
    from username@gmail.com

    # setup authentication
    auth on
    user username@gmail.com
  • –1
    Сочувствую тем, кто использует TrackStudio. Более неудобного и кривого продукта не встречал (опыт использования 2 года). Наконец-то начинаем с него съезжать. Авторам данного творения посылаю лучи.
    • 0
      а что вас не устраивает в нем?
      • –1
        Общее убожество, глючность (постоянно бьются страницы), абсолютно ебанутая система переноса задач — это первое, что пришло на ум. У нас в конторе 6 менеджеров, ни один положительно не отзывается о трек студио спустя 2 года использования. Не могу назвать ни одной вещи, чем бы TrackStudio мне нравился.
        • 0
          И, вдобавок, иностранные ребята не говорят «чтооо?» при упоминании TrackStudio.
          • 0
            «не» следует убрать из предыдущего поста
        • 0
          а вы какой версией пользуетесь?
        • +1
          ну и конечно не кто вам не запрещает написать свой интерфейс для TS у нее же есть такая возможность, я как нибудь напишу статью.
          • 0
            Мы эту вещь купили чтобы она экономила нам время и деньги, а не для того, чтобы потратить на неё время наших программистов. CSS-ку для хоть какой-то оптимизации интерфейса у нас кто-то всё-таки сделал, но проблему бьющихся страниц CSS-ка не решила, как вы понимаете.

            Версия 3.5.
            • +1
              эта стать посвящена версии 4,
              она много чем отличается от 3.5 и проблем с интерфейсом нет.
              ну вообщем на вкус и цвет товарищей нет.
              Видимо у меня просто больше положительных впечатлении от TS и моим требованиям все соответствует.
            • +1
              В этом корень проблем. Мне тоже не нравится, как 3.5 работает «из коробки». Но возможностей настроить под себя у TS гораздо больше, чем у конкурентов.
              • 0
                У продукции «Автоваза» тоже…
        • 0
          1) А какая именно 3.5? В последнее время (год-полтора) багрепорты по 3.5 приходили с интенсивностью 1 штука в пару месяцев (т.е. довольно редко). Сейчас никаких открытых проблем с выводом страниц в 3.5 нет, насколько я знаю.

          2) Что не нравится с переносом задач, если не секрет? Вроде обычный cut/paste, я даже не представляю как еще можно сделать.

          3) Интерфейс в 3.5 был в самом деле не слишком удобным, но эта версия была выпущена в 2006 году, с тех пор много изменилось. Вот список what's new от 4.0:
          www.trackstudio.ru/whatsnew.html
          • 0
            1. 3.5.56. Интересный момент: мы ни разу не писали багрепорты по данному продукту. Даже не могу объяснить почему. Может быть из-за того, что всего в нём не перечинишь %)

            2. Большинство наших менеджеров в первое время вообще не понимали, что таким способом можно перенести задачи. Потом один всё-таки допёр до этого (и ведь нельзя сказать, что у нас тормоза работают), после чего все остальные (включая меня) удивились, что оно так странно и неудобно сделано. Имхо, перенос должен быть в т.ч. в настройках задачи, т.е. при её редактировании должна быть возможность перенести её в любую ветвь иерархии.

            3. Мы купили эту версию в первой половине 2009 года, т.е. далеко не в бог знает какие времена.
            • +1
              1) Если глюки повторяются, то обычно исправляем все в течение 1-2 недель, список известных багов в 3.5.77 сейчас практически пустой.

              2) Перенос через редактирование задачи был в TrackStudio 3.0, потом от него отказались из-за непонимания со стороны пользователей назначения этого поля. Перенос задачи — это действие, поэтому пользователи ожидали увидеть какую-нибудь кнопку/менюшку, а не просто поле выбора новой родительской задачи. Кроме того, часто нужно переносить множества задач по условиям фильтрации (например, «все открытые задачи переносим в новую версию»), через редактирование свойств задачи это тоже трудно сделать.

    • 0
      Мне тоже интересно :-)
  • 0
    Спасибо, ушло в избранное.
    В самом начале только поправьте, пожалуйста: можно организовать удобную процесс разработки…
    • 0
      спасибо, поправил.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.