Odlbirds 帶你快速生成周報

語言: CN / TW / HK

公司要求每週都要寫週報,週報的大體內容就是你本週做的事情,暫時不需要所思所想所感(質量要求不高)。通常都是自己從 gitlab 的操作面板篩選出自己本週提交的日誌,然後每個提交 title 複製一份。然後我傻傻的把這件事幹了 2 年多了,雖然覺得應該有更便捷的方式,但是還是屈服自己懶惰。直到有那麼一天,上頭要求 ci 打出的包,要附帶發版日誌😱。

總有那麼一天,該來還是會來,只不過是時間罷了
複製程式碼

本文就是在這個需求威壓中產出,由於大大解放雙手,所以將這個思路整理成文,一起努力成為一名偷懶的程式設計師。

從日誌規範說起

個人通常在提交日誌的時候,會在文字中新增字首,且有以下規範:

  • Feat: 新功能(feature)
  • Fix: 修補bug
  • Docs: 文件(documentation)
  • Style: 格式(不影響程式碼執行的變動)
  • Refactor:重構(即不是新增功能,也不是修改bug的程式碼變動)
  • Test: 增加測試
  • Chore: 構建過程或輔助工具的變動

上面的規範是是某個東家學到的,起初覺得新增字首規範,不過是快速知道提交的大致意圖。所以在某些小公司,這個優點還是無法讓一個團隊從意識上遵守(如果不是技術負責人拍板),總有一兩個人,或者幾個提交突兀出來,破窗理論很快就得到驗證。對於毫無決定權的默默無聞的你只能走自己的路了。

以前看過一本書,裡面有大致的說辭:對於戒菸的人,要讓他戒菸,減量、控制吸食次數類似方法,戒菸效果不理想。更好的辦法是讓他意識到吸菸的危害,危害的認識越深,戒菸的成功率越高。

如果一個規則無法普及,很大原因是這個規則的所帶來的影響無法讓人深刻意識到。 效果越好,驅動力越強。

日誌實操

檢視提交日誌的命令:

$ git log
commit f35f45c654e56a1d55aaca24e0e3fd3b9577bcc0 (HEAD -> master, origin/master, origin/HEAD)
Author: jihua <[email protected]>
Date:   Fri Jan 22 23:03:05 2021 +0800

    Feat: 新增詳情
....
複製程式碼

可能對這個命令的認識,我們就到此為止了。但通過help命令我們知道它不止於此。

git log --help
複製程式碼

git log 的功能就是瀏覽歷史記錄。可以通過許多不同的引數傳遞給 git log 來更改日誌輸出,這些功能可以概括以下兩類:

  • 格式化每個提交的顯示方式
  • 過濾輸出中包括哪些提交

格式化

將每次提交壓縮為一行

它僅顯示提交ID和提交訊息的第一行,這對於獲得專案的高階概述非常有用

$ git log --oneline
f35f45c (HEAD -> master, origin/master, origin/HEAD) Feat: 新增詳情
199a0ce (tag: state) Feat: 狀態不同步問題
6e2c7d4 Feat: 新增檔案
複製程式碼

顯示指向每個提交的所有引用

很多時候瞭解每個提交與哪個分支或標籤相關聯很有用,使你可以更全面地瞭解儲存庫的邏輯結構

$ git log --oneline --decorate
0e25143 (HEAD, master) Merge branch 'feature'
ad8621a (feature) Fix: fix a bug in the feature
16b36c6 Feat: Add a new feature
23ad9ad (tag: v0.9) Feat: Add the initial code base
複製程式碼

每次提交時顯示差異

--stat 選項顯示每次提交更改的每個檔案的插入和刪除次數(請注意,修改一行表示為1次插入和1次刪除),這使你瞭解可以在何處找到每個提交的更改。

$ git log --stat
commit f2a238924e89ca1d4947662928218a06d39068c3
Author: John <[email protected]>
Date: Fri Jun 25 17:30:28 2014 -0500
Add a new feature
hello.py | 105 ++++++++++++++++++++++++-----------------
1 file changed, 67 insertion(+), 38 deletions(-)
複製程式碼

-p 檢視每個提交所引入的實際更改。

簡短日誌

$ git shortlog
Mary (2):
Fix a bug in the feature
Fix a serious security hole in our framework
John (3):
Add the initial code base
Add a new feature
Merge branch 'feature'
複製程式碼

它按作者對每個提交進行分組,並顯示每個提交訊息的第一行。 這是檢視誰在做什麼的一種簡單方法。

自定義格式輸出

可以使用 --pretty = format:“<string>”選項。這樣可以使用 printf 樣式的佔位符來顯示每個提交。

$ git log --pretty=format:"%cn:%s(%cd)"
jihua:Feat: 新增詳情(Fri Jan 22 23:03:05 2021 +0800)
jihua:Feat: 狀態不同步問題(Sun Jan 17 22:19:48 2021 +0800)
jihua:Feat: 新增檔案(Sun Jan 17 20:30:07 2021 +0800)
jihua:Feat: 修改(Sun Jan 17 16:43:58 2021 +0800)
jihua:Feat: 修改(Wed Jan 13 23:06:06 2021 +0800)
複製程式碼

過濾

限制顯示的提交數量

通過 -<n> 選項來限制 git log 的輸出數量

以下命令將僅顯示3個最新提交

$ git log -3
複製程式碼

查詢特定時間範圍內的提交

可以使用--after--before標誌來按日期過濾提交

$ git log --after="2021-1-1"
複製程式碼

還可以傳遞相對引用,例如“ 1周前”和“昨天”:

$ git log --after="yesterday"
複製程式碼

要搜尋在兩個日期之間建立的提交,可以同時提供-之前和-之後的日期

$ git log --after="2021-1-1" --before="2021-1-20"
複製程式碼

僅查詢由特定使用者建立的提交

$ git log --author="lai"
複製程式碼

還可以使用正則表示式來建立更復雜的搜尋,以下命令搜尋Mary或John的提交

$ git log --author="John\|Mary"
複製程式碼

按檔案

要顯示與檔案相關的歷史記錄,傳遞檔案路徑即可。 例如,以下程式碼返回所有影響 foo.py 或 bar.py 檔案的提交

$ git log -- foo.py bar.py
複製程式碼

按範圍

以將一系列提交提交給 git log,以僅顯示該範圍內包含的提交。當你使用分支引用作為引數時,此命令特別有用。

$ git log master..feature 
複製程式碼

以上是對 git log 一些引數的使用介紹,還有更多引數的使用,可以參考文件 檢視提交歷史

實戰生成周報

功能需求:獲取使用者lai在本週的程式碼日誌到檔案 log.txt 中,不包括 merge 的資訊,輸出格式如下:

* Feat: 新增詳情(2021-01-22)
複製程式碼

那麼要完成這個功能,我們要做的有:

  • 獲取到 lai 的日誌
  • 獲取到本週的日誌
  • 自定義日誌的輸出
  • 去除 merge 資訊
  • 輸出到檔案 log.txt 中

所以,整個命令:

$ git log --no-merges --author=lai --since=1.weeks --pretty=format:'* %s(%ad)' --date=short > ~/Desktop/log.txt
複製程式碼

log.txt 的內容類似:

* Chore: 版本升級到 1.5.0(2021-01-23)
* Chore: 自動化打包指令碼優化(2021-01-23)
* Chore: 指令碼優化, 發版的時候強制設定環境,防止受其他分支改動影響(2021-01-23)
* Feat: h5 介面對接(2021-01-22)
* Fix: 解決陣列越界問題(2021-01-22)
* Doct: README 文件修改(2021-01-22)
* Refactor:重構 WebController (2021-01-22)
複製程式碼

那麼這個功能就做完成了。但你以為就結束了麼?

更進一步

對於文章開頭提到的提交規範,我們說對於規範的益處認識不足。當我們將日誌蒐集到 log.txt 中,如果就怎麼給上頭審閱的,可能會被打回來,因為不能一眼知道,哪些是新增,哪些是修改,哪些是優化。所以我們必須給日誌進行整理,不能就這麼直白的輸出。希望看到:

## 新增
* h5 介面對接(2021-01-22)
## bug
* 解決陣列越界問題(2021-01-22)
## 優化
* 重構 WebController (2021-01-22)
## 文件
* README 文件修改(2021-01-22)
## 其他
* 版本升級到 1.5.0(2021-01-23)
* 自動化打包指令碼優化(2021-01-23)
* 指令碼優化, 發版的時候強制設定環境,防止受其他分支改動影響(2021-01-23)
複製程式碼

那麼本質上就是對日誌進行歸類:

  • Feat => 新增
  • Fix => bug
  • Refactor => 優化
  • Doct => 文件
  • Chore => 其他

可以直接通過規範的字首將日誌進行分類。這就是日誌規範化的另一個好處,可以統計提交。

import os
import json
from pathlib import Path
import sys
import getopt

argv = sys.argv[1:]

name = 'product' # preview | product (預覽模式和發版模式)
 
try:
    opts, args = getopt.getopt(argv, "m:")  # 短選項模式
except:
    print("錯誤,不支援m:")

for opt, arg in opts:
    if opt in ['-m']:
        name = arg


## 最開始收集日誌的 commitid
start_commit_id = "xxxxw454344346"

# 是否是上傳到線上
# 如果是上傳到線上,則日誌從 start_commit_id 開始獲取
# 如果是日常發版,則日誌從當前版本的上一次打包的 commit 開始
is_online_release = name == 'product'

history_commit_file = "%s/package-logs.json" % str(Path.home())

def init_history_commit_file():
    if not os.path.exists(history_commit_file):
        with open(history_commit_file, 'w') as f:
            json.dump({"name": "version logs"}, f)
    else:
        pass

def write_note(content):
    with open('release-note.txt', 'w') as f:
        content = f.write(content)

def git_shell(git_command):
    try:
        return os.popen(git_command).read().strip()
    except:
        return None

def get_history_commit_id(branch):
    result = {}
    with open(history_commit_file, 'r') as f:
        result = json.load(f)
    return result.get(branch, None)


def save_history_commit(branch, commit_id):
    result = {}
    with open(history_commit_file, 'r') as f:
        result = json.load(f)
    
    with open(history_commit_file, 'w') as ff:
        result[branch] = commit_id
        json.dump(result, ff)
        
def pretty_log(logs):
    # Feat => 新增
    # Fix => bug
    # Refactor => 優化
    # Doct => 文件
    # Chore => 其他
    pass

init_history_commit_file()

# 獲取當前分支名
git_branch = git_shell('git rev-parse --abbrev-ref HEAD')

if not is_online_release:
    history_commit_id = get_history_commit_id(git_branch)
    if history_commit_id:
        start_commit_id = history_commit_id


# 當前分支的最後一個提交ID
last_commit_id = git_shell('git rev-parse HEAD')

log_cmd = "git log %s..%s --date=short --no-merges --pretty=" % (start_commit_id, last_commit_id) + f"format:'* %s(%an)'"
git_logs = git_shell(log_cmd)


# 獲取到日誌後,需要對日誌進行歸類,便於閱讀
git_logs = pretty_log(git_logs)

# 寫入日誌
write_note(git_logs)

if not is_online_release:
    save_history_commit(git_branch, last_commit_id)


print('✅ 日誌生成完成')
複製程式碼

pretty_log 並沒有提供實現程式碼,讀者可以自己填充🤗。

努力成為一名愛偷懶的程式設計師💪,珍愛生命
複製程式碼

更多優質文章閱讀,請關注官方微信公眾號:OldBirds