同事说她只想格式化变更的代码行,而不是变更的整个文件,怎么办

项目背景:

公司里的某个代码仓库配置的提交前校验 lint-staged 由于文件路径匹配有问题,导致过去几年曾经出现很多“漏网之鱼”,这些代码没有被 prettier 格式化,看上去有些杂乱。

我发现这个问题后,及时进行修复。但没想到过了几天,同事找我说她每次提交代码时,prettier 不仅会格式化她变更的代码,还会调整以前别人写的代码,导致她需要补写的单元测试巨多……(因为我司规定变更代码的单元测试覆盖率检测需大于 80% 才能发布)所以她希望只格式化自己变更的代码行,而不是整个文件

在这里插入图片描述


方案分析:

我的内心当时有两个小人:
激进派:将 master 分支代码全部用 prettier 格式化一遍,修改文件大约 2000+ 个,测试回归后发布。
保守派:按同事妹子说的那样,每次只格式化变更的代码行,而不是整个文件。

我打算先看看保守派的这个做法技术上是否可行,再拿着方案和仓库 Owner 沟通。我上网查了一下,发现 prettier 可以指定格式化的范围,貌似可行。

一顿折腾+自测,在 copilot 的帮助下,我实现了这个功能,
在这里插入图片描述

#!/bin/bash

# 获取暂存的更改
diff_output=$(git diff --cached --unified=0)

# 初始化数组
blocks=()

# 使用 grep 和 awk 提取以 diff --git 开头的所有片段,并存储到数组中
current_block=""
while IFS= read -r line; do
    if [[ "$line" =~ ^diff\ --git ]]; then
        if [[ -n "$current_block" ]]; then
            blocks+=("$current_block")
        fi
        current_block="$line"
    else
        current_block="$current_block"$'\n'"$line"
    fi
done < <(echo "$diff_output")

# 添加最后一个块
if [[ -n "$current_block" ]]; then
    blocks+=("$current_block")
fi

# 遍历数组
for block in "${blocks[@]}"; do

    # echo block: $block
    #提取文件名和行号
    echo "$block" | grep -E '^\+\+\+' | while read -r line; do

        # 提取文件名并去掉前缀路径
        file=$(echo "$line" | awk '{print $2}' | sed 's|^b/resibuflightsenglish/EnglishSite/||')

        # 跳过删除的文件
        if [ "$file" == "/dev/null" ]; then
            continue
        fi

        # 只处理特定后缀的文件
        if [[ ! "$file" =~ \.(ts|tsx|js|jsx)$ ]]; then
            continue
        fi

        # 提取行号
        echo "$block" | grep -E "^@@.*@@" | while read -r hunk; do

            # 提取行号范围
            start_line=$(echo "$hunk" | sed -n 's/^@@ -[0-9,]* \+\([0-9]*\).*/\1/p')
            # echo $start_line
            line_count=$(echo "$hunk" | sed -n 's/^@@ -[0-9,]* \+\([0-9]*\),\([0-9]*\).*/\2/p')

            # 如果没有匹配到行号,line_count 可能为空,设置默认值为 1
            if [ -z "$line_count" ]; then
                line_count=1
            fi

            # 如果 line_count 为 0,直接跳过
            if [ "$line_count" -eq 0 ]; then
                continue
            fi
            
            # 计算结束行号
            end_line=$((start_line + line_count - 1))

            # 确保行号范围有效
            if [ "$start_line" -le 0 ] || [ "$end_line" -le 0 ] || [ "$start_line" -gt "$end_line" ]; then
                echo "Invalid line range: $start_line to $end_line"
                continue
            fi

            # 计算字符位置
            start_char=$(awk -v start=$start_line 'NR<start {total += length($0) + 1} NR==start {total += 1; print total}' $file)
            end_char=$(awk -v end=$end_line 'NR<=end {total += length($0) + 1} END {print total}' $file)
            
            # # 使用 Prettier 格式化特定字符范围
            # echo "Formatting characters $start_char to $end_char in file $file $start_line to $end_line"
            npx prettier --write --range-start $start_char --range-end $end_char $file
        done
    done
done

解决方案:

最终我拿着这两个方案和仓库 Owner 沟通时,她选择了方案一,直接把所有代码格式化一遍,手动加白名单跳过这次覆盖率卡点,然后发布。虽然方案二最终没有派上用场,这里记录一下,因为觉得写的过程还是比较有收获的。如果其他人有类似需求也可以做个参考~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值