Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion csharp/Platform.Bot/Platform.Bot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Octokit" Version="7.0.1" />
<PackageReference Include="Octokit" Version="14.0.0" />
<PackageReference Include="Platform.Communication.Protocol.Lino" Version="0.4.0" />
<PackageReference Include="Platform.Data.Doublets.Sequences" Version="0.1.1" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
Expand Down
121 changes: 120 additions & 1 deletion csharp/Storage/RemoteStorage/GitHubStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using Octokit.Internal;
using Platform.Threading;
Expand Down Expand Up @@ -242,13 +244,50 @@ public void CloseIssue(Issue issue)

#region Repository

public async Task<List<int>> GetAuthorIdsOfCommits(long repositoryId, CommitRequest commitRequest)
public async Task<List<long>> GetAuthorIdsOfCommits(long repositoryId, CommitRequest commitRequest)
{
var commits = await Client.Repository.Commit.GetAll(repositoryId, commitRequest);
return commits.Select(commit => commit.Author.Id).ToList();
}

public Task<IReadOnlyList<Repository>> GetAllRepositories(string ownerName) => Client.Repository.GetAllForOrg(ownerName);

/// <summary>
/// Search for commits using the GitHub Search API.
/// Since Octokit.NET doesn't support SearchCommits yet, this method uses direct HTTP calls to GitHub API.
/// </summary>
/// <param name="query">The search query (e.g., "repo:owner/repo author:username")</param>
/// <returns>Search results containing commits</returns>
public async Task<SearchCommitsResult> SearchCommits(string query)
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("User-Agent", "LinksplatformBot/1.0.0");
httpClient.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json");
httpClient.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28");

if (Client.Credentials.AuthenticationType == AuthenticationType.Bearer)
{
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {Client.Credentials.Password}");
}
else if (Client.Credentials.AuthenticationType == AuthenticationType.Basic)
{
httpClient.DefaultRequestHeaders.Add("Authorization", $"token {Client.Credentials.Password}");
}

var encodedQuery = Uri.EscapeDataString(query);
var url = $"https://api.github.com/search/commits?q={encodedQuery}";

var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();

var jsonResponse = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<SearchCommitsResult>(jsonResponse, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
});

return result ?? new SearchCommitsResult { TotalCount = 0, Items = new List<CommitSearchResult>() };
}

#region Content

Expand Down Expand Up @@ -397,4 +436,84 @@ public async Task<List<User>> GetAllOrganizationMembers(string organizationName)

#endregion
}

/// <summary>
/// Represents the result of a commit search operation.
/// This class mirrors the GitHub API response structure for commit search.
/// </summary>
public class SearchCommitsResult
{
public int TotalCount { get; set; }
public bool IncompleteResults { get; set; }
public List<CommitSearchResult> Items { get; set; } = new();
}

/// <summary>
/// Represents a single commit result from the search.
/// Contains essential commit information returned by GitHub API.
/// </summary>
public class CommitSearchResult
{
public string Sha { get; set; } = string.Empty;
public CommitSearchCommit Commit { get; set; } = new();
public string Url { get; set; } = string.Empty;
public string HtmlUrl { get; set; } = string.Empty;
public CommitSearchAuthor Author { get; set; } = new();
public CommitSearchAuthor Committer { get; set; } = new();
public List<CommitSearchParent> Parents { get; set; } = new();
public CommitSearchRepository Repository { get; set; } = new();
}

public class CommitSearchCommit
{
public CommitSearchAuthor Author { get; set; } = new();
public CommitSearchAuthor Committer { get; set; } = new();
public string Message { get; set; } = string.Empty;
public CommitSearchTree Tree { get; set; } = new();
public string Url { get; set; } = string.Empty;
public int CommentCount { get; set; }
}

public class CommitSearchAuthor
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public DateTime Date { get; set; }
public long? Id { get; set; }
public string Login { get; set; } = string.Empty;
public string AvatarUrl { get; set; } = string.Empty;
public string HtmlUrl { get; set; } = string.Empty;
}

public class CommitSearchTree
{
public string Sha { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
}

public class CommitSearchParent
{
public string Sha { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public string HtmlUrl { get; set; } = string.Empty;
}

public class CommitSearchRepository
{
public long Id { get; set; }
public string Name { get; set; } = string.Empty;
public string FullName { get; set; } = string.Empty;
public CommitSearchOwner Owner { get; set; } = new();
public bool Private { get; set; }
public string HtmlUrl { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}

public class CommitSearchOwner
{
public long Id { get; set; }
public string Login { get; set; } = string.Empty;
public string AvatarUrl { get; set; } = string.Empty;
public string HtmlUrl { get; set; } = string.Empty;
}
}
2 changes: 1 addition & 1 deletion csharp/Storage/Storage.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Octokit" Version="7.0.1" />
<PackageReference Include="Octokit" Version="14.0.0" />
<PackageReference Include="Octokit.GraphQL" Version="0.2.1-beta" />
<PackageReference Include="Platform.Data.Doublets.Sequences" Version="0.1.1" />
<PackageReference Include="Platform.Exceptions" Version="0.5.0" />
Expand Down
60 changes: 60 additions & 0 deletions examples/search-commits-example.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Storage.Remote.GitHub;
using System;
using System.Threading.Tasks;

/// <summary>
/// Example demonstrating how to use the SearchCommits functionality
/// that was added to GitHubStorage to work around the missing SearchCommits
/// feature in Octokit.NET library.
/// </summary>
class SearchCommitsExample
{
static async Task Main(string[] args)
{
Console.WriteLine("SearchCommits API Example");
Console.WriteLine("==========================");

// Note: In a real application, you would get these from environment variables or configuration
var githubUsername = "your-github-username";
var githubToken = "your-github-token";
var applicationName = "LinksplatformBot";

Console.WriteLine("This example demonstrates the SearchCommits functionality");
Console.WriteLine("that was implemented to solve GitHub issue #145.");
Console.WriteLine();

// Initialize GitHubStorage (this would normally use real credentials)
Console.WriteLine("Example usage scenarios:");
Console.WriteLine();

// Example 1: Search for commits in a specific repository
Console.WriteLine("1. Search for commits in a specific repository:");
Console.WriteLine(" githubStorage.SearchCommits(\"repo:linksplatform/Bot\");");
Console.WriteLine();

// Example 2: Search for commits by author
Console.WriteLine("2. Search for commits by specific author:");
Console.WriteLine(" githubStorage.SearchCommits(\"repo:linksplatform/Bot author:FreePhoenix888\");");
Console.WriteLine();

// Example 3: Search for commits with specific message
Console.WriteLine("3. Search for commits containing specific text:");
Console.WriteLine(" githubStorage.SearchCommits(\"repo:linksplatform/Bot upgrade framework\");");
Console.WriteLine();

// Example 4: Search for commits in date range
Console.WriteLine("4. Search for recent commits:");
Console.WriteLine(" githubStorage.SearchCommits(\"repo:linksplatform/Bot author-date:>=2024-01-01\");");
Console.WriteLine();

Console.WriteLine("Note: To use this functionality, you need valid GitHub credentials.");
Console.WriteLine("The SearchCommits method returns a SearchCommitsResult object with:");
Console.WriteLine("- TotalCount: Number of matching commits");
Console.WriteLine("- Items: List of CommitSearchResult objects");
Console.WriteLine("- Each CommitSearchResult contains commit SHA, message, author, etc.");
Console.WriteLine();

Console.WriteLine("This implementation bridges the gap until Octokit.NET officially");
Console.WriteLine("adds SearchCommits support as requested in issue #2425.");
}
}
12 changes: 12 additions & 0 deletions examples/search-commits-example.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../csharp/Storage/Storage.csproj" />
</ItemGroup>

</Project>
Loading