diff --git a/doc/notes.txt b/doc/notes.txt index c417fb88..7b3518c0 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -141,7 +141,7 @@ TODO: - test edge/failure cases - what to do about included files? - what if files already open in editor - - un-bind from repo? + - un-bind from repo? delete repo? - can published files retain path? - what if import interrupted and partial files? - CORS for some blobs? @@ -150,6 +150,9 @@ TODO: - support projects with subdirectories, file list? - emulator needs reset shortcut for nes - local/ files in repository? + - build ca65 projects? https://github.com/pinobatch/thwaite-nes/blob/master/makefile + - switching platform of a repo? + - retaining repo_id in localstorage? WEB WORKER FORMAT diff --git a/src/services.ts b/src/services.ts index 62a8fdac..2cd28526 100644 --- a/src/services.ts +++ b/src/services.ts @@ -18,6 +18,7 @@ export interface GHSession extends GHRepoMetadata { user : string; // user name reponame : string; // repo name repopath : string; // "user/repo" + subtreepath : string; // tree/master/[...] prefix : string; // file prefix, "local/" or "" branch : string; // "master" is default repo : any; // [repo object] @@ -38,7 +39,7 @@ export function parseGithubURL(ghurl:string) { if (toks[0] != 'https:') return null; if (toks[2] != 'github.com') return null; if (toks[5] && toks[5] != 'tree') return null; - return {user:toks[3], repo:toks[4], repopath:toks[3]+'/'+toks[4], branch:toks[6], treepath:toks[7]}; + return {user:toks[3], repo:toks[4], repopath:toks[3]+'/'+toks[4], branch:toks[6], subtreepath:toks[7]}; } export class GithubService { @@ -98,11 +99,12 @@ export class GithubService { no("Please enter a valid GitHub URL."); } var sess = { - url: 'https://github.com/' + urlparse.repopath, + url: ghurl, user: urlparse.user, reponame: urlparse.repo, repopath: urlparse.repopath, branch: urlparse.branch || "master", + subtreepath: urlparse.subtreepath, prefix: '', //this.getPrefix(urlparse.user, urlparse.repo), repo: this.github.repos(urlparse.user, urlparse.repo), platform_id: this.project ? this.project.platform_id : null @@ -121,6 +123,17 @@ export class GithubService { sess.head = head; return sess.repo.git.trees(head.object.sha).fetch(); }) + .then( (tree) => { + if (sess.subtreepath) { + for (let subtree of tree.tree) { + if (subtree.type == 'tree' && subtree.path == sess.subtreepath && subtree.sha) { + return sess.repo.git.trees(subtree.sha).fetch(); + } + } + throw "Cannot find subtree '" + sess.subtreepath + "' in tree " + tree.sha; + } + return tree; + }) .then( (tree) => { sess.tree = tree; return sess; @@ -254,6 +267,9 @@ export class GithubService { var sess : GHSession; return this.getGithubHEADTree(ghurl).then( (session) => { sess = session; + if (sess.subtreepath) { + throw "Sorry, right now you can only commit files to the root directory of a repository."; + } return Promise.all(files.map( (file) => { if (typeof file.data === 'string') { return sess.repo.git.blobs.create({ diff --git a/src/ui.ts b/src/ui.ts index 968a3452..96c7cc48 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -401,9 +401,7 @@ function importProjectFromGithub(githuburl:string) { } // redirect to repo if exists var existing = getRepos()[urlparse.repopath]; - if (existing) { - qs = {repo:urlparse.repopath}; - gotoNewLocation(); + if (existing && !confirm("You've already imported " + urlparse.repopath + " -- do you want to replace all files?")) { return; } // create new store for imported repository diff --git a/test/cli/testgithub.js b/test/cli/testgithub.js index 6ef58325..416cf265 100644 --- a/test/cli/testgithub.js +++ b/test/cli/testgithub.js @@ -30,10 +30,10 @@ describe('Store', function() { it('Should import from Github (check README)', function(done) { var store = mstore.createNewPersistentStore('vcs', function(store) { var gh = newGH(store, 'vcs'); - gh.importAndPull('https://github.com/pzpinfo/test123123').then( (sess) => { + gh.importAndPull('https://github.com/pzpinfo/test123123/').then( (sess) => { console.log(sess.paths); assert.equal(2, sess.paths.length); - assert.deepEqual(serv.getRepos(), {"pzpinfo/test123123":{url: 'https://github.com/pzpinfo/test123123', platform_id: 'vcs', mainPath:'helloworld.bas'}}); + assert.deepEqual(serv.getRepos(), {"pzpinfo/test123123":{url: 'https://github.com/pzpinfo/test123123/', platform_id: 'vcs', mainPath:'helloworld.bas'}}); done(); }); }); @@ -70,7 +70,7 @@ describe('Store', function() { var gh = newGH(store, 'nes'); gh.importAndPull('https://github.com/brovador/NESnake/tree/master/src').then( (sess) => { console.log(sess.paths); - assert.equal(5, sess.paths.length); + assert.equal(14, sess.paths.length); done(); }); }); @@ -116,6 +116,24 @@ describe('Store', function() { }); }); + it('Should commit/push to Github (subdirectory tree)', function(done) { + var store = mstore.createNewPersistentStore(test_platform_id, function(store) { + var gh = newGH(store); + var files = [ + {path:'text.txt', data:'hello world'} + ]; + gh.commitPush('https://github.com/brovador/NESnake/tree/master/src', 'test commit', files) + .catch( (e) => { + console.log(e); + assert.equal(e, 'Sorry, right now you can only commit files to the root directory of a repository.'); + done(); + }); + /*.then( (sess) => { + done(); + });*/ + }); + }); + it('Should bind paths to Github', function(done) { var store = mstore.createNewPersistentStore(test_platform_id, function(store) { var gh = newGH(store); @@ -125,7 +143,7 @@ describe('Store', function() { gh.bind(sess, false); assert.deepEqual(serv.getRepos(), {}); gh.getGithubSession('https://github.com/foo/bar/tree').then((sess) => { - assert.equal(sess.url, 'https://github.com/foo/bar'); + assert.equal(sess.url, 'https://github.com/foo/bar/tree'); assert.equal(sess.repopath, 'foo/bar'); done(); });