microsoft / github-actions-for-desktop-apps

This repo contains a sample WPF application to demonstrate how to create CI/CD pipelines using GitHub Actions.
MIT License
353 stars 109 forks source link

msbuild command for wapproj doesn't work locally via cli #28

Closed bdrum closed 4 years ago

bdrum commented 4 years ago

Hi.

Thanks for the example. It's really helpful!

I would like to clarify some moment: I study your ci.yml file and try to repeat all basics command locally on my machine. So I've got a situation when I can build wapproject via visual studio, but it doesn't build via cli.

Environment:

➜ dotnet --version
3.1.201
➜ dotnet msbuild
Microsoft (R) Build Engine version 16.5.0+d4cbfca49 for .NET Core

➜ Get-ComputerInfo -Property @("OsVersion", "WindowsVersion", "CsSystemType")

OsVersion  WindowsVersion CsSystemType
---------  -------------- ------------
10.0.18363 1909           x64-based PC

As I've already mentioned I can build wapproject via visual studio (2019 community Version 16.5.3), but

➜ dotnet build
Microsoft (R) Build Engine version 16.5.0+d4cbfca49 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

.wapproj(51,3): error MSB4019: The imported project "C:\Program Files\dotnet\sdk\3.1.201\Microsoft\DesktopBridge\Microsoft.DesktopBridge.props" was not found. Confirm that t
he expression in the Import declaration "C:\Program Files\dotnet\sdk\3.1.201\\Microsoft\DesktopBridge\\Microsoft.DesktopBridge.props" is correct, and that the file exists on disk.

Build FAILED.

Compiler complains on this row:

  <PropertyGroup>
    <WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
  </PropertyGroup>
  <Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />

How I understood my .net core sdk doesn't have DesktopBridge.

With dotnet msbuild and all parameters like platform, UapAppxPackageBuildMode and so on the result will be the same.

Do you have any idea how to solve it and it possible in principle I mean pack win exe to appx via .net core sdk?

Thanks and good luck!

edwardskrod commented 4 years ago

Packaging a WPF NetCore application with WapProj can be very tricky. This is because the Wpf project's obj folder needs to be properly populated with the projects target runtime before you package the Wap.

To do this, first you need to define the element in the WPF .csproj. In this case, I do it like this:

win-x86;win-x64

See github-actions-for-desktop-apps/MyWPFApp/MyWPFApp.csproj

Then, you have to "restore" the Wpf app to populate the obj folders. To properly do this, you have to also pass in the RuntimeIdentifier:

    # Restore the application
    - name:  Restore the Wpf application to populate the obj folder
      run: **msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier**
      env:
        Configuration: Debug
        RuntimeIdentifier: win-${{ matrix.targetplatform }}

I know that's confusing!

From there, you should be able to build and package the WAP.

Please let me know if this helps. :)

bdrum commented 4 years ago

Yes, restore option fixed it.

Many thanks!

NSouth commented 4 years ago

@bdrum, would you mind posting the CLI commands that worked for you? I am facing this same issue on my own project. I am restoring my WPF project before building as shown below.

dotnet restore "F:\dev\mySolution.sln" /p:Configuration=Debug;RuntimeIdentifier="win-x64"
dotnet build "F:\dev\mySolution.sln" /p:Configuration=Debug;AppxBundle=Never;Platform=x64;UapAppxPackageBuildMode=SideloadOnly;RuntimeIdentifier="win-x64"

Based on documentation dotnet build runs a restore implicitly, too. I am also declaring the runtime identifiers in my WPF project's .csproj:

<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>

However, I am still getting the error:

F:\dev\myWPF.Packaging.wapproj(56,3): error MSB4019: The imported project "C:\Program Files\dotnet\sdk\3.1.201\Microsoft\DesktopBridge\Microsoft.DesktopBridge.props" was not found. Confirm that the expression in the Import declaration "C:\Program Files\dotnet\sdk\3.1.201\Microsoft\DesktopBridge\Microsoft.DesktopBridge.props" is correct, and that the file exists on disk.

I would appreciate any help, as we need to be able to build via the dotnet core SDK. Thanks.

bdrum commented 4 years ago

@NSouth, yeah, sure:

➜ dotnet build .\GSIPackage.wapproj
Microsoft (R) Build Engine version 16.5.0+d4cbfca49 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

GSIPackage.wapproj(51,3): error MSB4019: The imported project "C:\Program Files\dotnet\sdk\3.1.202\Microsoft\DesktopBridge\Microsoft.DesktopBridge.props" was not found. Confirm that the expression in the Import declaration "C:\Program Files\dotnet\sdk\3.1.202\\Microsoft\DesktopBridge\\Microsoft.DesktopBridge.props" is correct, and that the file exists on disk.

Build FAILED.
    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:00.23

➜ dotnet build .\GSIPackage.wapproj /t:Restore
Microsoft (R) Build Engine version 16.5.0+d4cbfca49 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.30
NSouth commented 4 years ago

Thanks, but that looks like the build command that failed. For the sake of others, here's what is working for me in order to build in a Docker container as part of a Jenkins pipeline:

Make sure my WPF project and its references have RuntimeIdentifiers defined

<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers> in each .csproj.

Add dependencies to my docker image

For me, building only works when using the msbuild.exe that comes with Visual Studio, not when using dotnet build (the installed SDK). Therefore, I needed this on my container. I had to use a base image that already had .NET 4.8 because otherwise installing it requires a restart which is problematic when building the Docker image. Here's an abbreviated version of my dockerfile. The key components are

FROM mcr.microsoft.com/dotnet/framework/sdk:4.8

SHELL ["powershell.exe", "-ExecutionPolicy", "Bypass", "-Command"]

RUN Install-PackageProvider NuGet -Force
RUN Import-PackageProvider NuGet -Force

# Install Chocolatey
RUN Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

RUN choco install dotnetcore-sdk --version 3.1.201 -y
RUN choco install visualstudio2019-workload-universalbuildtools -y
RUN choco install windows-sdk-10-version-1903-all -y

Restore the solution

In the container, the installed MSBuild.exe is found at

C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\bin

Using it, I run the restore operation (and seemingly don't need to pass the RuntimeIdentifier parameter).

msbuild "F:\myPath\MySolution.sln" /t:Restore

For this, using dotnet build appears to also work:

dotnet build "F:\myPath\MySolution.sln" /t:Restore

Build the solution

Finally, this is the build command that is working for me. I probably have some tweaks to make, but this works. My solution contains the WPF and WAP projects and I get the expected results in the AppxPackages folder of the WAP project.

msbuild "F:\myPath\MySolution.sln" /p:Configuration=Release;AppxBundle=Always;AppxBundlePlatforms="x86|x64";Platform=x64
BenjaminMichaelis commented 3 years ago

Whether I am doing it locally on my machine or github actions I am getting the error \5.0.402\Microsoft\DesktopBridge\Microsoft.DesktopBridge.props" was not found and think my problem is similar to the ones above but I can't tell if I just haven't installed something properly (I found the .props file on my computer in 'Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Microsoft\DesktopBridge\Microsoft.DesktopBridge.props' but when I run dotnet test in the command prompt, I get that error still. Is there a pre-instillation condition that has to occur or something when using dotnet test?

LanceMcCarthy commented 3 years ago

@BenjaminMichaelis Are you building this project and getting that error? Or are you asking for help with a different project?

That error output is a bit old and used to happen when you used a VS2015 project structure with DesktopBridge before Project Reunion (see https://stackoverflow.com/questions/56051960/microsoft-desktopbridge-props-was-not-found).

The GitHub Actions runners have the required software installed, just make sure you're using windows-latest for your runner. You can look at my existing project that I ran the other day and published from it https://github.com/LanceMcCarthy/MediaFileManager (see the Actions workflow files and pat attention to my comments above each task)

Locally speaking, do you have the reunion extension installed? https://marketplace.visualstudio.com/items?itemName=ProjectReunion.MicrosoftProjectReunion

brmonaghan commented 3 years ago

I am having the same problem with my Program. It says it cant be found.

LanceMcCarthy commented 3 years ago

@BenjaminMichaelis @brmonaghan

I'll try some runs on a test branch to see if I can reproduce. Can you please share your workflow yaml?

brmonaghan commented 3 years ago

ok there you go.

brmonaghan commented 3 years ago

https://github.com/empointco/BreakTime/blob/master/.github/workflows/dotnet-desktop.yml

brmonaghan commented 3 years ago

@LanceMcCarthy just added you to the repo because it needs to be tested with admin

LanceMcCarthy commented 3 years ago

@brmonaghan I'm working on it now and will push a test branch and test workflow soon (all your original stuff remains unchanged). I'll open an Issue in your repo to continue this conversation.

In the meantime, I can share my initial insights so that anyone else visiting this thread may benefit from.

Problem 1 - Specify Target Platform in csproj/vbproj

Since your project is using .NET 5, you'll want to change

<TargetFramework>net5.0-windows</TargetFramework>

to

<TargetFramework>net5.0-windows10.0.17134.0</TargetFramework>

Problem 2 - WPF Project restoration

Restoring the WPF project's obj is important, specifically this step https://github.com/microsoft/github-actions-for-desktop-apps/blob/bb7a85ae8deddeb0f74ffe504156853808e854b8/.github/workflows/ci.yml#L70-L75

If you have fixed the issue I mentioned in #1, you can move on to this step

I see that your workflow doesn't have a matrix-targetplatform variable or value (there's only a matrix-configuration). It should be the following

  build:
    strategy:
      matrix:
        targetplatform: [x86, x64]

but you have

  build:
    strategy:
      matrix:
        configuration: [Debug, Release]

Since the workflow is expecting a value for the targetplatform variable, it can't create a proper RID. You'll get an empty value like win- instead of win-x86.

image

That explains why the WPF project's obj folder is never restored and the the subsequent steps fail.

Other Observations

I did see other inconsistencies. For example, the AppxBuildMode is set to Store. However you're still signing the package with a code signing cert. You only need to sign the msix when sideloading. When creating a Microsoft Store package, you set /p:AppxPackageSigningEnabled=False (because Microsoft signs it during ingestion).

Suggestion

You can simplify this by using separate workflows for Debug (normal CI builds that you want to go quickly) and Release build that take a long time, but produce an MSIX to sideload or publish to the Store.

Real World Side Loadable and Microsoft Store Example

Go take a look at one of my real world WPF+MSIX project's workflows https://github.com/LanceMcCarthy/MediaFileManager/tree/main/.github/workflows

I am actively using three workflows that do the following:

BenjaminMichaelis commented 3 years ago

@BenjaminMichaelis @brmonaghan

I'll try some runs on a test branch to see if I can reproduce. Can you please share your workflow yaml?

Here's the file: https://github.com/BenjaminMichaelis/SpreadsheetApplication/blob/Packaging/.github/workflows/dotnet-desktop.yml

Mine was having issues both on desktop and github actions when "dotnet test" runs with the error I described before, which makes me suspect it might be with wpp setup itself. (I see maybe the import statement in both mine and @brmonaghan having double \ in it in the error message (https://github.com/empointco/BreakTime/runs/3954291040#step:6:35) but haven't had much time to relook at it in the past 3 days but haven't figured out the exact problem yet.

Update: modified the import location in the .wapproj file to not have double \ and didn't fix the problem.

BenjaminMichaelis commented 3 years ago

Silly me, @LanceMcCarthy got it fixed by removing and readding project. Case closed. 🥴🥴🤦🏻‍♂️

Got an example for reference of the change made? Tried looking in your repo quickly and it still looked like the build was failing so don't see yet where the change was made

brmonaghan commented 3 years ago

Silly me, @LanceMcCarthy got it fixed by removing and readding project. Case closed. 🥴🥴🤦🏻‍♂️

Got an example for reference of the change made? Tried looking in your repo quickly and it still looked like the build was failing so don't see yet where the change was made

HEY! I GOT I FIXED! STUPID ME FORGOT THAT DB IS PLACED IN C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\DesktopBridge\Microsoft.DesktopBridge.props INSTEAD OF THE OLD DIRECTORY! MY COMMIT WILL HAVE THIS. sorry for caps, just excited.

brmonaghan commented 3 years ago

fixed in next release

LanceMcCarthy commented 3 years ago

Thank you both for the discourse, this has made me aware of some limitations to the usefulness of the current setup with .NET 5.

This demo was initially built during the for NET Core 3/3.1 timeframe. There have indeed been a lot of changes in Project Reunion, as well as .NET5 project structure, that causes a bit of confusion when trying to use this example's workflows.

I'll work on updating this demo to use .NET 5/6 and build a set of workflows for .NET5 (similar to my other project's .NET 6 project workflows and packaging)

@edwardskrod should we just replace the NET Core 3.x project with the .NET 5 one? Visitors could always look at the repo history to get workflows for NET Core 3, while keeping the current demo up to date with the latest .NET 5/6/7 release.

brmonaghan commented 3 years ago

C:\Users\runneradmin\AppData\Local\Microsoft\dotnet\sdk\5.0.402\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(241,5): error NETSDK1047: Assets file 'D:\a\BreakTime\BreakTime\Wildcat All-In-One Timer\obj\project.assets.json' doesn't have a target for 'net5.0-windows/win-x64'. Ensure that restore has run and that you have included 'net5.0-windows' in the TargetFrameworks for your project. You may also need to include 'win-x64' in your project's RuntimeIdentifiers. [D:\a\BreakTime\BreakTime\Wildcat All-In-One Timer\BreakTime.vbproj] Now working but with a error!

LanceMcCarthy commented 3 years ago

@brmonaghan See Nsouth's reply above to fix that problem. I have opened an Issue in your repo to explain the problem and how to fix it https://github.com/empointco/BreakTime/issues/6.

You can also review my csproj for guidance https://github.com/LanceMcCarthy/MediaFileManager/blob/4819b30085caacdb2f61cea1a2e33ddbd648a80c/src/MediaFileManager/MediaFileManager.Desktop/MediaFileManager.Desktop.csproj#L2-L20

brmonaghan commented 3 years ago

Got it fixed now. Everybody needs to change their dotnet to msbuild. see empointco/breaktime#6 for details

BenjaminMichaelis commented 3 years ago

Got it working a couple days ago. Might reorient packaging a bit, but this file should still exist even so for reference to help people here: Package and release yml file