cake-build / cake

:cake: Cake (C# Make) is a cross platform build automation system.
https://cakebuild.net
MIT License
3.87k stars 728 forks source link

Unable to use custom static classes with extension methods in cake scripts #1285

Open modernist opened 7 years ago

modernist commented 7 years ago

What You Are Seeing?

I have added a static class containing extension methods for the AssemblyInforParseResult class in order to simplify the instantiation of an AssemblyInfoSettings object. When running the build, I get the following message:

Error: M:/Projects/Dev/CakeTest/common.cake(34,40): error CS1109: Extension methods must be defined in a top level static class; VersioningHelper is a nested class

What is Expected?

I would expect the build script to be compiled without errors. I am guessing this happens because Cake converts the entire cake.build into a single class that is then complied with Roslyn, thus my custom class turns into a nested class, and, correctly, the compiler doesn't allow declaring extension methods in it. I am able to circumvent this by creating a class library with the custom functionality and referencing it, but this is not very convenient as the cake script is no longer self-contained.

What version of Cake are you using? Are you running on a 32 or 64 bit system? What environment are you running on? Windows? Linux? Mac? Are you running on a CI Server? If so, which one?

I am running Cake 0.16.2 on Windows (64bit), both locally and on (on-premise) TFS.

How Did You Get This To Happen? (Steps to Reproduce)

Add a static class containing extension methods to a cake script

Output Log

Module directory does not exist.
Analyzing build script...
Analyzing M:/Projects/Dev/CakeTest/build.cake...
Analyzing M:/Projects/Dev/CakeTest/common.cake...
Processing build script...
Installing addins...
Package Cake.FileHelpers has already been installed.
The addin Cake.FileHelpers will reference Cake.FileHelpers.dll.
Creating script session...
Adding reference to mscorlib.dll...
Adding reference to System.dll...
Adding reference to System.Core.dll...
Adding reference to System.Data.dll...
Adding reference to System.Xml.dll...
Adding reference to System.Xml.Linq.dll...
Adding reference to Cake.Core.dll...
Adding reference to Cake.Common.dll...
Adding reference to Cake.exe...
Adding reference to Cake.FileHelpers.dll...
Importing namespace Cake.Common...
Importing namespace Cake.Common.Build...
Importing namespace Cake.Common.Build.AppVeyor...
Importing namespace Cake.Common.Build.AppVeyor.Data...
Importing namespace Cake.Common.Build.BitbucketPipelines...
Importing namespace Cake.Common.Build.BitbucketPipelines.Data...
Importing namespace Cake.Common.Build.Bitrise...
Importing namespace Cake.Common.Build.Bitrise.Data...
Importing namespace Cake.Common.Build.ContinuaCI...
Importing namespace Cake.Common.Build.ContinuaCI.Data...
Importing namespace Cake.Common.Build.Jenkins...
Importing namespace Cake.Common.Build.Jenkins.Data...
Importing namespace Cake.Common.Build.TravisCI...
Importing namespace Cake.Common.Build.TravisCI.Data...
Importing namespace Cake.Common.Diagnostics...
Importing namespace Cake.Common.IO...
Importing namespace Cake.Common.IO.Paths...
Importing namespace Cake.Common.Net...
Importing namespace Cake.Common.Security...
Importing namespace Cake.Common.Solution...
Importing namespace Cake.Common.Solution.Project...
Importing namespace Cake.Common.Solution.Project.Properties...
Importing namespace Cake.Common.Solution.Project.XmlDoc...
Importing namespace Cake.Common.Text...
Importing namespace Cake.Common.Tools...
Importing namespace Cake.Common.Tools.Cake...
Importing namespace Cake.Common.Tools.Chocolatey...
Importing namespace Cake.Common.Tools.Chocolatey.ApiKey...
Importing namespace Cake.Common.Tools.Chocolatey.Config...
Importing namespace Cake.Common.Tools.Chocolatey.Features...
Importing namespace Cake.Common.Tools.Chocolatey.Install...
Importing namespace Cake.Common.Tools.Chocolatey.Pack...
Importing namespace Cake.Common.Tools.Chocolatey.Pin...
Importing namespace Cake.Common.Tools.Chocolatey.Push...
Importing namespace Cake.Common.Tools.Chocolatey.Sources...
Importing namespace Cake.Common.Tools.Chocolatey.Upgrade...
Importing namespace Cake.Common.Tools.DNU...
Importing namespace Cake.Common.Tools.DNU.Build...
Importing namespace Cake.Common.Tools.DNU.Pack...
Importing namespace Cake.Common.Tools.DNU.Restore...
Importing namespace Cake.Common.Tools.DotCover...
Importing namespace Cake.Common.Tools.DotCover.Analyse...
Importing namespace Cake.Common.Tools.DotCover.Cover...
Importing namespace Cake.Common.Tools.DotNetCore...
Importing namespace Cake.Common.Tools.DotNetCore.Build...
Importing namespace Cake.Common.Tools.DotNetCore.Execute...
Importing namespace Cake.Common.Tools.DotNetCore.Pack...
Importing namespace Cake.Common.Tools.DotNetCore.Publish...
Importing namespace Cake.Common.Tools.DotNetCore.Restore...
Importing namespace Cake.Common.Tools.DotNetCore.Run...
Importing namespace Cake.Common.Tools.DotNetCore.Test...
Importing namespace Cake.Common.Tools.DupFinder...
Importing namespace Cake.Common.Tools.Fixie...
Importing namespace Cake.Common.Tools.GitLink...
Importing namespace Cake.Common.Tools.GitReleaseManager...
Importing namespace Cake.Common.Tools.GitReleaseManager.AddAssets...
Importing namespace Cake.Common.Tools.GitReleaseManager.Close...
Importing namespace Cake.Common.Tools.GitReleaseManager.Create...
Importing namespace Cake.Common.Tools.GitReleaseManager.Export...
Importing namespace Cake.Common.Tools.GitReleaseManager.Publish...
Importing namespace Cake.Common.Tools.GitReleaseNotes...
Importing namespace Cake.Common.Tools.GitVersion...
Importing namespace Cake.Common.Tools.ILMerge...
Importing namespace Cake.Common.Tools.ILRepack...
Importing namespace Cake.Common.Tools.InspectCode...
Importing namespace Cake.Common.Tools.MSBuild...
Importing namespace Cake.Common.Tools.MSTest...
Importing namespace Cake.Common.Tools.NSIS...
Importing namespace Cake.Common.Tools.NuGet...
Importing namespace Cake.Common.Tools.NuGet.Install...
Importing namespace Cake.Common.Tools.NuGet.Pack...
Importing namespace Cake.Common.Tools.NuGet.Push...
Importing namespace Cake.Common.Tools.NuGet.Restore...
Importing namespace Cake.Common.Tools.NuGet.SetApiKey...
Importing namespace Cake.Common.Tools.NuGet.SetProxy...
Importing namespace Cake.Common.Tools.NuGet.Sources...
Importing namespace Cake.Common.Tools.NuGet.Update...
Importing namespace Cake.Common.Tools.NUnit...
Importing namespace Cake.Common.Tools.OctopusDeploy...
Importing namespace Cake.Common.Tools.OpenCover...
Importing namespace Cake.Common.Tools.ReportGenerator...
Importing namespace Cake.Common.Tools.ReportUnit...
Importing namespace Cake.Common.Tools.Roundhouse...
Importing namespace Cake.Common.Tools.SignTool...
Importing namespace Cake.Common.Tools.SpecFlow...
Importing namespace Cake.Common.Tools.SpecFlow.StepDefinitionReport...
Importing namespace Cake.Common.Tools.SpecFlow.TestExecutionReport...
Importing namespace Cake.Common.Tools.TextTransform...
Importing namespace Cake.Common.Tools.VSTest...
Importing namespace Cake.Common.Tools.WiX...
Importing namespace Cake.Common.Tools.WiX.Heat...
Importing namespace Cake.Common.Tools.XBuild...
Importing namespace Cake.Common.Tools.XUnit...
Importing namespace Cake.Common.Xml...
Importing namespace Cake.Core...
Importing namespace Cake.Core.Diagnostics...
Importing namespace Cake.Core.IO...
Importing namespace Cake.Core.Scripting...
Importing namespace Cake.FileHelpers...
Importing namespace System...
Importing namespace System.Collections.Generic...
Importing namespace System.IO...
Importing namespace System.Linq...
Importing namespace System.Text...
Importing namespace System.Threading.Tasks...
Compiling build script...
Error: Roslyn.Compilers.CompilationErrorException: M:/Projects/Dev/CakeTest/common.cake(34,40): error CS1109: Extension methods must be defined in a top level static class; VersioningHelper is a nested class
   at Roslyn.Scripting.CommonScriptEngine.CompilationError(DiagnosticBag localDiagnostics, DiagnosticBag diagnostics)
   at Roslyn.Scripting.CommonScriptEngine.Compile(String code, String path, DiagnosticBag diagnostics, Session session, Type delegateType, Type returnType, CancellationToken cancellationToken, Boolean isInteractive, Boolean isExecute, CommonCompilation& compilation, Delegate& factory)
   at Roslyn.Scripting.CommonScriptEngine.Execute[T](String code, String path, DiagnosticBag diagnostics, Session session, Boolean isInteractive)
   at Roslyn.Scripting.Session.Execute(String code)
   at Cake.Core.Scripting.ScriptRunner.Run(IScriptHost host, FilePath scriptPath, IDictionary`2 arguments)
   at Cake.Commands.BuildCommand.Execute(CakeOptions options)
   at Cake.CakeApplication.Run(CakeOptions options)
   at Cake.Program.Main()
devlead commented 7 years ago

While this isn't possible with the current implementations, weren't opposed to the idea, this would need to be investigated how to best support static classes. Might be something we postpone until we unified around one scripting engine to reduce effort duplication.

daveaglick commented 7 years ago

Lifting type declarations and methods out of a Roslyn script is actually one of my next blog posts :).

I use a walker on the syntax tree to find stuff that should be lifted: https://github.com/Wyamio/Wyam/blob/9a83529aecef73cfacba849b28f892c251b39748/src/core/Wyam.Configuration/ConfigScript/LiftingWalker.cs Then you create the container class and method and stuff the remainder into it, placing all the stuff you lifted outside.

If there's interest I can take a look at what it would take to apply this approach in Cake. The alternate script host might be problematic though because the approach above obviously only works with Roslyn.

devlead commented 7 years ago

@daveaglick sounds interesting, wonder if it could be done as a WIP module to Cake.

patriksvensson commented 7 years ago

Yes, if it requires Roslyn we can add this as soon as we unify the script engines.

petriashev commented 6 years ago

Any progress on this issue? I have the same problem. Is there some workarounds?

devlead commented 6 years ago

Workaround is to just do a static extension method without a surrounding class.

petriashev commented 6 years ago

Thanks, it works!

augustoproiete commented 3 years ago

Repro:

public static class MyBuildExtensions
{
    public static int ToInt(this string value)
    {
        return Convert.ToInt32(value);
    }
}