-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Auditing the GitHub API using Analyzers #1
Conversation
General feedback:
private Uri GetResource([CallerMemberName] string method = null)
{
var methodInfo = typeof(this).GetMembers(method).GetCustomAttributes().Single(a => a.Name == "EndPoint").ExtractConstructorArgumentHere();
} (if you have overloads, this gets tricker of course |
@Pilchie thanks for the 👀
|
@Pilchie and I apologise in advance as I'm probably mis-purposing the "Roslyn" name here for the various components of the stack 😁 |
Ok - looking at your commits I understand a bit more what you're trying to do, and it could make sense as a Roslyn analyzer. I was actually thinking that you could steal a page from MVC, and pass an anonymous type with all the parameters into the method, and it could do the substitutions and verify that they match too: private Uri GetResource(object params, [CallerMemberName]method = null)
{
// ...
}
// Note the change from "name" to "repo" so that it matches the attribute.
[Endpoint("GET", "repos/:owner/:repo/issues/events")]
public Task<IReadOnlyList<string>> GetAllForRepository(string owner, string repo)
{
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
Ensure.ArgumentNotNullOrEmptyString(repo, "repo");
var uri = GetResource(new { owner, repo });
return ApiConnection.GetAll<string>(uri);
} (Note, when you go to C# 6, you can also use |
@Pilchie that's interesting, still a runtime concern but avoids the need for an analyzer completely.. |
💯 I like it My assumtion is that you will then use reflection to get every method with the endpoint attribute to match it up to the offical docs? |
@shiftkey 👍 This was exactly what I had in mind and parsing the API was step one. |
What do you mean here? Do you mean that
is not enabled? It seems to me that the approach @Pilchie proposes completely obviates the need to do any checking because the thing we're checking against is the thing that supplies the URL. Why have compile time checking if we can completely remove the need for it. We might even be able to avoid reflection by using a partial class and have Roslyn generate the method to generate the URL based on the attribute. It's funny, because at the MVP summit, Miguel, Mads, and I (among others) talked about a desire for some partial code generation (aka Macros). This seems like a nice potential application of such a thing. 😄 |
@haacked see https://github.com/mattwar/roslyn/tree/Injectors for a prototype of the code injector thing. |
The biggest reason why I'm looking at this approach over reflection (in whatever form) is that we can verify things at compile time. Basically, I'd like to know before executing the code that things are correct (or not correct).
This definitely intrigues me. |
Walk me through this if you don't mind. What kind of things are you checking to see are correct or not via using an attribute and then using it again in the code? |
@haacked sure! Things to check at compile time:
Things to check post-build (reflect over assembly):
|
There's a simple trick to this. In .NET Core/PCL, you have to call
So I typically write an extension method named #IF NOT CORECLR
public static Type GetTypeInfo(this Type type) { return type; }
#ENDIF Also, it looks like As far as I know, all the reflection APIs except reflection emit are available on every platform. There's some small differences. Hopefully, for the types of things we need to do, we could rely on loading attributes in a reflection only context using |
Why not use https://github.com/jbevain/cecil? I am sure this should work in coreclr. I was thinking of doing a PR using cecil. |
@haacked oh! I guess that's one less issue for me to worry about! |
How does the work in octokit/octokit.net#1290 fit into this? (if at all) |
@M-Zuber 1290 makes our usages of URIs more consistent, and we could now audit the |
okay, but aren't you suggesting here to 🔥 the |
@M-Zuber maybe, but I think that's a "nice to have" thing rather than essential... |
I found myself working through the excellent work that @naveensrinivasan had done to parse the GitHub API docs and identify which endpoints had not been implemented in Octokit.
octokit/octokit.net#968 (comment)
And sure, I could audit these manually - in fact I started doing this, but then I paused to think about how I could automate this, so that it could be done more than once.
This PR starts the first step of creating that auditing process. Let me explain what I'm trying to do here...
The Current State Of Affairs
Let's say we have a method that does this:
It's not easy to see what resource this is actually associated with - I need to navigate to
ApiUrls
and look at the implementation:I also need some familiarity with the GitHub API docs to ensure that this is actually the right format (arguments are added, in the correct order).
This is also just a convenience method. I'm not sure it adds much these days.
The Problem
Let's say I have a page of resources that I extracted from the GitHub API docs:
This is just the interesting bits after you parse this page:
https://developer.github.com/v3/activity/events/
If I wanted to be in sync with the GitHub API, I'd like for all of these actions to exist on one of the
Clients
defined here - but how could I verify this programmatically?An Alternative Proposal
Broadly speaking, there's two things I'd like to verify:
/activity/events/
) I'd like to verify that a number of methods are implementedSo let's 🔥 the
ApiUrls
class to the ground as that's getting in the way, and move these resources closer to where they're needed.I'm imagining something like this for defining the contract:
For other scenarios, you may want to specify the verb as well:
Benefits:
ApiConnection
usages matches documented behaviourProblems:
To Do List:
cc @Pilchie @haacked @M-Zuber for general feedback