Home » Posts tagged "trac"

DefaultCcPlugin 改 Component 不會增加 Cc 列表的問題...

TracDefaultCcPlugin 裡有個很喜歡用的 feature:改 component 後會自動增加該 component 的 cc list。但這在 Changeset 13747 被「修正」掉了:

0.3dev: Only append to CC field when ticket is created. Fixes #11624.
Previously the CC field would be modified on Preview and during any ticket change, however these would often go undetected since the field is de-duplicated on save.

而這個 plugin 還是用 Subversion 管理,本來找了一堆 svn2git 的工具,後來發現 Git 所以靠 git-svn 拉下來再改,然後再丟出來:「gslin/defaultccplugin」。

Trac 關票時的資訊...

Trac 關票時一般都是由開票的人關 (i.e. Reporter),今天遇到的情況是這樣,在關票時的畫面上你會不知道是誰開的:

只要往上一點拉就會看到 Reporter 資訊 XD 這通常會發生在螢幕沒打直的人,直接拉到最下方的情況 XD

試著用 CSS 的 position: sticky 但抓不太到要的效果,決定還是開 jQuery 下去解決 XD

        // Copy reporter information to action section
        if ($('#action_resolve_resolve_resolution').length > 0) {
            var reporter = $('#h_reporter').parent().find('.trac-author, .trac-author-user')[0].outerHTML;

            $('#action_resolve_resolve_resolution').each(function(){
                $(this).parent().append('<span class="hint">(This ticket is created by ' + reporter + ')');
            });
        }

當下寫得很隨性,之後也許會再改... (會更新到「Trac - Gea-Suan Lin's Wiki」這邊)

Trac 的 DuplicateTicketSearchPlugin

DuplicateTicketSearchPluginTrac 的 plugin,在開新票時會搜尋系統內可能重複開過的票給出建議。

之前在寫 wiki 上的「Trac」條目時沒寫到,大概是最早的時候都沒裝,後來有人找出來要我裝的東西,所以印象沒那麼深刻。剛剛是在找 Trac + Elasticsearch 有沒有現成的方案可以搭,結果先看到這個...

產生的效果是這樣,在改變 summary 後會出現 (focus 從 summary 移開時):

當然就算裝了還是難免會重複開 (尤其組織夠大的時候),但算是有幫助的東西...

Trac 1.2 上惡搞 TracTicketReferencePlugin 讓他會動...

TracTicketReferencePlugin 是個 Trac 上設定 ticket 之間關聯性的 plugin,與子母票有比較強烈的關係不同,有些人喜歡把相關的資料都掛在這邊。先前用都是在 Trac 1.0 上用,也沒什麼問題,最近在 Trac 1.2 上跑發現直接有 js error...

原因是 TracTicketReferencePlugin 用到 jQuery.live(),而這個函式在 jQuery 1.7 被宣告 deprecated,在 jQuery 1.9 被正式拔掉了。而 Trac 1.0 用的是 jQuery 1.7,所以不會有問題;Trac 1.2 用的是 jQuery 1.12,於是就爛掉了...

剛好就是昨天,有人在作者的 repository 上發 issue 出來 (另外也提供了 patch):「t2y / trac.plugins.ticketref / issues / #9 - JavaScript errors with Trac 1.2 — Bitbucket」。雖然 patch 本身不算難,但我實在懶的查 Mercurial 的操作,於是決定用 workaround 解...

想法是讓 jQuery.live() 會動,這點在 jQuery 官方出的 Migrate 就可以達到 (需要用 1.4.1 版,而不是 3.0.1 版),於是第一步就是在 site.html 內直接先下手為強,讀 jQuery 後馬上讀 Migrate:

  <!--! Add site-specific style sheet -->
  <head py:match="head" py:attrs="select('@*')">
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://code.jquery.com/jquery-migrate-1.4.1.min.js"></script>
    ${select('*|comment()|text()')}

但 Trac 還是會再載入一次的 jQuery 而蓋過去,所以我們要讓 Trac 不會載入,在 trac.ini 內的 jquery_location 設定讓他讀一個空的 js 檔:

jquery_location = site/null.js

然後生一個空的 trac/htdocs/null.js 讓他讀。

最後開一張票追蹤,看什麼時候官方放新版,再把這串 workaround 拔掉...

在 nginx 環境中把 Trac 裝到子目錄下的設法

以前的「Nginx + FastCGI + Trac」提到給的範例是把 Trac 裝在 / 下的方法。如果是裝在 /trac 或是其他路徑時就需要修改了。

一開始試著改會出現這樣的錯誤:

No handler matched request to /trac/report/7

然後研究調整後,發現 Trac 純粹是吃 FastCGI 給的參數去判斷要怎麼處理 url routing,在 trac.ini 內 url 相關參數主要還是用在其他地方... (像是信件通知時用的 url)

首先是把檔案簡化,這是 2016 年寫的:

    location / {
        auth_basic "trac realm";
        auth_basic_user_file /srv/domain.example.com/.htpasswd;

        include fastcgi.conf;
        fastcgi_param AUTH_USER $remote_user;
        fastcgi_param HTTPS on;
        fastcgi_param PATH_INFO $fastcgi_script_name;
        fastcgi_param REMOTE_USER $remote_user;
        fastcgi_param SCRIPT_NAME "";
        fastcgi_pass unix:/var/run/trac/trac.sock;
    }

發現現在 fastcgi.conf 內都會處理 HTTPS 了,所以拿掉 HTTPS 的處理,然後把 location 的判斷改用 regex 去抓 /trac 後的東西,所以先變成這樣:

    location ~ /trac(/.*) {
        auth_basic "trac realm";
        auth_basic_user_file /srv/domain.example.com/.htpasswd;

        include fastcgi.conf;
        fastcgi_param AUTH_USER $remote_user;
        fastcgi_param PATH_INFO $fastcgi_script_name;
        fastcgi_param REMOTE_USER $remote_user;
        fastcgi_param SCRIPT_NAME "";
        fastcgi_pass unix:/var/run/trac/trac.sock;
    }

最後是把 PATH_INFO 改傳 $1 (在 / 的情境下 $fastcgi_script_name 剛好就會是 routing 用的 PATH_INFO 資訊,所以當時直接拿來用),把 SCRIPT_NAME 改成 /trac

也就是跟 Trac 說基底在 /trac,後面的路徑才是你的 routing engine 要處理的東西,所以變成:

    location ~ /trac(/.*) {
        auth_basic "trac realm";
        auth_basic_user_file /srv/domain.example.com/.htpasswd;

        include fastcgi.conf;
        fastcgi_param AUTH_USER $remote_user;
        fastcgi_param PATH_INFO $1;
        fastcgi_param REMOTE_USER $remote_user;
        fastcgi_param SCRIPT_NAME "/trac";
        fastcgi_pass unix:/var/run/trac/trac.sock;
    }

沒寫下來就會花不少時間重新摸...

Trac 1.2 裡 datepicker 每個禮拜的第一天改成星期天

Trac 1.0 搭配舊的 DateFieldPlugin 時,預設每週的第一天會是星期一,但這個設定可以在 trac.ini 內用 first_day 參數調整,像是這樣:

[datefield]
format = ymd
separator = -
first_day = 0

但在 Trac 1.2 在 trac.ini 裡就沒有提供設定讓人調整了... 而由於 Trac 是用 jQuery UIDatepicker,在這個套件裡有提供方法讓人調整,所以解決的方向變成在 site.html 內用 JavaScript 處理,把這段程式碼塞到 JavaScript 的區段內就可以了:

// Datepicker
jQuery.datepicker.setDefaults({firstDay: 0});

一整個繼續惡搞中... 然後把 wiki 上的 Trac 條目也更新上去。

Trac 1.2 的 Due Date...

在先前的文章提到了把自己在用的事件管理系統 Trac 從 1.0 升級到 1.2,然後 Due Date 的設計改變了:「Trac 1.1 增加的 time 欄位,以及 Due Date 資料的轉移」、「總算把手上的 Trac 1.0 升級到 1.2 了...」。

Trac 1.2 的資料型態是在底層存 unix timestamp 的變形 (乘以 1000000,然後前端補上 0 存成文字),這幾天用下來才發現一些以前沒遇到的問題。

一開始轉到 Trac 1.2 是設成 date,但意外的發現 (因為伺服器時間不是 UTC),不同時區的使用者在更新 ticket 時,系統會判定 Due Date 有變動而產生變更記錄,想了一下就改用 datetime 來處理這個問題。

用了 datetime 一陣子後,才發現先前的公司遇到的情境中,時區差異都很小,所以不會有 Due Date 理解上的問題 (像是從 +7 到 +9 的時區),如果今天是美國西岸跟台灣互相合作的話,只用 date 就會產生很明顯的理解問題了...

算是這陣子用 Trac 1.2 而對 Due Date 設計有不一樣的理解...

總算把手上的 Trac 1.0 升級到 1.2 了...

就如同上一篇提到的,Trac 在 1.1.1 後新增了 time 格式,所以本來的 DateFieldPlugin 有些資料要轉換。我這邊只有用在 Due Date,所以就是轉 due_date 的資料而已。

先把 due_date 都改成 due_date_bak

UPDATE ticket_custom SET name = 'due_date_bak' WHERE name = 'due_date';

然後重新計算資料,這邊是因為所有的系統都是 UTC,所以直接轉就可以了:

INSERT INTO ticket_custom (ticket, name, value) SELECT ticket, 'due_date', LPAD(UNIX_TIMESTAMP(STR_TO_DATE(value, '%Y-%m-%d')) * 1000000, 18, '0') FROM ticket_custom WHERE name = 'due_date_bak';

而我的 Report 有用到 due_date 欄位的東西,本來是 c.value 直接輸出,現在要改成:

FROM_UNIXTIME(CONVERT(c.value / 1000000, UNSIGNED INTEGER), '%Y-%m-%d') AS due_date

Trac 1.2 相較於 1.0 最不習慣的地方應該是修改界面的位置改變了,現在 Add Comment 變成在 Modify 下面,有點不太習慣,但之後用久了應該就會習慣了。其他的修一修改一改都會動了...

Trac 1.1 增加的 time 欄位,以及 Due Date 資料的轉移

Trac 的版本玩法跟早期 Linux Kernel 的模式有點像,也就是版號偶數是正式版,奇數是開發版... 雖然現在 Linux Kernel 已經不玩這套了,但 Trac 還是維持這樣的開發方式。

先前一直都是用 Trac 1.0,其中 Due Date 的功能則是用「DateFieldPlugin」這個套件,讓 Trac 支援 date 格式,於是就可以在 [ticket-custom] 裡面指定 Due Date 了:

due_date = text
due_date.date = true
due_date.date_empty = false
due_date.label = Due Date
due_date.value = <now>

在套件的頁面也有提到在 Trac 1.1.1 後就有內建的方式可以用了:

Notice: This plugin is deprecated in Trac 1.2 and later. Custom fields of type ​time were added in Trac 1.1.1.

連結是連到 1.1 的,我要測 1.2 的,所以往現在的版本翻資料,可以看到在 TracTicketsCustomFields 這邊的說明:(這邊就懶的照原來 html 排了,用 pre 直接放縮排)

time: Date and time picker. (Since 1.1.1.)
    label: Descriptive label.
    value: Default date.
    order: Sort order placement.
    format: One of:
        relative for relative dates.
        date for absolute dates.
        datetime for absolute date and time values.

這樣一來設定就會變成:

due_date = time
due_date.format = date
due_date.label = Due Date
due_date.value = now

但底層資料怎麼存?先看 ticket_custom 這個表格的結構,可以看到是 EAV 的架構:

+--------+------------+------+-----+---------+-------+
| Field  | Type       | Null | Key | Default | Extra |
+--------+------------+------+-----+---------+-------+
| ticket | int(11)    | NO   | PRI | NULL    |       |
| name   | mediumtext | NO   | PRI | NULL    |       |
| value  | mediumtext | YES  |     | NULL    |       |
+--------+------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

隨便拉一些可以看出來放法很簡單:

+--------+----------+------------+
| ticket | name     | value      |
+--------+----------+------------+
|      1 | due_date | 2016-10-03 |
+--------+----------+------------+

改成 Trac 1.2 內建的 time 後,塞 2018/02/28 變成:

+--------+----------+--------------------+
| ticket | name     | value              |
+--------+----------+--------------------+
|      1 | due_date | 001519776000000000 |
+--------+----------+--------------------+

拿掉後面的六個 0 後可以看到就是 2018/02/28 了,要注意的是,這邊會受到時區影響,我一開始測試的時候沒調整,寫進去的時間是用伺服器預設的時區計算的。另外也大概能理解前面放兩個 0 的目的,是為了讓 string 比較時的大小就會是數字實際的大小。

$ date --date=@1519776000
Wed Feb 28 00:00:00 UTC 2018

這樣就知道要怎麼做人工轉換了...

在 Trac 裡把參與者自動加到 cc list 裡面的 plugin

之前在 Trac 裡會想要達成「當使用者參與這張票時,自動加到 cc list 讓他收到後續的更新」這樣的功能。之前沒有仔細研究要怎麼在 Trac 裡面實踐,就直接在 template (也就是 site.html) 裡面用 javascript 在 client 做掉...

先拉出 authname

<script>
(function() {
    window.authname = "${authname}";
})();
</script>

然後再攔截網址裡有 /ticket/ 的頁面,當 form 符合條件時攔截 submit 事件,在 cc list 裡面沒有自己時把自己加進去:

// Add myself into cc list, if I am not in cc list now.
(function() {
    if (-1 === document.location.href.indexOf('/ticket/')) {
        return;
    }
    var cc_list = jQuery('input[name="field_cc"]').val().split(/[ ,]+/);
    for (var i in cc_list) {
        if (window.authname === cc_list[i]) {
            return;
        }
    }

    jQuery(function() {
        jQuery('form#propertyform').submit(function() {
            var cc = jQuery('input[name="field_cc"]');
            cc.val(cc.val() + ',' + window.authname);
        });
    });
})();

這樣是可以達成目的啦,但有種惡搞的感覺... 所以這次還是寫了個 Trac plugin 來解決,這樣不用擔心當網頁界面改版時會產生問題:「104corp/trac-addtocc-plugin」。

Archives