Skip to content
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

Question: Reusing script utils? #488

Closed
jrnail23 opened this issue Nov 4, 2015 · 18 comments
Closed

Question: Reusing script utils? #488

jrnail23 opened this issue Nov 4, 2015 · 18 comments
Labels

Comments

@jrnail23
Copy link
Contributor

jrnail23 commented Nov 4, 2015

Hey guys, what would be the best way to extract some common utils (things like extension methods, helpers, etc.) for reuse without having to build a true add-in?

I'm trying to refactor a Cake script that's getting a bit too complex for my comfort, so I'm looking for ways to pull common behavior out into other "util" script files that I can reference from my main Cake script.

It looks like #load ./utils/MyHelpers.cake seems to work, and I can define classes and methods there, so that's nice. Unfortunately it doesn't work for extension methods, which is what I'd really prefer for a lot of these kinds of things, for fluency's sake.

Any ideas?
Might it be possible to pull in other referenced files as CakeAliases?

@devlead
Copy link
Member

devlead commented Nov 5, 2015

Because of the current code generation, extension methods aren't allowed as they need to be in a static non nested class.

Probably not impossible but would indeed need some refactoring to work.

@patriksvensson
Copy link
Member

We should be able to extract extension methods from the code, but it would be a lot of work. I would rather wait until Roslyn is used on all platforms. Then it will be a cake walk (pun intended).

@gep13 gep13 added the Question label Nov 5, 2015
@jrnail23
Copy link
Contributor Author

jrnail23 commented Nov 5, 2015

This discussion also reminds me of something I've been meaning to ask you guys.
What strategies do you (or others) use to decompose complex scripts into more manageable components?

@RichiCoder1
Copy link
Contributor

At this point, I generally divvy bits and pieces into other .cake files and #l them.

@jrnail23
Copy link
Contributor Author

jrnail23 commented Nov 5, 2015

@RichiCoder1, I'd like to hear more about your approach.
I'd think that would probably involve defining related tasks in a separate file, then defining the dependencies to/from non-related tasks to the higher-level script. Does that sound accurate so far?

Where do you define your script args? I'd assume you'd define them in the separated file containing the tasks they relate to. That also implies that it might be a bit difficult to see at a glance which args are needed (kind of analogous to constructor injection vs. service location when discussing dependency injection).

Do your separate files assume anything about the externally defined variables/args available to them? Is there a clean way to declare/define such items in those files?

Also, in terms of Cake's script processing, I assume that Cake pretty much combines all the loaded cake scripts into a single scripting context, rather than encapsulating them in specific closures / scopes (thinking about variable scoping between one script and another -- so you wouldn't be able to declare variables of the same name in two different files to be used by the same top-level script). Is that correct?

@devlead
Copy link
Member

devlead commented Nov 5, 2015

@jrnail23 at work we package and fetch common scripts and resources via nuget packages. We have a common repository that has a cake script that packages and deploys them to a private feed continuously.

@jrnail23
Copy link
Contributor Author

jrnail23 commented Nov 5, 2015

@devlead, that's another interesting wrinkle! How do you load those packages? They don't quite seem to fit the definition of #addin or #tool.

EDIT: oh duh, I'm sure you're adding those packages to your packages.config file then just doing #load from the expected nuget package folder, right?

@devlead
Copy link
Member

devlead commented Nov 5, 2015

#tool actually works fine as long you have an stub exe... Now that it's xplat it shouldn't actually care about exe's at second thought.

Though we have an package.json our bootstrapper PowerShell uses and that also can be used as dependency for build server caching of binaries.

@gep13
Copy link
Member

gep13 commented Nov 5, 2015

@devlead said...
at work we package and fetch common scripts and resources via nuget packages.

I think that would be a great article for cakebuild.net, perhaps in a "how-to" section.

@jrnail23
Copy link
Contributor Author

jrnail23 commented Nov 5, 2015

@devlead, Looking at the ScriptProcessor now, if no *.exe files are returned for a tool, it throws an exception saying "Failed to install tool 'MyTool'".
So unless there's something else I don't know about, it doesn't look like the xplat part comes into play there.

So installing the nuget as a #tool works if there's an exe in there, but I think you'd have to reference the specific script file you want to use by hand, right?.
Likeise, it would work as an #addin, if there's a DLL in there, but it also wouldn't pull the packaged script into the current one.

That brings up an interesting question though -- should we consider extending #addin (or some other mechanism) to install packaged cake scripts and load/reference them in one shot?

@kibiz0r
Copy link

kibiz0r commented Jan 26, 2016

Sort of related to this... I have a set of .cake files right now that declare tasks and do some basic operations automatically when they are loaded. I want to package them up as an addin for easy reuse, but it looks like the addin API only allows you to do things when explicitly invoked, which isn't really the point of this particular "addin". Is there a way to declare tasks from an addin and/or run code when #addined?

For now, I'll just deal with requiring consumers to do a MyAddin.Init(), but this kind of support seems necessary for many authors who are migrating components from .cake files to packaged assemblies.

@kibiz0r
Copy link

kibiz0r commented Jan 27, 2016

Actually, it looks like one can't even (simply) declare tasks from an addin, given only a reference to an ICakeContext.

I worked around this by requiring consumers to do MyAddin.Init(this), and then abusing the CakeBuildScriptImpl via reflection in order to declare tasks...

Registering tasks seems like a common use case for addins; am I missing a better option here?

@devlead
Copy link
Member

devlead commented Jan 27, 2016

@kibiz0r haven't seen this use case yet, though as you call Init method from script you could probably pass Task method body to it as a delegate parameter, eliminating the need for reflection.

@gep13
Copy link
Member

gep13 commented Jan 28, 2016

@kibiz0r I have to agree with @devlead here. My approach is the following...

I have a NuGet Package which contains my common scripts:

https://github.com/gep13/ChocolateyPackages/tree/master/gep13.DefaultBuild/Content

And then these are consumed with a parent script, after the NuGet Package is bootstrapped into my environment. From there, I can then use the #l directive to pull though external scripts into the main workflow:

https://github.com/gep13/ReSharperReports/blob/improvements/setup.cake

NOTE: this is still very much a work in progress.

@gep13
Copy link
Member

gep13 commented Jul 19, 2016

@jrnail23 I am going to go ahead and close this, as this is now a known solution, and seems to work for the most part. Please re-open if you feel more is required.

@gep13 gep13 closed this as completed Jul 19, 2016
@MiguelAlho
Copy link

@kibiz0r I know this is old and it's been a while, but have you progressed when building you addin?

I'm trying to do something similar - define a addin that will only be used internally, but has common tasks and sequences with useful defaults. We have dozens of repos and creating the same cake script logic over and over again is tedious. Having a set of conventions and enough configurable points makes script creation /setup a whole lot easier.

Mainly I'm looking for how to register Setup, TaskSetup, TaskTeardown and Tasks from the addin lib.

@pascalberger
Copy link
Member

@MiguelAlho Checkout Cake.Recipe. You can create a similar approach for an internal shared script library, which can be reused across multiple repositories.

@kibiz0r
Copy link

kibiz0r commented Aug 8, 2018

@MiguelAlho: My memory is a little hazy on where my team really landed with this. I think we just used the .Init() approach for a while since we already had it working, but we ultimately moved to React Native so Cake became irrelevant. Sorry I'm not more help.

You might also be interested to check out FAKE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants