亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python封裝git命令的流程步驟

 更新時間:2024年01月24日 08:25:59   作者:麥田里的守望者江  
在日常的 Android 項目開發(fā)中,一般只會使用到: git add, git commit, git push, git pull, git rebase, git merge, git diff等常規(guī)命令,但是使用 git 命令,還可以做一些特別的事情,下面將介紹使用 python 封裝 git 命令,需要的朋友可以參考下

上一篇文章介紹了Python 封裝 gradle 命令,這一篇將介紹 Python 封裝 git 命令,用于查看某個版本某個作者的所有提交更改查看某個提交第一次出現(xiàn)的 release 分支。

執(zhí)行 git 命令

在日常的 Android 項目開發(fā)中,一般只會使用到: git add, git commit, git push, git pull, git rebase, git merge, git diff等常規(guī)命令。但是使用 git 命令,還可以做一些特別的事情,比如查看某個版本某個作者的所有提交更改,方便自己或其他人進行 code review;比如查看某個提交第一次出現(xiàn)的版本,方便排查問題。下面將介紹使用 python 封裝 git 命令。

查看某個版本某個作者的所有提交更改

在某個版本迭代中,不管是單人還是多人開發(fā),如果想在 mr 之前 或 之后,或者 release 之前 或 之后,隨時查看自己本次版本迭代中的所有提交更改(隨時對自己編寫的代碼進行自我 code review),現(xiàn)只能使用 git 命令:git log branch1...branch2 --author=wangjiang --name-status --oneline 等進行簡單查看,而且較麻煩。我們期望有一個工具,能夠展示自己當(dāng)前分支提交的所有代碼更改內(nèi)容?,F(xiàn)利用 python 可以實現(xiàn)這個工具。

雖然創(chuàng)建的 mr 也能查看自己在本版本迭代中提交的所有代碼更改,但是在本次迭代中提交了多個 mr 或者過了很久也想查看自己在某個版本中的更改時,用 mr 查看就很不方便。

git 命令介紹

要比對兩個分支(branch)的提交歷史,可以使用 git log 命令并指定不同的分支名稱。

比對兩個具體的分支

git log branch1..branch2

該命令只顯示 branch2 相對于 branch1 的提交歷史,也就是:

  • 顯示在 branch2 中而不在 branch1 中的提交歷史
  • 只會顯示 branch2 中相對于 branch1 的新增提交
  • 不包括 branch1 中相對于 branch2 的新增提交

這個命令用于比對開發(fā)分支與拉出開發(fā)分支的主分支,比如從 master 分支 拉出 feature/7.63.0-wangjiang 分支,那么使用: git log master..feature/7.63.0-wangjiang --author=wangjiang --name-status --oneline 可以查看自己在 feature/7.63.0-wangjiang 分支上的所有提交記錄。

顯示共同的祖先以及兩個分支的不同

git log branch1...branch2

顯示兩個分支的共同祖先以及它們之間的不同,也就是:

  • 顯示兩個分支之間的差異,包括它們各自相對于共同祖先的所有提交
  • 顯示兩個分支的共同祖先以及它們之間的不同
  • 如果兩個分支有共同的提交,... 語法將顯示兩個分支最新的共同提交之后的提交

這個命令用于比對兩個 release 分支,比如當(dāng)前要發(fā)布的版本分支 release/7.63.0,上一個發(fā)布的版本分支 release/7.62.0,那么使用: git log release/7.63.0...release/7.62.0 --author=wangjiang --name-status --oneline 可以查看自己在 release/7.63.0 分支上的所有提交記錄,包含本次迭代提交的所有 feature。

如果上面比對開發(fā)分支與拉出開發(fā)分支的主分支使用 ... :git log master...feature/7.63.0-wangjiang --author=wangjiang --name-status --oneline ,那么其它 feature 分支合并到 master 的提交記錄,也會顯示。

另外,對于 git log branch1..branch2 git log branch1...branch2 添加 --name-status --oneline 會顯示:

d7a42a90c feat:--story=1004796 --user=王江 Python封裝 git 命令需求 
M       music/src/main/java/com/music/upper/module/fragment/MusicAlbumPickerFragment.kt
A       music/src/main/res/drawable-xxhdpi/ic_draft.png
M       music/src/main/res/layout/music_album_choose_container_fragment.xml
D       music/src/main/res/drawable-xxhdpi/ic_save.png
R098   music/src/main/java/com/music/upper/module/fragment/MusicVideoPickerFragment.kt music/src/main/java/com/music/upper/module/fragment/MusicVideoListPickerFragment.kt

其中 M 表示修改文件,A 表示添加文件,D 表示刪除文件,R098 表示重命名文件。

檢查文件是否存在

上面提交記錄里會有修改、添加、刪除、重命名文件,那么需要查看某個分支上某個文件是否存在。

git ls-tree branch file-path

該命令這將列出 branch 分支上指定路徑的文件信息。如果文件存在,將顯示相關(guān)信息;如果文件不存在,則命令不會有輸出。

顯示指定分支上指定文件的詳細更改信息

git show branch:file-path

這個命令會顯示指定分支上指定文件的詳細更改信息,包括修改的內(nèi)容。如果文件存在,將顯示文件內(nèi)容信息;如果文件不存在,則命令會輸出錯誤信息。

了解了上面的 git 命令后,使用 python 將這些命令組合,并輸出自己當(dāng)前分支提交的所有代碼更改內(nèi)容的 html 文檔報告。

期望執(zhí)行的 python 腳本命令:

 python3 diff_branch.py android_project_path current_branch target_branch
 
 例如:
 python3 diff_branch.py /Users/wangjiang/Public/software/android-workplace/Demo release/7.63.0 release/7.62.0
 python3 diff_branch.py /Users/wangjiang/Public/software/android-workplace/Demo feature/wangjiang master

首先定義一個執(zhí)行 git 命令的基礎(chǔ)方法:

def run_git_command(command):
    """
    :param command: 實際相關(guān)命令
    :return: 執(zhí)行命令結(jié)果
    """
    try:
        result = subprocess.run(command, check=True, text=True, capture_output=True, encoding='utf-8')
        return result.stdout
    except subprocess.CalledProcessError as e:
        print(f"Error executing command: {e}")
        return None

第一步:同步目標(biāo)分支

  • 獲取遠程分支:git fetch origin branch
  • 切換到分支:git checkout branch
  • 更新分支:git pull origin branch
def sync_branch(branch):
    """
    同步分支到最新代碼
    :param branch: 分支名稱
    :return: 檢查結(jié)果
    """
    result = run_git_command(
        ['git', 'fetch', 'origin', branch])
    if result is None:
        return None
    result = run_git_command(
        ['git', 'checkout', branch])
    if result is None:
        return None
    result = run_git_command(
        ['git', 'pull', 'origin', branch])
    return result


def check_branch(target_branch, current_branch):
    """
    檢查分支
    :param current_branch: 當(dāng)前分支
    :param target_branch: 要比對的分支
    :return: 檢查分支結(jié)果,True表示成功,否則失敗
    """
    if sync_branch(target_branch) is None:
        print(f"Sync branch: {target_branch} Failed")
        return False
    if sync_branch(current_branch) is None:
        print(f"Sync branch: {current_branch} Failed")
        return False
    return True

第二步:獲取自己的 git 賬號名稱

  • 獲取 git 賬號名稱:git config --get user.name
def get_git_user():
    """
    獲取自己的 git user name
    :return: git 賬戶名稱
    """
    return run_git_command(['git', 'config', '--get', 'user.name']).strip()

第三步:比較 current_branch 和 target_branch,獲取提交的文件列表

  • 比對分支:git log branch1..branch2 或 git log branch1...branch2
def get_commit_file_path_set(target_branch, current_branch, author):
    """
    比對 branch,獲取提交的文件相對路徑列表
    :param target_branch: 要比對的分支
    :param current_branch: 當(dāng)前分支
    :param author: git user.name
    :return: 提交的文件相對路徑列表
    """
    try:
        # 如果當(dāng)前開發(fā)分支與master或release分支比對,使用 git log master..feature
        if (target_branch == 'master' or target_branch.startswith('release')) and not current_branch.startswith(
                'release'):
            branch_command = f"{target_branch}..{current_branch}"
        else:
            # 否則都是用 git log branch1...branch2
            branch_command = f"{current_branch}...{target_branch}"

        command = ['git', 'log', branch_command, f"--author={author}",
                   '--name-status', '--oneline']
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
        file_path_list = set()
        rename_file_path_list = set()
        while True:
            output = process.stdout.readline()
            if output == '' and process.poll() is not None:
                process.kill()
                break
            if output:
                text = output.strip().replace("\t", "")
                if text.startswith('M') or text.startswith('A') or text.startswith('D'):
                    file_path = text[1:]
                    file_path_list.add(file_path)
                else:
                    # 重命名文件
                    if output.strip().startswith('R'):
                        rename_file_path = output.strip().split('\t')[1]
                        rename_file_path_list.add(rename_file_path)
        if len(file_path_list) == 0:
            print(f"{' '.join(command)}: No commit files")
            return None
        for rename_file_path in rename_file_path_list:
            file_path_list.remove(rename_file_path)
        return file_path_list
    except subprocess.CalledProcessError as e:
        print(f"Error executing command: {e}")
        return None

第四步:根據(jù)文件列表獲取文件內(nèi)容

  • 查看分支上是否有該文件:git ls-tree branch-name file-path
  • 顯示分支上該文件內(nèi)容:git show branch:file-path
def get_commit_content(commit_file_path_set, target_branch, current_branch):
    """
    獲取提交的內(nèi)容
    :param commit_file_path_set: 提交的文件相對路徑列表
    :param target_branch: 要比對的分支
    :param current_branch: 當(dāng)前分支
    :return: 要比對的分支內(nèi)容,當(dāng)前分支內(nèi)容
    """
    target_content_lines = []
    current_content_lines = []
    for file_path in commit_file_path_set:
        try:
            file_in_target_branch = run_git_command(['git', 'ls-tree', target_branch, file_path])
            if file_in_target_branch.find('blob') >= 0:
                target_content = run_git_command(
                    ['git', 'show', target_branch + ":" + file_path])
                if target_content is not None:
                    target_content_lines += target_content.splitlines()
        except UnicodeDecodeError as e:
            target_content_lines += [file_path + '\n']
        try:
            file_in_current_branch = run_git_command(['git', 'ls-tree', current_branch, file_path])
            if file_in_current_branch.find('blob') >= 0:
                current_content = run_git_command(
                    ['git', 'show', current_branch + ":" + file_path])
                if current_content is not None:
                    current_content_lines += current_content.splitlines()
        except UnicodeDecodeError as e:
            current_content_lines += [file_path + '\n']
    return target_content_lines, current_content_lines

第五步:生成 html 報告文件

  • 生成 html 報告文件:difflib.HtmlDiff
def make_html_file(project_path, target_branch_content, current_branch_content, target_branch, current_branch, author):
    """
    生成 html 文件報告
    :param project_path: 項目路徑
    :param target_branch_content: 要比對的分支內(nèi)容
    :param current_branch_content:  當(dāng)前分支內(nèi)容
    :param target_branch: 要比對的分支
    :param current_branch: 當(dāng)前分支
    :param author: git user.name
    :return: html 文件報告路徑
    """
    html_report_dir = f"{project_path}{os.path.sep}build{os.path.sep}reports{os.path.sep}diff{os.path.sep}{author}"
    if not os.path.exists(html_report_dir):
        os.makedirs(html_report_dir)
    html_file_path = f"{html_report_dir}{os.path.sep}{current_branch.replace('/', '_')}-diff-{target_branch.replace('/', '_')}.html"
    d = difflib.HtmlDiff(wrapcolumn=120)
    diff_html = d.make_file(target_branch_content, current_branch_content, target_branch, current_branch, context=True)
    if os.path.exists(html_file_path):
        os.remove(html_file_path)
    with open(html_file_path, 'w', encoding='utf-8') as html_file:
        html_file.write(diff_html)
        html_file.close()
    print(f"{project_path} Html Report Path: {html_file_path}")
    return html_file_path

第六步:在瀏覽器中打開 html 文檔報告

def open_file(file_path):
    """
    在電腦上打開截屏文件
    :param file_path: 電腦上的截屏文件地址
    """
    system = platform.system().lower()
    if system == "darwin":  # macOS
        subprocess.run(["open", file_path])
    elif system == "linux":  # Linux
        subprocess.run(["xdg-open", file_path])
    elif system == "windows":  # Windows
        subprocess.run(["start", file_path], shell=True)
    else:
        print("Unsupported operating system.")

第七步:將上面步驟組合在一起執(zhí)行

if __name__ == "__main__":
    args = sys.argv[1:]
    if len(args) > 0:
        project_path = args[0]
    if len(args) > 1:
        current_branch = args[1]
    if len(args) > 2:
        target_branch = args[2]

    os.chdir(project_path)
    # 第一步:同步目標(biāo)分支
    if not check_branch(target_branch, current_branch):
        exit(1)
    # 第二步:獲取自己的git賬戶名稱
    author = get_git_user()
    if author is None:
        exit(1)
    # 第三步:比較 current_branch 和 target_branch,獲取提交的文件列表
    commit_file_path_set = get_commit_file_path_set(target_branch, current_branch, author)
    if commit_file_path_set is None or len(commit_file_path_set) == 0:
        exit(0)
    # 第四步:根據(jù)文件列表獲取文件內(nèi)容
    last_branch_content, current_branch_content = get_commit_content(commit_file_path_set, target_branch,
                                                                     current_branch)
    # 第五步:生成 html 報告文件
    report_html_file_path = make_html_file(project_path, last_branch_content, current_branch_content, target_branch,
                                           current_branch, author)
    # 第六步:打開 html 報告文件
    open_file(report_html_file_path)

將上面的代碼封裝成 diff_branch.py,在命令行執(zhí)行:

python3 diff_branch.py /Users/wangjiang/Public/software/android-workplace/Demo  release/7.63.0 release/7.62.0

輸出結(jié)果,這里比較私密,就不展示了。

查看某個提交第一次出現(xiàn)的 release 分支

在日常的 Android 項目開發(fā)中,如果想排查問題,或查看 feature 在哪個版本上線的,那么查看某個 commit 第一次出現(xiàn)的 release 分支,能夠輔助你得到更多有用的信息。

第一步:查找包含 commit id 的所有分支名稱

  • 查找包含 commit id 的所有分支:git branch --contains commit-id -all
def find_commit(commit_id):
    """
    查找包含 commit id 的所有分支名稱
    :param commit_id: commit id 值
    :return: 分支列表
    """
    result = run_git_command(
        ['git', 'branch', '--contains', commit_id, '--all'])
    if result is not None:
        return result.splitlines()
    return None

第二步:找到 commit id 第一次出現(xiàn)的 release 分支

def compare_versions(version1, version2):
    """
    比較版本號
    :param version1: 7.63.0
    :param version2: 7.64.0
    :return: 如果 version1<version2,返回-1;如果version1>version2,返回1;如果version1=version2,返回0
    """
    parts1 = list(map(int, version1.split('.')))
    parts2 = list(map(int, version2.split('.')))

    length = max(len(parts1), len(parts2))

    for i in range(length):
        part1 = parts1[i] if i < len(parts1) else 0
        part2 = parts2[i] if i < len(parts2) else 0

        if part1 < part2:
            return -1
        elif part1 > part2:
            return 1

    return 0


def find_min_release_branch(branch_list):
    """
    篩選出版本最低的 release branch,也就是找到 commit id 第一次出現(xiàn)的 release branch
    :param branch_list: 分支列表
    :return: 版本最低的 release branch
    """
    min_version_name = None
    min_branch = None
    release_prefix = 'remotes/origin/release/'
    for branch in branch_list:
        index = branch.find(release_prefix)
        if index >= 0:
            version_name = branch[index + len(release_prefix):]
            if min_version_name is None:
                min_version_name = version_name
                min_branch = branch
            else:
                if compare_versions(min_version_name, version_name) > 0:
                    min_version_name = version_name
                    min_branch = branch

    return min_branch.strip()

第三步:獲取 commit 信息

  • 獲取 commit 信息:git show commit-id
def get_commit_info(commit_id):
    """
    獲取提交的信息
    :param commit_id: commit id值
    :return: commit 信息,包含文件更改信息
    """
    return run_git_command(
        ['git', 'show', commit_id])

第四步:生成 html 文檔報告

def make_html_file(project_path, commit_id, title, content):
    """
    生成 html 文件報告
    :param project_path: 項目路徑
    :param commit_id: commit id值
    :param title: html 文檔標(biāo)題
    :param content: html 文檔內(nèi)容
    :return: html 文件報告路徑
    """
    html_content = f"""
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <style>
            body {{
                font-family: 'Arial', sans-serif;
                background-color: #272822;
                color: #f8f8f2;
                margin: 20px;
            }}
            pre {{
                white-space: pre-wrap;
                font-size: 14px;
                line-height: 1.5;
                background-color: #1e1e1e;
                padding: 20px;
                border: 1px solid #333;
                border-radius: 5px;
                overflow-x: auto;
            }}
            .header {{
                color: #66d9ef;
            }}
            .bordered-div {{
                border: 1px solid #000;
                padding: 10px;
            }}
        </style>
    </head>
    <body>
        <h1>{title}</h1>
        <pre>
           {content}
        </pre>
    </body>
    </html>
    """
    html_report_dir = f"{project_path}{os.path.sep}build{os.path.sep}reports{os.path.sep}diff{os.path.sep}commit_id"
    if not os.path.exists(html_report_dir):
        os.mkdir(html_report_dir)
    html_file_path = f"{html_report_dir}{os.path.sep}{commit_id}.html"
    if os.path.exists(html_file_path):
        # 如果文件存在,刪除文件
        os.remove(html_file_path)
    with open(html_file_path, 'w') as html_file:
        html_file.write(html_content)
        html_file.close()
    print(f"Html Report Path: {html_file_path}")
    return html_file_path

第五步:在瀏覽器中打開 html 文檔報告

def open_file(file_path):
    """
    在電腦上打開截屏文件
    :param file_path: 電腦上的截屏文件地址
    """
    system = platform.system().lower()
    if system == "darwin":  # macOS
        subprocess.run(["open", file_path])
    elif system == "linux":  # Linux
        subprocess.run(["xdg-open", file_path])
    elif system == "windows":  # Windows
        subprocess.run(["start", file_path], shell=True)
    else:
        print("Unsupported operating system.")

第六步:將上面步驟組合在一起執(zhí)行

if __name__ == "__main__":
    args = sys.argv[1:]
    if len(args) > 0 and os.path.exists(args[0]):
        project_path = args[0]
    if len(args) > 1 :
        commit_id = args[1]

    os.chdir(project_path)
    # 第一步:查找包含 commit id 的所有分支名稱
    branch_list = find_commit(commit_id)
    # 第二步:找到 commit id 第一次出現(xiàn)的 release 分支
    min_release_branch = find_min_release_branch(branch_list)
    title = f"<p>Project: {project_path}</p>The commit id: {commit_id} first appears in the release branch: {min_release_branch}"
    # 第三步:獲取 commit 信息
    content = get_commit_info(commit_id)
    # 第四步:生成 html 文檔報告
    html_file_path = make_html_file(project_path, commit_id, title, content)
    # 第五步:打開 html 文檔報告
    open_file(html_file_path)

將上面的代碼封裝成 find_commit.py,在命令行執(zhí)行:

python3 find_commit.py /Users/wangjiang/Public/software/android-workplace/Demo 00b9d42d70

小結(jié)

使用 python 執(zhí)行相關(guān) git 命令,主要是生成可視化的 html 文檔報告。比對分支操作,在開發(fā) feature 合并到主分支前,可以查看自己當(dāng)前分支提交的所有代碼更改內(nèi)容;在本迭代版本 release 前,可以反復(fù)查看自己的所有更改,進行代碼 double check,防止出現(xiàn)線上 bug。在排查問題或者代碼回溯中,可以快速找到 commit id 第一次出現(xiàn)的 release 版本,得到有用關(guān)鍵信息。總之,利用 python 組合 git 命令,可以在開發(fā)中做很多意想不到的事情。

另外,沒有提供上面的完整的代碼,但是依照步驟去做,就可以完全實現(xiàn)。

寫在最后,使用 python 不止可以封裝 adb, gradle, git 命令,還可以做 json 比對,代碼靜態(tài)分析(利用detekt,pmd等的cli),下線或升級某個庫查看庫在項目中的代碼分布情況,業(yè)務(wù)和技術(shù)指標(biāo)可視化報告,查看pb文件,用戶日志定制化分析等。學(xué)習(xí) python,對于日常 Android 開發(fā),非常有用,能幫助省去很多瑣碎時間。

以上就是Python封裝git命令的流程步驟的詳細內(nèi)容,更多關(guān)于Python封裝git命令的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Pytorch.nn.conv2d 過程驗證方式(單,多通道卷積過程)

    Pytorch.nn.conv2d 過程驗證方式(單,多通道卷積過程)

    今天小編就為大家分享一篇Pytorch.nn.conv2d 過程驗證方式(單,多通道卷積過程),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-01-01
  • 基于Python實現(xiàn)微博抓取GUI程序

    基于Python實現(xiàn)微博抓取GUI程序

    在前面的分享中,我們制作了一個天眼查 GUI 程序,今天我們在這個的基礎(chǔ)上,繼續(xù)開發(fā)新的功能,微博抓取工具,感興趣的可以了解一下
    2022-09-09
  • python list語法學(xué)習(xí)(帶例子)

    python list語法學(xué)習(xí)(帶例子)

    python list語法學(xué)習(xí)
    2013-11-11
  • 利用pyshp包給shapefile文件添加字段的實例

    利用pyshp包給shapefile文件添加字段的實例

    今天小編就為大家分享一篇利用pyshp包給shapefile文件添加字段的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • python退出命令是什么?詳解python退出方法

    python退出命令是什么?詳解python退出方法

    在本篇內(nèi)容中我們給學(xué)習(xí)python編程的朋友們整理了關(guān)于python退出的命令和方法,需要的學(xué)習(xí)下。
    2018-12-12
  • python執(zhí)行shell并獲取結(jié)果的詳細示例

    python執(zhí)行shell并獲取結(jié)果的詳細示例

    在Python中執(zhí)行Shell命令并獲取其結(jié)果,通??梢允褂胹ubprocess模塊,這個模塊允許我們啟動新的進程,連接到它們的輸入/輸出/錯誤管道,并獲取它們的返回碼,下面是一個詳細的示例,展示了如何使用subprocess.run()函數(shù)來執(zhí)行Shell命令并獲取其輸出,需要的朋友可以參考下
    2024-07-07
  • 深入淺析python中的多進程、多線程、協(xié)程

    深入淺析python中的多進程、多線程、協(xié)程

    這篇文章主要介紹了深入淺析python中的多進程、多線程、協(xié)程 的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • 解決pyqt中ui編譯成窗體.py中文亂碼的問題

    解決pyqt中ui編譯成窗體.py中文亂碼的問題

    下面小編就為大家?guī)硪黄鉀Qpyqt中ui編譯成窗體.py中文亂碼的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • Python中的基本數(shù)據(jù)類型介紹

    Python中的基本數(shù)據(jù)類型介紹

    這篇文章介紹了Python中的基本數(shù)據(jù)類型,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • pytest多文件執(zhí)行順序控制詳解

    pytest多文件執(zhí)行順序控制詳解

    默認情況下pytest測試用例的執(zhí)行順序是先按照外層后內(nèi)層(目錄下的文件),同層級的包或文件、根據(jù)名稱、按照ascii碼升序執(zhí)行,文件內(nèi)的用例根據(jù)先后順序執(zhí)行,這篇文章主要給大家介紹了關(guān)于pytest多文件執(zhí)行順序控制的相關(guān)資料,需要的朋友可以參考下
    2022-07-07

最新評論