Document and refactor resin.vcs

This commit is contained in:
Juan Cruz Viotti 2014-12-12 09:19:46 -04:00
parent 596446835a
commit 15c73b6ed5
4 changed files with 220 additions and 22 deletions

View File

@ -68,10 +68,10 @@ exports.init = (id) ->
async.waterfall [
(callback) ->
resin.vcs.wasInitialized(currentDirectory, callback)
resin.vcs.isResinProject(currentDirectory, callback)
(wasInitialized, callback) ->
if wasInitialized
(isResinProject, callback) ->
if isResinProject
error = new Error('Project is already a resin application.')
return callback(error)
return callback()
@ -80,7 +80,7 @@ exports.init = (id) ->
resin.models.application.get(id, callback)
(application, callback) ->
resin.vcs.initApplication(application, currentDirectory, callback)
resin.vcs.initProjectWithApplication(application, currentDirectory, callback)
], (error) ->
resin.errors.handle(error) if error?

View File

@ -7,20 +7,72 @@ gitCli = require('git-cli')
errors = require('../../errors/errors')
settings = require('../../settings')
# TODO: Refactor somewhere else and reuse trough all modules
# @nodoc
nodeify = (func) ->
return ->
return func.call(null, null, arguments...)
# Get git directory for a certain path
#
# By git directory, we mean the hidden .git folder that every git repository have
#
# @private
#
# @param {String} directory the directory path
# @throw {Error} Will throw if directory is not a string
# @return {String} the absolute path to the child .git directory
#
# @note This function doesn't check if the path is valid, it only constructs it.
#
# @example Get git directory
# result = getGitDirectory('/opt/projects/myapp')
# console.log(result)
# # /opt/projects/myapp/.git
#
exports.getGitDirectory = (directory) ->
return if not directory?
if not _.isString(directory)
throw new Error('Invalid git directory')
return path.join(directory, '.git')
# Get current git directory
#
# Get the path to the .git directory in the current directory
#
# @private
#
# @return {String} the absolute path to the current directory's .git folder
#
# @note The current directory is determined by from where you ran the app
#
# @example Get current git directory
# $ cd /Users/me/Projects/foobar && resin ...
# result = getCurrentGitDirectory()
# console.log(result)
# # /Users/me/Projects/foobar/.git
#
exports.getCurrentGitDirectory = ->
currentDirectory = process.cwd()
return exports.getGitDirectory(currentDirectory)
# Check if a directory is a git repository
#
# @private
#
# @param {String} directory the directory
# @param {Function} callback callback(error, isGitRepository)
#
# @throw {DirectoryDoesntExist} Will throw if directory doesn't exist
#
# @example Is git repository?
# isGitRepository 'my/git/repo', (error, isGitRepository) ->
# throw error if error?
# if isGitRepository
# console.log('Yes, it\'s a git repo!')
# else
# console.log('I should use git here!')
#
exports.isGitRepository = (directory, callback) ->
gitDirectory = exports.getGitDirectory(directory)
@ -39,7 +91,23 @@ exports.isGitRepository = (directory, callback) ->
], callback)
exports.getRepository = (directory, callback) ->
# Get repository instance
#
# An instance of a [gitCli](https://github.com/tuvistavie/node-git-cli) repository, for internal usage.
#
# @private
#
# @param {String} directory the directory
# @param {Function} callback callback(error, repository)
#
# @throw {Error} Will throw if directory is not a git repository.
#
# @example Get repository instance
# getRepositoryInstance 'my/git/repo', (error, repository) ->
# throw error if error?
# # I can now use gitCli functions on `repository`
#
exports.getRepositoryInstance = (directory, callback) ->
exports.isGitRepository directory, (error, isGitRepository) ->
return callback(error) if error?
@ -51,19 +119,77 @@ exports.getRepository = (directory, callback) ->
repository = new gitCli.Repository(gitDirectory)
return callback(null, repository)
# Check if an application is a git app
#
# @private
#
# @param {Object} application an application from resin API
# @return {Boolean} wheter is a valid git application or not
#
# @note All it does is check if the application object contains a valid git_repository field.
# @todo We should also test that the string contained in git_repository is a valid url.
#
# @example Is valid git application?
# resin.models.application.get 91, (error, application) ->
# throw error if error?
# result = isValidGitApplication(application)
# console.log(result)
# # True
#
exports.isValidGitApplication = (application) ->
gitRepository = application.git_repository
return false if not gitRepository?
return false if not _.isString(gitRepository)
return true
# Check if a repository has a certain remote
#
# @private
#
# @param {Object} repository a repository instance from getRepositoryInstance()
# @param {String} name the name of the remote to check for
# @param {Function} callback callback(error, hasRemote)
#
# @todo We should extract the logic that lists all remotes into a separate function.
#
# @example Has origin remote?
# repository = getRepositoryInstance('my/git/repo')
# hasRemote repository, 'origin', (error, hasRemote) ->
# throw error if error?
# if hasRemote
# console.log('It has an origin remote!')
# else
# console.log('It doesn\'t has an origin remote!')
#
exports.hasRemote = (repository, name, callback) ->
repository.listRemotes null, (error, remotes) ->
return callback(error) if error?
hasRemote = _.indexOf(remotes, name) isnt -1
return callback(null, hasRemote)
# TODO: This should be better tested
# Add a remote to a git repository
#
# @private
#
# @param {Object} repository a repository instance from getRepositoryInstance()
# @param {String} name the name of the remote to add
# @param {String} url url of the new remote
# @param {Function} callback callback(error)
#
# @throw {Error} Will throw if name is not a string
#
# @todo We should check the validity of all arguments.
# @todo This function should be better tested
#
# @example Add resin remote
# repository = getRepositoryInstance('my/git/repo')
# addRemote repository, 'resin', 'git@git.resin.io:johndoe/app.git', (error) ->
# throw error if error?
#
# $ cd my/git/repo && git remote -v
# resin git@git.resin.io:johndoe/app.git (fetch)
# resin git@git.resin.io:johndoe/app.git (push)
#
exports.addRemote = (repository, name, url, callback) ->
if not _.isString(name)
error = new Error("Invalid remote name: #{name}")
@ -71,8 +197,27 @@ exports.addRemote = (repository, name, url, callback) ->
repository.addRemote(name, url, callback)
# TODO: This should be better tested
exports.initApplication = (application, directory, callback) ->
# Initialize an application project
#
# - Add the corresponding git remote.
#
# @param {Object} application an application from resin API
# @param {String} directory the directory to initialize
# @param {Function} callback callback(error)
#
# @throw {Error} Will throw if application is not a valid application
#
# @note The directory should already be a git repo (maybe we should take care of git init as well here if necessary?)
# @todo This function should be better tested
#
# @example Init project
# resin.models.application.get 91, (error, application) ->
# throw error if error?
#
# initProjectWithApplication application, 'my/new/project', (error) ->
# throw error if error?
#
exports.initProjectWithApplication = (application, directory, callback) ->
async.waterfall([
@ -83,7 +228,7 @@ exports.initApplication = (application, directory, callback) ->
return callback(error)
(callback) ->
exports.getRepository(directory, callback)
exports.getRepositoryInstance(directory, callback)
(repository, callback) ->
gitUrl = application.git_repository
@ -92,12 +237,27 @@ exports.initApplication = (application, directory, callback) ->
], callback)
# TODO: Find a sane way to test this
exports.wasInitialized = (directory, callback) ->
# Check if an application was already initialized
#
# It checks if we have a resin remote added already.
#
# @param {String} directory the directory
# @param {Function} callback callback(error, isResinProject)
#
# @todo Find a way to test this function
#
# @example Was application initialized?
# isResinProject 'my/resin/app', (error, initialized) ->
# if initialized
# console.log('It\'s already a resin app!')
# else
# console.log('It\'s just a boring project! It should be resinified!')
#
exports.isResinProject = (directory, callback) ->
async.waterfall([
(callback) ->
exports.getRepository(directory, callback)
exports.getRepositoryInstance(directory, callback)
(repository, callback) ->
gitRemoteName = settings.get('gitRemote')

View File

@ -39,7 +39,7 @@ describe 'VCS Git:', ->
expectedResult = path.join(process.cwd(), '.git')
expect(result).to.equal(expectedResult)
describe '#getRepository()', ->
describe '#getRepositoryInstance()', ->
filesystem =
gitRepo:
@ -54,14 +54,14 @@ describe 'VCS Git:', ->
mock.fs.restore()
it 'should throw an error if directory does not exist', (done) ->
git.getRepository '/foobar', (error, repository) ->
git.getRepositoryInstance '/foobar', (error, repository) ->
expect(error).to.be.an.instanceof(Error)
expect(repository).to.not.exist
done()
it 'should return a repository', (done) ->
repo = filesystem.gitRepo
git.getRepository repo.name, (error, repository) ->
git.getRepositoryInstance repo.name, (error, repository) ->
expect(error).to.not.exist
expect(repository).to.exist
@ -181,7 +181,7 @@ describe 'VCS Git:', ->
expect(isGitRepo).to.be.false
done()
describe '#initApplication()', ->
describe '#initProjectWithApplication()', ->
filesystem =
gitRepo:
@ -202,12 +202,12 @@ describe 'VCS Git:', ->
mock.fs.restore()
it 'should return an error if directory is not a git repo', (done) ->
git.initApplication @application, filesystem.notGitRepo.name, (error) ->
git.initProjectWithApplication @application, filesystem.notGitRepo.name, (error) ->
expect(error).to.be.an.instanceof(Error)
done()
it 'should return an error if application does not contain a git repo url', (done) ->
git.initApplication {}, filesystem.gitRepo.name, (error) ->
git.initProjectWithApplication {}, filesystem.gitRepo.name, (error) ->
expect(error).to.be.an.instanceof(Error)
done()
@ -217,7 +217,7 @@ describe 'VCS Git:', ->
addRemoteStub.yields(null)
mock.fs.init(filesystem)
git.initApplication @application, filesystem.gitRepo.name, (error) =>
git.initProjectWithApplication @application, filesystem.gitRepo.name, (error) =>
expect(error).to.not.exist
expect(addRemoteStub).to.have.been.calledOnce

View File

@ -1,5 +1,43 @@
git = require('./git/git')
# We will delegate to git for now
exports.initApplication = git.initApplication
exports.wasInitialized = git.wasInitialized
# TODO: We will delegate to only git for now
# Initialize an application project
#
# - Add the corresponding git remote.
#
# @param {Object} application an application from resin API
# @param {String} directory the directory to initialize
# @param {Function} callback callback(error)
#
# @throw {Error} Will throw if application is not a valid application
#
# @note The directory should already be a git repo (maybe we should take care of git init as well here if necessary?)
# @todo This function should be better tested
#
# @example Init project
# resin.models.application.get 91, (error, application) ->
# throw error if error?
#
# resin.vcs.initProjectWithApplication application, 'my/new/project', (error) ->
# throw error if error?
#
exports.initProjectWithApplication = git.initProjectWithApplication
# Check if an application was already initialized
#
# It checks if we have a resin remote added already.
#
# @param {String} directory the directory
# @param {Function} callback callback(error, isResinProject)
#
# @todo Find a way to test this function
#
# @example Was application initialized?
# resin.vcs.isResinProject 'my/resin/app', (error, initialized) ->
# if initialized
# console.log('It\'s already a resin app!')
# else
# console.log('It\'s just a boring project! It should be resinified!')
#
exports.isResinProject = git.isResinProject