From 15c73b6ed571e27438843a4e5ce997844209a618 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 12 Dec 2014 09:19:46 -0400 Subject: [PATCH] Document and refactor resin.vcs --- lib/actions/app.coffee | 8 +- lib/resin/vcs/git/git.coffee | 176 ++++++++++++++++++++++++++++-- lib/resin/vcs/git/git.spec.coffee | 14 +-- lib/resin/vcs/vcs.coffee | 44 +++++++- 4 files changed, 220 insertions(+), 22 deletions(-) diff --git a/lib/actions/app.coffee b/lib/actions/app.coffee index 98becbb8..bae11f3b 100644 --- a/lib/actions/app.coffee +++ b/lib/actions/app.coffee @@ -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? diff --git a/lib/resin/vcs/git/git.coffee b/lib/resin/vcs/git/git.coffee index 7e2df76a..2fa89952 100644 --- a/lib/resin/vcs/git/git.coffee +++ b/lib/resin/vcs/git/git.coffee @@ -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') diff --git a/lib/resin/vcs/git/git.spec.coffee b/lib/resin/vcs/git/git.spec.coffee index 31b6a8b8..42506278 100644 --- a/lib/resin/vcs/git/git.spec.coffee +++ b/lib/resin/vcs/git/git.spec.coffee @@ -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 diff --git a/lib/resin/vcs/vcs.coffee b/lib/resin/vcs/vcs.coffee index 6c0498a2..3eed6dbf 100644 --- a/lib/resin/vcs/vcs.coffee +++ b/lib/resin/vcs/vcs.coffee @@ -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