-
Notifications
You must be signed in to change notification settings - Fork 368
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
feat: Refactor generator inputs, and first pass at a container interface #13896
Conversation
9f0b98c
to
1fd2fe3
Compare
@amanda-tarafa: This is far enough along now that it's worth reviewing. I'd encourage you to review one commit at a time, and then note how far you've got (to avoid having to re-review). I don't anticipate modifying earlier commits any more - I suspect it'll be most productive to make changes as new commits. Work still to do is noted in a second tab in the internal document. |
generator-input/tweaks/Google.Cloud.Bigtable.V2/postgeneration.sh
Outdated
Show resolved
Hide resolved
# TODO: Use the appropriate output directory | ||
|
||
GENERATOR_OUTPUT=../../.. | ||
COMPUTE_OUTPUT=$GENERATOR_OUTPUT/apis/Google.Cloud.Compute.V1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving this comment here so I don't forget to ask about this:
Since we'll have <output>/apis
I'm guessing each language can have whatever structure they need under <output>
, right? Which means the CLI can make no assumptions about the structure of <output>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically output is intended to overlay on top of the repo root - the CLI will (currently) make no assumptions about the structure of the repo other than the generator-input directory and a file specifying the container to use.
We may revisit this later, if we want all generated files to live until a single output directory (which then doesn't have any non-generated files in).
@@ -0,0 +1,74 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file itself? It's an input to the generator, so that the whole file is generated - we update "ignorePaths" based on the APIs we generate.
# Build the production library in a temporary directory so that we don't depend on | ||
# whether we're within a repo or not. | ||
rm -rf /tmp/compute | ||
mkdir -p /tmp/compute | ||
|
||
# Even if we've got handwritten code available, we don't want it for this build. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this. This code is very concerned with how a tool may use it. It feels like these isolation concerns should be handled by the tool and not by this code?
And we just had a chat about this, and the general case is that this is happening in an empty directory, that is, no handwritten code available. So, why do we have to double guard ourselves against that happening?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the general case, but not the local development case. We could potentially make sure that we always generate to an empty output directory (and then copy the results) in which case this could be simplified (and yes, I don't like it either). One downside of that would be slowing down local generation - we used to generate separately and then copy, and generating in-place instead massively improved performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm adding a TODO here to remind us to think about this more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think moving the enum constant generator into the GAPIC generator would probably be the best fix for this, to be honest.
/// <summary> | ||
/// Projects that exist in a non-predictable fashion. | ||
/// Only the suffix is required - so for "Google.Cloud.Storage.V2.IntegrationTests" in "Google.Cloud.Storage.V2", this | ||
/// would just have "IntegrationTests". Where the suffix doesn't match, a leading caret (^) is used to indicate this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, do we actually have "where the suffix doesn't match"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One that I'm aware of: in Google.Cloud.Logging.Console, there's a SampleApp directory. It's deliberately not Google.Cloud.Logging.Console.SampleApp, as we don't want namespace defaulting to change what we import.
JArray ignorePaths = (JArray) jobj["ignorePaths"]; | ||
foreach (var api in _catalog.Apis) | ||
{ | ||
ignorePaths.Add($"apis/{api.Id}/{api.Id}/**"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duh, I left a comment somewhere about why renovate was in input.
Maybe there's a way to configure renovate so that we don't have to be explicit about each folder we want to skip? Maybe we can just add the ones we want renovate to look at.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have added a TODO for this. Now that we're using Directory.Packages.props, we might not need to skip at all.
|
||
public sealed class UpdateProjectPropertiesCommand : CommandBase | ||
{ | ||
public UpdateProjectPropertiesCommand() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to run whenever we delete a "special" project then right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can have a github action run this on submit, or a check based on this. Similar to how we check "generate projects".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's also what we'd run when adding a project, I think.
But yes, a github action wouldn't be a bad idea. Will add a TODO.
@@ -0,0 +1,29 @@ | |||
<Project> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yikes, what makes certain these are the same?
Can't you have the root Directory.Packages.props and global.json point to these somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a plan right now. We could at least have some validation step (e.g. a GitHub action).
Mind you, to some extent it doesn't really matter if they're not aligned (and I'd expect there to be Roslyn-based packages in here that aren't in the root one). Let's chat about this more though.
// we get consistent project IDs (hashed from the project name). | ||
// This also means we don't need the project files to exist before we | ||
// create the solution file (as they may be handwritten projects). | ||
// Currently this is really ugly - it will be a lot cleaner with slnx files. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh but so much better than the ghost project files. I prefer this.
(Some scripts will need to be edited due to the change in location.)
(The scripts still need editing.)
…ator-input/tweaks
This also adjusts the post-generation steps to make sure they work without any current handwritten production code. (In other words, we should be able to generate into an entirely empty directory, and the result should be the same as is in the repo, for all the files that end up being generated.) There's still work to do around project and solution files.
…m generator input This includes moving apis.json into generator-input. Changes compared with the status quo: - Coverage XML files are no longer generated - Solution files won't contain project references at the moment - Documentation stubs won't be generated - Either this will become part of the onboarding step, or we'll create one temporarily during documentation generation if the file is absent at that point - We generate test/snippet project files for OsLogin.Common, but there are no C# files. I believe that should be okay, but it's a change.
…r code Code in the generator-input directory needs to be runnable even if it's separate from the rest of the repo.
This allows us to generate solution files predictably - whereas running "dotnet sln add" generates a new project GUID each time.
We should assume we can write to /tmp or equivalent, but not to the current working directory
The "tweaks" should assume they can modify googleapis - the calling code should take a copy beforehand if necessary.
This "supports" generate and clean as subcommands, but both are unimplemented.
Additionally, use a factory method to create an in-place NonSourceGenerator. We'll want further refactoring later, but this is at least better.
This allows us to determine the root directory when building a Docker image.
(We want to regenerate project files etc, even if we don't have a protoc plugin.)
79d764a
to
91033a5
Compare
…eans We have some code which *is* generated code, but not generated in a regular way - e.g. conformance tests, common resource names, BigQuery resource classes. Those are all updated by running their generators manually, so shouldn't be cleaned here.
91033a5
to
55786cb
Compare
This is the result of regenerating all APIs. (There's an uncommitted Artifact Registry change due to duplicate JSON files, which can be fixed separately.)
I believe the test failure is because we're missing the Grafeas project in the solution file. Given that we want project references anyway, I'll just amend the solution generator for that (and check that it actually improves things anyway). |
…rences This solves the client creating testing issue for Google.Cloud.DevTools.ContainerAnalysis.V1, as well as helping for projects such as Spanner.Data. (Regeneration in the next commit.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few nits, this looks good. I'm fine with merging.
var options = new Dictionary<string, string>(); | ||
foreach (var arg in args.Skip(1)) | ||
{ | ||
if (!arg.StartsWith("--") || !arg.Contains('=')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, but: should this be &&
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope - it's an error if either it doesn't start with --
or it doesn't contain =
.
Could change it to: if (!(arg.StartsWith("--") && arg.Contains('=')))
if that would be clearer.
// Source code | ||
DeleteAll(Directory.EnumerateFiles(layout.SourceDirectory, "*.g.cs", SearchOption.AllDirectories)); | ||
// Snippet metadata | ||
DeleteAll(Directory.EnumerateFiles(Path.Combine(layout.SourceDirectory, $"{id}.GeneratedSnippets"), "*.json")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: But maybe you can just delete de GeneratedSnippets folder entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wondered about that, but felt it was risky in terms of potentially accidentally deleting handwritten code. While it would be weird for GeneratedSnippets to have non-generated code, I wouldn't be hugely surprised if it happened...
/// - api-root: effectively the googleapis directory. We take a copy of this before running generation, unless we're running raw generation. | ||
/// - generator-input: optional, when omitted, run "raw generation" | ||
/// - output: root folder for result; required, must exist | ||
/// - api-path: e.g. google/cloud/functions/v2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add: "relative to api-root"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
var id = catalog.Apis.FirstOrDefault(api => api.ProtoPath == apiPath)?.Id; | ||
if (id is null) | ||
{ | ||
// TODO: Optionally, create a temporary configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly using "oboard" command but without saving the result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe. I'm really not sure at the moment, to be honest. It's possible that in-memory will be a better approach, so that we can make generator-input readonly...
No description provided.