rebar3 icon indicating copy to clipboard operation
rebar3 copied to clipboard

Support for configuring which profiles to use within an alias

Open tak30 opened this issue 2 years ago • 11 comments

Environment

An erlang project that has N rebar profiles, one per company using the project. Each profile has a specific set of dependencies and configurations in order to build a release. We have an alias for running the tests named "test".

Current behaviour

For running the tests of the profile "company_a" we need to run rebar3 as company_a test So we don't have a way of selecting profiles just by running an alias.

Expected behaviour

For running the tests of the profile "company_a" we could run use an alias named "test_company_a" that has configured the profiles to use. Example: rebar3 test_company_a

This would be helpful for not having to store "commands" in a makefile or a shell script.

tak30 avatar Sep 07 '21 07:09 tak30

This would turn things upside down a bit, because the idea is that you can specify rebar3 as <command> whether the command is an alias or not.

Commands themselves can define their own profiles so it's not like there would be no precedent for that, but I have no idea what sort of syntax could be allowed to specify these when aliases are currently just command_name or {command_name, "string args"}.

ferd avatar Sep 07 '21 14:09 ferd

Hi! I've been thinking about the syntax and maybe, in order to not change the current design, the command "as" could be available inside aliases and maybe allow it to only select the profile and not do any command.

Example:

{alias, [
    {test_company_a, [
        {as, "company_a"},
        {ct, "--spec test/conf/test.spec --cover --readable true"}
    ]},

If using the "as" command would be confusing maybe there could be a new one only for selecting the profile:

Example:

{alias, [
    {test_company_a, [
        {set_profile, "company_a"},
        {ct, "--spec test/conf/test.spec --cover --readable true"}
    ]},

Thanks!!

tak30 avatar Sep 08 '21 07:09 tak30

Yeah this is where this gets funky, because supporting 'alias' and 'as' both individually are tricky. The alias module essentially just rewrites existing providers into new ones, working directly on the AST, and defers all calls to the 'do' provider (which chains up other calls), and the 'as' provider requires special core support in parsing for whenever it's called to avoid being confused with a namespace: https://github.com/erlang/rebar3/blob/master/src/rebar_core.erl#L36-L52

Specifically, the 'as' command's need for special considerations prevents it from being used in any way as an alias because of that magic requirement for special syntax.

There's one really buggy way to get it going, and it sort of sucks:

{alias, [
    {exp, [
        {do, "default as fake_profile compile"}
    ]}
]}.

By using do as a command, which calls as from the default namespace, then the command can be passed as-is and somehow bypass some of the safety checks we had put in place to avoid these issues. It's going to be hard to make something nicer than this. Calling it as rebar3 exp will run compile under the fake_profile profile.

ferd avatar Sep 08 '21 14:09 ferd

Oh, I know understand why "as" was not treated as another namespace... I get it The problem I see from using the suggested example is that any new safety check added to the core code could potentially break this functionality as it is not a requirement or a desired functionality.

What about writting a new provider for setting an alias like the one suggested before? (set_profile or any better name) I could try to write it first as a plugin.

tak30 avatar Sep 08 '21 15:09 tak30

I think this could make sense, and easily be done with a plugin as well.

ferd avatar Sep 08 '21 16:09 ferd

Great, I'll let you know as soon as the plugin is written just in case you want to move it to the main code. Thanks for the help!

tak30 avatar Sep 08 '21 17:09 tak30

would it be an option to extend the alias format from a 2-tuple to also support a 3-tuple eg

{alias, [
    {test_company_a, company_a, [test]}
]}.

and the alias provider would create a provider with {profiles, [company_a]}?

(My use case would be less to replace typing rebar3 as company_a test but to be able to include commands with different profiles in an alias eg:

{alias, [
    {test_company_a, company_a, [test]},
...
    {test_all, [test_company_a, test_company_b, ...]}
]}.

gomoripeti avatar Nov 18 '21 12:11 gomoripeti

How do you think this should deal with situations such as rebar3 as company_b test_company_a ? I figure the as priority would be higher than the alias's priority, but this whole thing is just getting messy exceedingly fast.

ferd avatar Nov 18 '21 16:11 ferd

I imagined it would work the same way as rebar3 as company_b eunit would run in a combined company_b+test profile. You mentioned that

Commands themselves can define their own profiles

So without any extra logic and special handling a command or provider that was created on the fly with alias could define its own profile(s) as well. Based on existing logic the profile of as would be applied first, then the profile of the alias, and last the profile of the encapsulated commands. You are right that this opens up the possibility of having really long chain of profiles, but in practice I expect only 2-3. (And if I understand correctly it is already possible to abuse rebar3 as p1, p2, p3, ... cmd)

gomoripeti avatar Nov 18 '21 18:11 gomoripeti

but let me know if this is a totally bad idea, I am ready to accept that :)

gomoripeti avatar Nov 18 '21 18:11 gomoripeti

Hi! I tried the plugin way but somehow it was tricky to understand when the profiles are applied so I don't have yet a working solution. I'll try to dig further as soon as I get some time.

tak30 avatar Nov 19 '21 10:11 tak30