Skip to content

Commit

Permalink
Merge pull request #8 from hlaueriksson/user
Browse files Browse the repository at this point in the history
Metadata HasValidAuthor
  • Loading branch information
hlaueriksson authored Dec 14, 2024
2 parents 492549c + 8b383bc commit 52b9128
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 22 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,11 @@ Logs are written to a file, `ptrun-lint.log`, in the same directory as the tool
| `PTRUN1401` | Plugin metadata should be valid (`<package>`) |
| | Package missing |
| | Repository missing |
| | User missing |
| | ID is invalid |
| | ActionKeyword is not unique |
| | Name does not match plugin folder |
| | Author does not match repo owner |
| | Author does not match GitHub user |
| | Version is invalid |
| | Version does not match filename version |
| | Website does not match repo URL |
Expand Down
5 changes: 5 additions & 0 deletions src/Community.PowerToys.Run.Plugin.Lint/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ public static bool HasValidTargetPlatform(this Package package)
return package.AssemblyAttributeValue(typeof(TargetPlatformAttribute))?.StartsWith("Windows", StringComparison.Ordinal) == true;
}

public static bool HasValidAuthor(this Metadata metadata, User user)
{
return string.IsNullOrEmpty(metadata?.Author) ? false : metadata.Author == user?.login || metadata?.Author == user?.name;
}

private static string? AssemblyAttributeValue(this Package package, Type type)
{
var attribute = package?.AssemblyDefinition?.CustomAttributes.SingleOrDefault(x => x.AttributeType.FullName == type.FullName);
Expand Down
37 changes: 28 additions & 9 deletions src/Community.PowerToys.Run.Plugin.Lint/GitHubClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Community.PowerToys.Run.Plugin.Lint;

public interface IGitHubClient
{
Task<User?> GetUserAsync();
Task<Repository?> GetRepositoryAsync();
Task<Readme?> GetReadmeAsync();
Task<Release?> GetLatestReleaseAsync();
Expand Down Expand Up @@ -36,6 +37,20 @@ public GitHubClient(GitHubOptions options, ILogger logger)
private HttpClient HttpClient { get; }
private ILogger Logger { get; }

public async Task<User?> GetUserAsync()
{
try
{
// https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-a-user
return await HttpClient.GetFromJsonAsync<User>($"/users/{Options.Owner}");
}
catch (Exception ex)
{
Logger.LogError(ex, "GetUserAsync failed.");
return null;
}
}

public async Task<Repository?> GetRepositoryAsync()
{
try
Expand Down Expand Up @@ -86,13 +101,23 @@ public class GitHubOptions
public string Repo { get; set; }
}

/*
{
"login": "octocat",
"name": "monalisa octocat"
}
*/

public class User
{
public string login { get; set; }
public string name { get; set; }
}

/*
{
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"owner": {
"login": "octocat"
},
"html_url": "https://github.com/octocat/Hello-World",
"description": "This your first repo!",
"topics": [
Expand All @@ -110,18 +135,12 @@ public class Repository
{
public string name { get; set; }
public string full_name { get; set; }
public Owner owner { get; set; }
public string html_url { get; set; }
public string description { get; set; }
public string[] topics { get; set; }
public License? license { get; set; }
}

public class Owner
{
public string login { get; set; }
}

public class License
{
public string name { get; set; }
Expand Down
10 changes: 8 additions & 2 deletions src/Community.PowerToys.Run.Plugin.Lint/Rules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public IEnumerable<string> Validate()
}
}

public partial class PluginMetadataRules(Package package, Repository repository) : IRule
public partial class PluginMetadataRules(Package package, Repository repository, User? user) : IRule
{
public int Id => 1401;
public string Description => $"Plugin metadata should be valid {package.ToString().ToFilename()}";
Expand All @@ -239,13 +239,19 @@ public IEnumerable<string> Validate()
yield break;
}

if (user == null)
{
yield return "User missing";
yield break;
}

var metadata = package.Metadata;
string[] actionKeyword = ["=", "?", "!!", ".", "o:", ":", "!", ">", ")", "%%", "#", "//", "{", "??", "$", "_", "<",];

if (!Guid.TryParseExact(metadata.ID, "N", out Guid _)) yield return "ID is invalid";
if (actionKeyword.Contains(metadata.ActionKeyword)) yield return "ActionKeyword is not unique";
if (metadata.Name != RootFolder()) yield return "Name does not match plugin folder";
if (metadata.Author != repository.owner.login) yield return "Author does not match repo owner";
if (!metadata.HasValidAuthor(user)) yield return "Author does not match GitHub user";
if (!Version.TryParse(metadata.Version, out Version? _)) yield return "Version is invalid";
if (metadata.Version != GetFilenameVersion()) yield return "Version does not match filename version";
if (metadata.Website != repository.html_url) yield return "Website does not match repo URL";
Expand Down
4 changes: 3 additions & 1 deletion src/Community.PowerToys.Run.Plugin.Lint/Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public async Task<int> RunAsync()

Validate(rules);

var user = await client.GetUserAsync();

foreach (var package in packages)
{
rules =
Expand All @@ -61,7 +63,7 @@ public async Task<int> RunAsync()
new PackageRules(package),
new PackageContentRules(package),
new PluginDependenciesRules(package),
new PluginMetadataRules(package, repository!),
new PluginMetadataRules(package, repository!, user),
new AssemblyRules(package),
];

Expand Down
13 changes: 13 additions & 0 deletions tests/Community.PowerToys.Run.Plugin.Lint.Tests/ExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,18 @@ public void HasValidTargetPlatform_should_validate_Assembly()
((Package)null!)
.HasValidTargetPlatform().Should().BeFalse();
}

[Test]
public void HasValidAuthor_should_validate_Author()
{
new Metadata { Author = "hlaueriksson" }.HasValidAuthor(new() { login = "hlaueriksson" }).Should().BeTrue();
new Metadata { Author = "Henrik Lau Eriksson" }.HasValidAuthor(new() { name = "Henrik Lau Eriksson" }).Should().BeTrue();
new Metadata { Author = "Foo" }.HasValidAuthor(new() { login = "Bar" }).Should().BeFalse();
new Metadata { Author = "Foo" }.HasValidAuthor(new()).Should().BeFalse();
new Metadata { Author = "Foo" }.HasValidAuthor(null!).Should().BeFalse();
new Metadata { Author = "" }.HasValidAuthor(new() { name = "" }).Should().BeFalse();
new Metadata().HasValidAuthor(new()).Should().BeFalse();
((Metadata)null!).HasValidAuthor(null!).Should().BeFalse();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@ public class GitHubClientTests
public void SetUp()
{
_subject = new GitHubClient(new GitHubOptions { Owner = "hlaueriksson", Repo = "GEmojiSharp" }, NullLogger.Instance);
_subjectWithInvalidOptions = new GitHubClient(new GitHubOptions { Owner = "hlaueriksson", Repo = "Fail" }, NullLogger.Instance);
_subjectWithInvalidOptions = new GitHubClient(new GitHubOptions { Owner = "fail-hlaueriksson", Repo = "Fail-GEmojiSharp" }, NullLogger.Instance);
}

[Test]
public async Task GetUserAsync_should_return_user()
{
var result = await _subject.GetUserAsync();
result.Should().NotBeNull();

result = await _subjectWithInvalidOptions.GetUserAsync();
result.Should().BeNull();
}

[Test]
Expand Down
16 changes: 8 additions & 8 deletions tests/Community.PowerToys.Run.Plugin.Lint.Tests/RulesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,19 +211,19 @@ public void PackageContentRules_should_validate_Package()
[Test]
public void PluginMetadataRules_should_validate_Package()
{
var subject = new PluginMetadataRules(null!, new());
var subject = new PluginMetadataRules(null!, new(), new());
subject.Validate().Clean().Should().BeEquivalentTo(
"Package missing");

var package = new Package(new(), @"..\..\..\Packages\Valid-0.82.1-x64.zip");
package.Load();
subject = new PluginMetadataRules(package, null!);
subject = new PluginMetadataRules(package, null!, new());
subject.Validate().Clean().Should().BeEquivalentTo(
"Repository missing");

package = new Package(new(), @"..\..\..\Packages\NoMetadata-0.82.1-x64.zip");
package.Load();
subject = new PluginMetadataRules(package, new());
subject = new PluginMetadataRules(package, new(), new());
subject.Validate().Clean().Should().BeEquivalentTo(
"Package missing");

Expand All @@ -244,15 +244,14 @@ public void PluginMetadataRules_should_validate_Package()
});
var repository = new Repository
{
owner = new() { login = "hlaueriksson" },
html_url = "https://github.com/hlaueriksson/Community.PowerToys.Run.Plugin.Valid",
};
subject = new PluginMetadataRules(package, repository);
subject = new PluginMetadataRules(package, repository, new());
subject.Validate().Clean().Should().BeEquivalentTo(
"ID is invalid",
"ActionKeyword is not unique",
"Name does not match plugin folder",
"Author does not match repo owner",
"Author does not match GitHub user",
"Version is invalid",
"Version does not match filename version",
"Website does not match repo URL",
Expand All @@ -264,12 +263,13 @@ public void PluginMetadataRules_should_validate_Package()

package = new Package(new(), @"..\..\..\Packages\Valid-0.82.1-x64.zip");
package.Load();
subject = new PluginMetadataRules(package, repository);
var user = new User { login = "hlaueriksson" };
subject = new PluginMetadataRules(package, repository, user);
subject.Validate().Clean().Should().BeEmpty();

package = new Package(new(), @"..\..\..\Packages\ValidZipPathsWithSlash-0.82.1-x64.zip");
package.Load();
subject = new PluginMetadataRules(package, repository);
subject = new PluginMetadataRules(package, repository, user);
subject.Validate().Clean().Should().BeEmpty();

static void SetMetadata(Package package, Metadata metadata)
Expand Down

0 comments on commit 52b9128

Please sign in to comment.