dotnet / source-build

A repository to track efforts to produce a source tarball of the .NET Core SDK and all its components
MIT License
266 stars 132 forks source link

Design and implement shared build infrastructure for the VMR #3710

Open ViktorHofer opened 11 months ago

ViktorHofer commented 11 months ago

Mentioned in today's sync meeting. It would be good to define which build infrastructure should be shared and required across all repositories inside the VMR. I was thinking of the following pivots:

  1. The eng/common/ layout: That directory tree is already read-only in consuming repositories and not intended to be changed.
  2. The .NET SDK: The toolset SDK is the thing that is currently propagated via Arcade but picked up at different times. I.e. some repositories today prefer to not be on the latest preview. As part of the VMR consolidation, it makes so re-evaluate that option and consider requiring one version of the SDK for all repositories.
  3. The Arcade SDK: Recently the Arcade SDK got more tied to the .NET SDK so that it can depend on newer features or bugfixes.

There are probably others but these are the main ones that I'm concerned about at the moment.

cc @mmitche @MichaelSimons @dotnet/product-construction

T-Shirt Size Large (includes design and implementation)

MichaelSimons commented 11 months ago

+1

Source-build is already requiring these today but because they way source-build worked in the past, it had to dynamically update the SDK and arcade repos use. Formalizing this will make things so much better/simpler/more understandable. One example is https://github.com/dotnet/source-build/issues/3169.

One thing to note is some repos that are included in multiple products require building with older SDK versions. For this reason we may need an option in the source-mappings to prevent the backflow of these common/shared components.

mmitche commented 11 months ago

I think @ViktorHofer is right on the repo infra that is important to consider. I would add to that list, though:

To frame this discussion, I think it's good to call out that there are two separate copies of repo infrastructure, which may or may not be the same, but which are of equal importance:

The goals, as I see it, are as follows:

Arcade

The first thing to note is that the eng/commmon/* scripts and the Arcade SDK are directly related and tied. While generally compatible across arcade versions, the eng/common scripts are propagated to the repos through arcade updates, based on the sha of the arcade SDK. I.e. if we built arcade SDK 9.0.0-preview.1345.5 from sha abcd, when updating arcade in downstream repos, we copy the eng/common scripts from dotnet/arcade at abcd.

The second thing to note is that more than one Arcade may be in use when building the VMR. If the VMR contains arcade (which would not necessarily be the case, as outlined in https://github.com/dotnet/source-build/blob/main/Documentation/planning/multi-sdk-band-support.md), then are two versions in play. Otherwise, there is one:

Side note - We could theoretically not use live-built assets to build .NET. We could always use the previously built assets. This would have some advantages and disadvantages.

Now, when we look at the VMR today, we see that there are many existing copies of the eng/common scripts, and associated arcades (as defined in the global.json of these locations):

My proposal would be something like the following:

SDK

I think the SDK is a little simpler, based on the fact that it does not have associated scripting, and the one we use is consistent throughout the VMR build.

mmitche commented 11 months ago

Bleh, the more I think about this, the more this feels very messy. Some examples:

mmitche commented 11 months ago

@jaredpar May have opinions.

mmitche commented 11 months ago

I have another big thought, @MichaelSimons and and others may have some thoughts on it too:

A lot of these problems seem stem from us using to build, then building and then using build-time tooling. We use bootstrap version to build a new version, then use it. But we only do this for some kinds of tooling, like arcade. For the build SDK, we use a consistent version throughout. This leads to oddities around how the build time SDK could be upgraded (or not upgraded, but some of the just-built arcade tooling could require a different SDK, yadda yadda). It's messy.

What if we just eliminated this practice altogether? We have an input toolset (arcade, sdk, etc.), and an output toolset (produced from VMR), but we do not use the arcade just-built the VMR to build the rest of the VMR. If there are other cases like this, we would eliminate them. Then, the landscape might look something like this:

The underlying principals here are:

This means that the individual repos, aside from arcade, don't really need their eng/comon dirs in the VMR and they could eliminated. I suggest that we not eliminate them, though, for simplicity's sake.

jaredpar commented 11 months ago

Repo infrastructure may differ in the VMR and within a repo when in isolation (we should not force changes globally to individual repos through the VMR)

Don't understand what is being said here.

We should avoid source edits in the VMR (this may require changes in infra or new product features)

Is this touching on items like how we have to stomp on global.json today in order to build?

but we do not use the arcade just-built the VMR to build the rest of the VMR

Agree on this. I think it is valuable to regularly validate that we can build the VMR with the just-built arcade. Essentially that we can fully bootstrap the VMR. But I do not think it should be part of the default build experience. Doing so adds a lot of overhead and complexity for not that much gain. There are likely going to be times where we need to break compat for larger refactoring and having bootstrapping be part of the default inner build will make that more painful.

The compiler takes this overall approach (default build uses existing toolset, have a leg that validates bootstrap) and is quite happy with the results.

MichaelSimons commented 11 months ago

cc @NikolaMilosavljevic - this relates to the global.json and possibly the nuget.config mutations that get made during source-build.

mmitche commented 9 months ago

T-Shirt Size Large (includes design and implementation)

ViktorHofer commented 9 months ago

We need to figure out what to do with the eng/common scripts.

As we use the live Arcade SDK, we should use the corresponding eng/common files. I'm not sure how we could achieve that without doing yet another set of source edits. Maybe doing source edits is fine for now and we just always overwrite the repo ones with the ones from src/arcade?

Right now, the Windows PoC PR shows so many file changes because we updated all eng/common files manually.

mmitche commented 9 months ago

Yeah, agreed. I wouldn't mind doing a bit of an experiment to see how many assumptions about the eng/common and src/ layouts there is. My guess is quite a lot. This may be very difficult to achieve.

This is one reason that I was somewhat advocating for never using a live-built arcade within the build. If you don't do that then you don't have to worry about using scripts that align with the just-built arcade. Instead, eng/common is the bootstrap arcade's eng/common.

The downside to this approach is that it's harder to make cross-cutting infra changes.

mthalman commented 9 months ago

The downside to this approach is that it's harder to make cross-cutting infra changes.

While not ideal, we could maybe create some mini infrastructure that would allow a dev to author arcade changes and then apply those changes to the VMR as the input Arcade. Then once they have finished iterating on the changes, they could apply the Arcade changes to the arcade repo and then follow up with the rest of the VMR changes afterward. If we could make that a tight dev loop, that would be nice.

ViktorHofer commented 9 months ago

IMO it's useful to use the live built Arcade and the live eng/common scripts whenever possible. Here's one proposal for eng/common:

  1. Add a variable $RepositoryEngineeringCommonDir to tools.ps1 and eng_common_root to tools.sh that have their default value and respect the REPOSITORYENGINEERINGCOMMONDIR environment variable if set.
  2. Add an msbuild property (RepositoryEngineeringCommonDir) to the Arcade SDK with a default setting.
  3. Make repositories respect that env var in native scripts and the msbuild property in the repo specific msbuild infrastructure. This would be part of the "repository contract".
  4. Store the eng/common scripts in the VMR root and remove all the sub repo eng/common directories.
  5. Add the REPOSITORYENGINEERINGCOMMONDIR env var to the orchestrator that points to the VMR eng/common folder and propagate that setting to the inner repos.

The same could be done for the "artifacts" folder in case we would want it to be located in the VMR root as well, i.e. VMR/artifacts/runtime/.