Search code examples
gityeomanyeoman-generator

Push to git repo in a yeoman generator?


I'm hoping someone can clarify how Yeoman's spawnCommand() method works a little. I'm working on a generator and I'd like it to initialize a git repo, commit and push the generated app at the end.

I was under the impression that the second parameter being an array, it's an array of commands that would run under the process. So, something like this would run 'git init' followed by 'git remote add origin', etc.

end: function () {
    if(this.repo !== '') {
      this.spawnCommand('git', ['init', 
        'remote add origin ' + this.repo, 
        'add --all', 
        'commit -m "initial commit from generator"', 
        'push -u origin master']
      );
    }
    console.log(yosay('I believe we\'re done here.'));
}

Unfortunately, it just throws a usage error:

usage: git init [-q | --quiet] [--bare] ...

So then I tried doing init on its own followed by the others like this:

end: function () {
    if(this.repo !== '') {
      this.spawnCommand('git', ['init']);
      this.spawnCommand('git', ['remote add origin ' + this.repo, 
        'add --all', 
        'commit -m "initial commit from generator"', 
        'push -u origin master']
      );
    }
    console.log(yosay('I believe we\'re done here.'));
}

The output then makes a little less sense to me:

git: 'remote add origin {URL}' is not a git command. See 'git --help'.
Initialized empty Git repository in /my/project/.git/

This makes me think they're running asynchronously, which might be why adding the remote origin fails, but otherwise I'm very confused.

Is there another way to have the generator push to git, or am I better off not trying to automate the initial push?

EDIT:

Running each command as its own spawnCommand() doesn't work either.

this.spawnCommand('git', ['init']);
this.spawnCommand('git', ['remote add origin ', this.repo]);
this.spawnCommand('git', ['add --all']);
this.spawnCommand('git', ['commit -m "initial commit from generator"']);
this.spawnCommand('git', ['push -u origin master']);

Output:

error: invalid key: pager.remote add origin 
error: invalid key: pager.add --all
error: invalid key: alias.remote add origin
error: invalid key: alias.add --all
error: invalid key: pager.commit -m "initial commit from generator"
error: invalid key: pager.push -u origin master
Initialized empty Git repository in /my/project/.git/
error: invalid key: alias.commit -m "initial commit from generator"
error: invalid key: alias.push -u origin master
git: 'remote add origin ' is not a git command. See 'git --help'.
git: 'push -u origin master' is not a git command. See 'git --help'.
git: 'add --all' is not a git command. See 'git --help'.
git: 'commit -m "initial commit from generator"' is not a git command. See 'git --help'.

Beginning to think this may not be the best way to do this.


Solution

  • Use one this.spawnCommandSync() per git command you want to run.

    this.spawnCommandSync('git', ['init']);
    this.spawnCommandSync('git', ['remote', 'add', 'origin', this.repo]);
    this.spawnCommandSync('git', ['add', '--all']);
    this.spawnCommandSync('git', ['commit', '-m', '"initial commit from generator"']);
    this.spawnCommandSync('git', ['push', '-u', 'origin', 'master']);
    

    The array is an array of string arguments. This is the same interface as node.js spawn - no magic other than wrapping cross-spawn for windows support.

    this.spawnCommand() is asynchronous, so if you use it, you'll need to control the flow so that commands don't all get run at the same time and maybe in the wrong order. Considering this is a yeoman generator, using a synchronous command is usually good enough.