erlang / rebar3

Erlang build tool that makes it easy to compile and test Erlang applications and releases.
http://www.rebar3.org
Apache License 2.0
1.69k stars 515 forks source link

Support for configuring which profiles to use within an alias #2614

Open tak30 opened 3 years ago

tak30 commented 3 years ago

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.

ferd commented 3 years ago

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"}.

tak30 commented 3 years ago

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!!

ferd commented 3 years ago

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.

tak30 commented 3 years ago

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.

ferd commented 3 years ago

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

tak30 commented 3 years ago

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!

gomoripeti commented 2 years ago

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, ...]}
]}.
ferd commented 2 years ago

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.

gomoripeti commented 2 years ago

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 commented 2 years ago

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

tak30 commented 2 years ago

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.