Using Plugins, Deploy Contexts, and/or Environment Variables to create a user-based build process

Hey Netlify, I’m hoping you all could help me determine if Netlify would be able to support the developer experience I’m trying to create for future developers on my team. We’re very interested in Netlify for its front-end friendly workflows and seamless GitHub integration!

TLDR: Using a combination of Netlify’s environment variables, deploy contexts, and/or plugins, is it possible for Netlify to “know” a branch belongs to a certain user, and run a different build command accordingly? Here’s the full breakdown:

Our stack is pretty straightforward:

  • Static javascript SPA built with Create React App
  • Firebase instance for backend Storage, Cloud Functions, and Database
  • Various other services, like Auth0 for authentication and SendGrid for email notifications
  • …and hopefully Netlify for hosting and deploy/branch previews!

We imagine that upon each push to our master branch, Netlify will build our app with a command like this:

npm build && firebase deployTo production-firebase-instance

npm build would package our static html/css/js bundle and throw the result on a fabulous Netlify url. firebase deployTo production-firebase-instance would find the firebase code in our project and upload it to our Firebase instance, in this case, it’s called production-firebase-instance.

With a Firebase instance reserved for production, we’d also like to provision Firebase instances for each contributing developer. Each developer on the team would then have their own Firebase sandbox, like sarah-firebase-instance or david-firebase-instance. This way as developers work, they can test code using their own sandbox firebase instance, instead of the production firebase instance. As developers work on their own branches, we’re imagining the following workflow:

  • Developer Sarah creates a branch off of master called add-new-button and pushes it to GitHub, triggering a Netlify build
  • Somehow knowing the add-new-button branch belongs to Sarah, Sarah’s push would run npm build && firebase deployTo sarah-firebase-instance instead of running npm build && firebase deployTo production-instance
  • Later, when Sarah’s pull request is approved, her code, now merged into master, would trigger another Netlify build. This time, it will be built via npm build && firebase deployTo production-firebase-instance

We thought perhaps all branch names other than master could be prefixed with the developer’s name, and using that name, a build plugin might set a build command dynamically? In that case, a branch name in the format [name]-add-new-button would build via npm build && firebase deployTo [name]-firebase-instance.

What might be the most straightforward way to accomplish this?

I’d love your ideas!

Hey @imjbrad,
Thanks for your patience on this. This seems like an exciting idea for a workflow. Have you checked out our deploy contexts? I wonder if you could accomplish what you want with each dev having their own context?

If not, it would definitely make sense to poke around Build Plugins. I think you’d be working within the world of onPreBuild if you’re trying to somehow parse a branch name and use that to generate a build command during onBuild:

I thought the git utility might be of use to you to get the branch name you’re on:

but it doesn’t actually have access to branch information and you shouldn’t have to have devs include their names in commits, so scratch that!

We’ll drop other ideas here if we have them. And if you decide on a direction and need troubleshooting help along the way, definitely let us know.

You could use git log to grab the username of the person who committed. So long as the committer is always going to commit their specific branch, there’s starters for 10! That, coupled with contexts, would perhaps be the more streamlined approach?

Thank you all! I ended up writing a build plugin:

module.exports = {
  onPreBuild: async ({inputs}) => {

    const context = process.env.CONTEXT;
    const branch = process.env.BRANCH.toUpperCase().replace(/-/g, '_');
    const defaultDevPrefix = "DEV_";

    if (context === "production") {
      console.log("The current context is production, so we we'll only use default vars");
      return;
    }

    const devPrefix = branch.includes(defaultDevPrefix) ?
      branch.substr(0, branch.indexOf(defaultDevPrefix) + defaultDevPrefix.length) : defaultDevPrefix;

    const devVarsAvailable = Object.keys(process.env).some((key) => key.includes(devPrefix));

    if (devPrefix === defaultDevPrefix) {
      console.log(`The dev branch ${branch} doesn't have a custom prefix. Looking to replace env vars with the default indicator ${defaultDevPrefix}`);
    } else if (!devVarsAvailable) {
      console.log(`The branch ${branch} is prefixed with ${devPrefix}, but there are no keys with that prefix. Using default prefix instead ${defaultDevPrefix}`);
    } else {
      console.log(`The branch ${branch} is prefixed with ${devPrefix}. Looking to replace env vars with the same prefix`);
    }

    Object.keys(process.env).forEach(key => {

      const isDevEnvVar = key.includes(devPrefix);

      if (isDevEnvVar) {
        return;
      }

      const targetedPrefixedEnvVar = devPrefix + key;

      if (process.env[targetedPrefixedEnvVar]) {
        const valueForUserPrefixedEnvVar = process.env[targetedPrefixedEnvVar];
        console.log(`Replacing default var ${key} with prefixed var ${targetedPrefixedEnvVar}.`);
        process.env[key] = valueForUserPrefixedEnvVar;
      }

    });

  },
};

So, on any a to sarah-dev-add-new-button, this build plugin would replace the value of any env var with the value of an associated SARA_DEV prefixed env var.

Thanks for the great documentation!

1 Like

yay! i am stoked to see people using our new build plugins feature for super useful stuff :]