umbraco / Umbraco.Cloud.Issues

Public issue tracker for Umbraco Cloud
24 stars 2 forks source link

Umbraco Cloud for v11 demands a compilable project in the Git repository #635

Open LennardF1989 opened 1 year ago

LennardF1989 commented 1 year ago

Introduction

So, today for the first time in a long time we decided to use Umbraco Cloud for a v11 project (one of our first upgraded websites that made the cut). 

Our old CI/CD pipeline would prepare all the files (as-if you were deploying to Azure) and commit to result to the repo. Apparently with the transition to v9 the Cloud now "demands" a full dump of all the code on the repos and they will build it for you. This is a no-go for us. The source is dependent on internal packages and sub-modules, and not everyone with access to the Cloud environment should be able to grab all source just like that (Umbraco employees that may get added included), so we simply do not wish to do this.

On top of that, we also pre-compile the whole project as a standalone application so it will remain running even if underlying App Services get their SDKs updated.

Investigation

After some digging around, this is how it currently works.

The whole process relies on the .umbraco file in the root.

[project]
base = "src/UmbracoProject"
csproj = "UmbracoProject.csproj"

If this is missing, empty or somehow corrupted, things go bad quickly. Otherwise the deploy.cmd will proceed to run a series of commands to build and publish whatever that file references.

:: Restore nuget packages
call :ExecuteCmd dotnet restore "%DEPLOYMENT_SOURCE%\%UMBRACO_CSPROJ_PATH%"
IF !ERRORLEVEL! NEQ 0 goto error

:: Build
call :ExecuteCmd dotnet build "%DEPLOYMENT_SOURCE%\%UMBRACO_CSPROJ_PATH%" --configuration Release --no-restore
IF !ERRORLEVEL! NEQ 0 goto error

:: Publish to folder
call :ExecuteCmd dotnet publish "%DEPLOYMENT_SOURCE%\%UMBRACO_CSPROJ_PATH%" --output "%DEPLOYMENT_TEMP%" --configuration Release /p:EnvironmentName=%DOTNET_ENVIRONMENT% --no-restore --no-build
IF !ERRORLEVEL! NEQ 0 goto error

After this, the resulting folder is synced to the wwwroot of the App Service.

I would also like to note that the current deploy.cmd does not build a standalone application. This can lead to situations where after Azure updates the pre-installed SDKs a reboot of the site will no longer make it start (this can happen even if you do not deploy something). This will then demand a recompile with the proper SDK version before the site will startup again. For continuity sake on our side, this is also unacceptable.

Proposed solution

It would be great if we can opt-out of this behavior using the .umbraco file and immediately jump to the KuduSync step.

For example:

[project]
enabled = false

This should be relatively easy to implement inside the deploy.cmd. The KuduSync would then just take the root of the Git repository, and sync that accordingly, only excluding the .git-folder. This is the behavior we've seen for Umbraco 8 and older.

Workaround

I've spend a good two hours playing with this, and found a workaround I would like to share for people who are dealing with this now.

  1. Clone the repistory of an environment
  2. Literally wipe everything, except for:
    • .gitignore (although you might want to replace this with a less strict version that also allows .pdb files, for example)
    • .gitattributes (usually empty)
    • .umbraco
    • .dockerignore (probably optional, but I left it anyway)
    • src/UmbracoProject/UmbracoProject.csproj
    • src/UmbracoProject/umbraco-cloud.json
  3. Add an "output" directory to the root of the repository and put all the files you wish to publish in there.
  4. Replace the contents of the .csproj with the following:

    <Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    </PropertyGroup>
    
    <ItemGroup>
    <None Include="..\..\output\**\*">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    </ItemGroup>
    
    <ItemGroup>
    <Content Include="umbraco-cloud.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    </ItemGroup>
    
    <Target Name="PostPublish" AfterTargets="Publish">
    <Exec Command="del &quot;$(PublishDir)\UmbracoProject.*&quot;" />
    </Target>
    </Project>
  5. Push the changes and lean back!

The magic is in the .csproj:

Upon publish through deploy.cmd, this will build an empty UmbracoProject.dll, copy all files from the output directory, delete the UmbracoProject.dll/.pdb/.deps.json from the publish directory, before KuduSync takes over.

The deletion of the .dll is important because Umbraco will try to load the DLL even though it's not actually referenced in your project. I believe this is only an issue if you try to mix SDK versions/standalone vs. portable compiled DLLs.

As you can see, being able to opt-out would be a lot easier, but it works.

Side-note: This assumes your own project you wish to publish is not called "UmbracoProject". otherwise you will have to rename the default project Umbraco Cloud gives you. Which is fine, I just wanted minimal changes compared to the default setup.

Alternatively, you can add additional scripts to the PostPublish build-step. Technically I can just copy the whole output directory manually using the script as well. In the end it's a workaround for a problem I hope we can see fixed.

sajumb commented 1 year ago

Hi @LennardF1989, Thanks a lot for your feature request for a new CI/CD approach for Umbraco Cloud projects. Your suggestion and insight are really valuable to us, and we appreciate your willingness to share your feedback with us. 🙌

The timing for your feedback is really good timing as next week will have a big focus on defining a new approach for the build and release pipeline when working with Umbraco Cloud projects. I have shared your contribution with the stakeholders of the CI/CD workshop. I am confident that it will be of good use together with the other great contributions that we have received over the past year with the purpose of improving the current workflow.

At Umbraco, we are committed to delivering the best possible experience for our users, and an improved CI/CD flow will be an enabler for your suggestion will undoubtedly help us achieve this goal. We will carefully consider all the requests we receive in this area and work diligently to implement a solution that meets all the needs and requirements of our cloud users.

If you have any additional feedback or suggestions, please do not hesitate to reach out to us. 😄

LennardF1989 commented 1 year ago

You are most welcome, looking forward to those results.

I do would like to point out this is not new in any way, it has worked like that for Umbraco 7 and 8 projects since the inception of Umbraco Cloud: it did not do any source-code building at all. As such, I would like to see that being a supported method of deploying for Umbraco 9+ as well :)

LennardF1989 commented 1 week ago

Any update on this, we're in v14 era and I still need to resort to tricks :P The deploy.cmd as part of the Kudu extension is easily extended with the proposed enabled-check. In terms of sustainability, there is a lot of waste going on now just to work around this.