Microsoft ドキュメントの更新差分を検出してくれるアプリ – day 16

30 days AI challenge

本記事は 2026/02/01 ~ 2026/03/02 の間毎日 AI アプリケーション開発(AI を搭載したアプリ開発 or AI を使用した開発)をテーマに 30 days AI challenge を行う 16 日目のブログポストです。

今日のアプリは、Micosoft の公式ドキュメント “Microsoft Learn” の更新差分を確認できるアプリです。

Microsoft Learn は GitHub で管理されており、最終コミットを見ることで更新差分を確認することができ、私の仕事上時々その差分を確認しに行くことがあります。そんな時に役に立つアプリです。

アプリ概要

このアプリでは、ユーザーが差分を確認したいドキュメント URL を事前に登録しておき、その後更新チェックを行うことで、最後に確認した時からドキュメントの更新があるかを確認することができます。

複数のドキュメント URL を登録することが可能です。ユーザーが登録したドキュメント情報は SQL Server に記録しています。

先にも記載した通り、Microsoft Learn は GitHub 管理なので、GitHub のコミット情報を取得しそこから差分を検出します。更新チェックをすると以下のように更新を確認し、更新があれば表示し、更新が無ければ”更新無し”と表示してくれます。

本当はカテゴリだけ登録して、その配下のすべてのドキュメントで更新があったものをすべて表示(例えば Azure SQL Database とだけ登録し、Azure SQL Database 関連のドキュメントの差分をすべて検出)、のような機能にしたかったですが、ベータ版としてまずは登録したドキュメントの差分のみの検出としています。

技術要素

GitHub API を使用しています。

ユーザーが入力した Learn の URL から GitHub ページの URL を構築し、API に投げてコミット情報を取得するような仕組みです。

public async Task<(bool hasUpdate, string summary, string? commitSha, ...)> CheckForUpdatesAsync(...)
{
    // GitHub REST API から直接 commit 情報を取得
    var (latestCommitSha, latestCommitMessage, latestCommitDate) = 
        await FetchLatestCommitFromGitHubAsync(commitUrl);
    
    // 文字列比較で更新を検出
    bool hasUpdate = string.IsNullOrEmpty(lastCommitSha) || lastCommitSha != latestCommitSha;
    
    // Markdown 形式のサマリーを文字列結合で生成
    var summary = hasUpdate
        ? $"**更新が検出されました**\n\n- **最新 Commit**: {latestCommitSha}..."
        : $"**更新はありません**\n\n...";
}

最終コミット情報を取得する実装はこちら(一部)。URL を変換し、API リクエストを投げ、結果の受け取り、結果のパースをしています。

private async Task<(string? sha, string? message, string? date)> FetchLatestCommitFromGitHubAsync(string commitUrl)
        {
            try
            {
                // GitHub API を使用して commit 情報を取得
                // commits ページ URL を API URL に変換
                var uri = new Uri(commitUrl);
                var pathParts = uri.AbsolutePath.Split(new[] { "/commits/" }, StringSplitOptions.None);
                if (pathParts.Length != 2)
                    return (null, null, null);

                var repoPart = pathParts[0].TrimStart('/'); // MicrosoftDocs/sql-docs
                var branchAndPath = pathParts[1].Split('/', 2); // ["live", "docs/path/to/file.md"]
                if (branchAndPath.Length != 2)
                    return (null, null, null);

                var branch = branchAndPath[0];
                var filePath = branchAndPath[1];

                var apiUrl = $"https://api.github.com/repos/{repoPart}/commits?path={filePath}&sha={branch}&per_page=1";

                var request = new HttpRequestMessage(HttpMethod.Get, apiUrl);
                request.Headers.Add("User-Agent", "DocTrackerApp");
                request.Headers.Add("Accept", "application/vnd.github.v3+json");

                var response = await _httpClient.SendAsync(request);
                if (!response.IsSuccessStatusCode)
                    return (null, null, null);

                var json = await response.Content.ReadAsStringAsync();
                var commits = System.Text.Json.JsonDocument.Parse(json);

                if (commits.RootElement.GetArrayLength() == 0)
                    return (null, null, null);

                var latestCommit = commits.RootElement[0];
                var sha = latestCommit.GetProperty("sha").GetString();
                var message = latestCommit.GetProperty("commit").GetProperty("message").GetString();
                var dateStr = latestCommit.GetProperty("commit").GetProperty("author").GetProperty("date").GetString();

                return (sha, message, dateStr);
            }
            catch
            ~例外処理~
        }

終わりに

今日は少し Microsoft っぽい内容にしてみました。

実際にドキュメントの差分がすぐわかると便利だと思うので、これは仕事でつかえるとよいな。。(16 日目で初めて仕事でつかえるアプリを作りました)。

今日は残りの時間も少ないのでこのあたりで終わります。閲覧いただきありがとうございました!

コメント

タイトルとURLをコピーしました