From 95208612c37f7a9c2af1764d8501733db0bc0693 Mon Sep 17 00:00:00 2001 From: Elizabeth DuPre Date: Mon, 24 Aug 2020 16:45:05 -0400 Subject: [PATCH 1/6] Initial pass on docs, move from blocked to allow --- editorial/allowed_list.json | 6 + editorial/blacklist.json | 5 - integration/google/OAuth.json | 4 +- integration/google/onSubmit.gs | 526 +++++++++++++++++---------------- 4 files changed, 279 insertions(+), 262 deletions(-) create mode 100644 editorial/allowed_list.json delete mode 100644 editorial/blacklist.json diff --git a/editorial/allowed_list.json b/editorial/allowed_list.json new file mode 100644 index 0000000..ac781a7 --- /dev/null +++ b/editorial/allowed_list.json @@ -0,0 +1,6 @@ +{ + "allowed": [ + "mathieuboudreau", + "TommyBoshkovski" + ] +} \ No newline at end of file diff --git a/editorial/blacklist.json b/editorial/blacklist.json deleted file mode 100644 index 98c067e..0000000 --- a/editorial/blacklist.json +++ /dev/null @@ -1,5 +0,0 @@ -{ -"blocked": ["mathieuboudreau", - "TommyBoshkovski" -] -} diff --git a/integration/google/OAuth.json b/integration/google/OAuth.json index e6928c2..f0b0ab1 100644 --- a/integration/google/OAuth.json +++ b/integration/google/OAuth.json @@ -6,9 +6,9 @@ "runtimeVersion": "V8", "oauthScopes": [ "https://www.googleapis.com/auth/gmail.send", - "https://www.googleapis.com/auth/gmail.compose", + "https://www.googleapis.com/auth/gmail.compose", "https://www.googleapis.com/auth/gmail.modify", "https://www.googleapis.com/auth/gmail.addons.current.action.compose", "https://www.googleapis.com/auth/script.external_request" - ] + ] } \ No newline at end of file diff --git a/integration/google/onSubmit.gs b/integration/google/onSubmit.gs index d67f4ee..89bab93 100644 --- a/integration/google/onSubmit.gs +++ b/integration/google/onSubmit.gs @@ -7,58 +7,58 @@ // ------------------------------------------------------------------------- // OAuth SCOPES // ------------------------------------------------------------------------- -// OAuth Scopes required by this script are given in the appscript.json file +// OAuth Scopes required by this script are given in the appscript.json file // located at NeuroLibre's submit repo (neurolibre/submit/.google). // - This file is not visible by default in the project tab. To -// make it visible, View --> Show manifest file. +// make it visible, View --> Show manifest file. // - After you copy the content of NeuroLibre's appscript.json, make sure // that the OAuth scopes are listed in (File-->Project Properties-->Scopes). // ------------------------------------------------------------------------- // TRIGGER // ------------------------------------------------------------------------- // This project's triggger (Edit-->Current Project's trigger) must have the -// following configuration: +// following configuration: // - Function to run: dispatchToNeuroLibre -// - Runs at deployment: Head +// - Runs at deployment: Head // - Event source: From spreadsheet -// - Event type: On form submit +// - Event type: On form submit // ------------------------------------------------------------------------- // API CALLS // ------------------------------------------------------------------------- -// This script uses GitHub REST API (v3 as of May 2020) to: +// This script uses GitHub REST API (v3 as of May 2020) to: // - Open an issue on the target repository on form submission (POST) // - Fetch issue number and lock the conversation (PUT) // - TODO: Update this header.Script got much bigger. -// Please make sure that the API calls are up to date with the resources -// described by GitHub: https://developer.github.com/. +// Please make sure that the API calls are up to date with the resources +// described by GitHub: https://docs.github.com/. // ------------------------------------------------------------------------- -// VARIABLE NAMING CONVENTIONS +// VARIABLE NAMING CONVENTIONS // ------------------------------------------------------------------------- // To distinguish user-provided global variables from those declared by the script: // -// i - Global variables provided by form submission are stored in formValues +// i - Global variables provided by form submission are stored in formValues // object returned by getFormValues function. All the fieldnames in formValues -// object are CAPITALIZED. +// object are CAPITALIZED. // - var formValues = getFormValues(); -// - formValues.AUTHOR_EMAIL, formValues.AUTHOR_NAME ... etc. -// -// ii - Global variables declared by the script follow camelCase. These variables +// - formValues.AUTHOR_EMAIL, formValues.AUTHOR_NAME ... etc. +// +// ii - Global variables declared by the script follow camelCase. These variables // are intended for easing access to the auxiliary information. List of global -// variable declared by this script are: +// variable declared by this script are: // - mapVal, icon*, logo*, header*, footer*, inspectObject, binderConfig // -// iii - Global variables specifying GitHub repository to which authorized +// iii - Global variables specifying GitHub repository to which authorized // API calls will point (e.g. neurolibre/submit) are CAPITALIZED. // - HANDLE, REPO, TOKEN -// -// iv - Local variables follow snake_case. +// +// iv - Local variables follow snake_case. // // ------------------------------------------------------------------------- // FUNCTION NAMING CONVENTIONS // ------------------------------------------------------------------------- -// i- All the function names follow camelCase. +// i- All the function names follow camelCase. // ------------------------------------------------------------------------- -// Author: Agah Karakuzu | 2020 +// Author: Agah Karakuzu | 2020 // agahkarakuzu@gmail.com, Polytechnique Montreal // GitHub: @agahkarakuzu // ------------------------------------------------------------------------- @@ -74,20 +74,21 @@ var HANDLE = "roboneurotest"; var REPO = "submit"; // GitHub Token (of a dev who has write access to the repo) +// This is visible on script.google.com project var TOKEN = "REDACTED"; // Note that the variable passed to the scope of this project // contains form responses in `.values` field with this mapping between // the column names and the indexes: (A,B,C.. --> 0,1,2...). - + // The following object literal maps the spreadsheet column indexes to // the respective fields. var mapVal = { "author_email": 1, - "author_name": 3, + "author_name": 3, "author_github": 4, - "publication_title": 5, + "publication_title": 5, "publication_type": 6, "article_url": 7, "repo_url":8 @@ -97,10 +98,10 @@ var mapVal = { // ##################################################################### END // --------------------------------------------------------------------- -// Global vars for icons and images +// Global vars for icons and images // ##################################################################### START var iconBinder = "https://avatars3.githubusercontent.com/u/13699731?s=280&v=4"; -var iconJpbook = "https://sphinx-book-theme.readthedocs.io/en/latest/_static/logo.png"; +var iconJpbook = "https://jupyterbook.org/_static/logo.png"; var iconPython = "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-512.png"; var iconNotebook = "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/i/de920fda-40bd-43e8-9ed3-339bb970c3c4/dd8pdzs-cbc64bcd-86d9-4e22-a415-820e63c4e959.png"; var iconGithub = "https://cdn2.iconfinder.com/data/icons/black-white-social-media/64/github_social_media_logo-512.png"; @@ -158,7 +159,7 @@ var inspectObject = { // --------------------------------------------------------------------- -// Global vars for HTML template +// Global vars for HTML template // ##################################################################### START var header = "
" + "
" + @@ -169,8 +170,8 @@ var footer = "
" + "

" + "

" + - "" + - "" + + "" + + "" + "

"; // ##################################################################### END @@ -181,8 +182,8 @@ function dispatchToNeuroLibre(fromForm) var sanity_response; var formValues; - // Use the Properties Service to declare persistent global variables - // These porperties will be broadcasted to the global scope. + // Use the Properties Service to declare persistent global variables + // These properties will be broadcasted to the global scope. // Please see declarations at the below of this function. var script_properties = PropertiesService.getScriptProperties(); @@ -193,28 +194,27 @@ function dispatchToNeuroLibre(fromForm) script_properties .setProperty('publication_type', fromForm.values[mapVal.publication_type]); script_properties .setProperty('article_url', fromForm.values[mapVal.article_url]); script_properties .setProperty('repo_url', fromForm.values[mapVal.repo_url]); - - // Call main function if the sanityCheck is successful. sanity_response = sanityCheck(fromForm.values[mapVal.author_github],fromForm.values[mapVal.author_email], fromForm.values[mapVal.repo_url]); - + if (sanity_response.valid){ - + script_properties.setProperty('repo_owner', sanity_response.owner); script_properties.setProperty('repo_name', sanity_response.repo_name); - - // GET ALL THE FORM VALUES + + // GET ALL THE FORM VALUES formValues = getFormValues(); runSubmissionWorkflow(formValues); - - // Delete all the properties in the current Properties store. + + // Delete all the properties in the current Properties store. script_properties.deleteAllProperties(); }else{ - Logger.log("The submission did not meet the requirements or banned. An email has been sent to the submitter."); + Logger.log("The submission did not meet the requirements or not in allowed list. " + + "An email has been sent to the submitter."); } @@ -222,10 +222,10 @@ function dispatchToNeuroLibre(fromForm) // ENTRY FUNCTION ------------------------------------------------------ END // Expose persistent variables in PropertiesService to the global scope -// These are the values provided upon form submission and are not submitted -// to change. Therefore suitable for global scope. +// These are the values provided upon form submission and are not submitted +// to change. Therefore suitable for global scope. function getFormValues(){ - + var script_properties = PropertiesService.getScriptProperties(); var formValues = { @@ -247,56 +247,60 @@ return formValues; // MAIN FUNCTION // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| START function runSubmissionWorkflow(formValues){ - - var init_response; - var status_comment; - - // OPEN issue + // var status_comment; + + // OPEN issue init_response = openIssueForkRepo(formValues); - + // LOCK issue lockGitHubIssue(init_response.issue_details.number); - - // SEND email on success - GmailApp.sendEmail(formValues.AUTHOR_EMAIL, "Your NeuroLibre submission has been received!","", {htmlBody:getMailBodySuccess(formValues,init_response.issue_details)}); - + + // SEND email on success + // Fields correspond to (recipient, subject, body, options) + GmailApp.sendEmail(formValues.AUTHOR_EMAIL, + "Your NeuroLibre submission has been received!", + "", + {htmlBody:getMailBodySuccess(formValues,init_response.issue_details)} + ); + if (init_response.fork_status){ // IF FORKED - - var welcomer = init_response.issue_details.assignees[0].login; // This is a welcome team member. - - status_comment = makeComment(init_response.issue_details.number,"### Your repo has been forked successfully! " + - "\n It is available at "+ "[" + HANDLE + "/" + formValues.REPO_NAME + "]" + - "(https://github.com/" + HANDLE + "/" + formValues.REPO_NAME +")."); - - // PUT reponame.yml file + + var welcomer = init_response.issue_details.assignees[0].login; // This is a welcome team member. + + status_comment = makeComment(init_response.issue_details.number, + "### Your repo has been forked successfully! " + + "\n It is available at "+ "[" + HANDLE + "/" + formValues.REPO_NAME + "]" + + "(https://github.com/" + HANDLE + "/" + formValues.REPO_NAME +")."); + + // PUT reponame.yml file var yaml = getYAML(formValues,init_response.issue_details.number,welcomer); var status_yaml = putFile(HANDLE,formValues.REPO_NAME,yaml,formValues.REPO_NAME + ".yml", false, false); - + // ADD author as collaborator to the forked repo var status_collab = addCollaborator(HANDLE,formValues.REPO_NAME,formValues.AUTHOR_GITHUB); - - // SYNC files + + // SYNC files var status_sync = syncFiles(HANDLE,REPO,formValues.REPO_NAME,formValues.PUB_TYPE); - + // READY to go message status_comment = makeComment(init_response.issue_details.number,"### We are ready to go!" + - "\n The forked repo has been configured. I am unlocking this conversation." + - "\n ***" + - "\n @" + welcomer + " please touch base with @" + formValues.AUTHOR_GITHUB + + "\n The forked repo has been configured. I am unlocking this conversation." + + "\n ***" + + "\n @" + welcomer + " please touch base with @" + formValues.AUTHOR_GITHUB + " to assign a reviewer to [" + HANDLE + "/" + formValues.REPO_NAME + "]" + "(https://github.com/" + HANDLE + "/" + formValues.REPO_NAME +")." + "\n I am adding the latest list of NeuroLibre's technical review team below: " + - "\n ***" + + "\n ***" + "\n" + getReviewerList()); - + var status_unlock = unlockIssue(init_response.issue_details.number); - + }else{ // IF NOT forked - status_comment = makeComment(init_response.issue_details.number,"Hmm...Looks like I cannot fork this repo."); - + status_comment = makeComment(init_response.issue_details.number, + "Hmm...Looks like I cannot fork this repo. "+ + "Please confirm that the repository is correctly configured."); } - } // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| END @@ -315,8 +319,8 @@ function openIssueForkRepo(formValues){ var response_file ={}; // Body of the GitHub issue - var body = "# Submission details" - + "\n- **Title**: " + formValues.PUB_TITLE + var body = "# Submission details" + + "\n- **Title**: " + formValues.PUB_TITLE + "\n- **Corresponding author**: " + "\n - **Name**: " + formValues.AUTHOR_NAME + "\n - **GitHub handle**: @" + formValues.AUTHOR_GITHUB @@ -328,80 +332,80 @@ function openIssueForkRepo(formValues){ // NeuroLibre's submission form has logic jumps depending // on the type of the submission. Hence, the body of the GitHub - // issue is populated based on this condition. - + // issue is populated based on this condition. + var body_footer; if (formValues.PUB_TYPE == "Publication"){ // Label for the GitHub issue label.push("New Publication"); label.push("pre-review"); - // Add details re article + // Add details re article body = body + "\n- **Associated journal article** " + "\n - **Citation**: " + formValues.ARTICLE_URL + "\n - **URL**: " + "EDIT"; body_footer = footerPublication - + } else{ // Label for GitHub issue label.push("New Tutorial"); label.push("pre-review"); body_footer = footerTutorial; - + } - + // repoDetails.status flag whether to fork // repoDetails.info inspection report var inspection_results = inspectGitHubRepo(formValues); - + if(inspection_results.info !== null && inspection_results.info !== '') { body = body + "\n ## Source repository details" + inspection_results.info; } - + response_file = getFile(HANDLE,REPO,"editorial/neurolibre_roles.json",true,false); - + // THIS MUST BE ARRAY // We should decide if this is gonna be one person every time or multi. - // For now agahkarakuzu only. + // For now agahkarakuzu only. // We can have a set of rules for this. - var nl_assignee = [response_file.payload.welcome_team[1]]; + var nl_assignee = [response_file.payload.welcome_team[1]]; body = body + "\n" + "\n ***" + "\n "; - + var response = openIssue(HANDLE,REPO,title,body,label,nl_assignee); - - // Forwards details about the issue opened. + + // Forwards details about the issue opened. var issue_details = JSON.parse(response.getContentText()); - + var forked = false; // init - + // FORK THE REPOSITORY if (!inspection_results.status){ forked = forkRepo(formValues.REPO_OWNER,formValues.REPO_NAME,"roboneurotest"); - + } - - + + return {issue_details: issue_details, fork_status: forked}; } -// ===================================================================== END +// ===================================================================== END // --------------------------------------------------------------------- // LOCK CONVERSATION BY DEFAULT // ===================================================================== START function lockGitHubIssue(issue_number){ - + // Lock issue, to be unlocked on GitHub. // https://developer.github.com/v3/issues/#lock-an-issue - + var payload = { "locked": true, "active_lock_reason": "resolved" } - + var options = { "method": "PUT", "contentType": "application/vnd.github.sailor-v-preview+json", @@ -410,8 +414,8 @@ function lockGitHubIssue(issue_number){ Authorization: "token " + TOKEN } }; - - var response = UrlFetchApp.fetch("https://api.github.com/repos/"+HANDLE+"/"+REPO+"/issues/"+String(issue_number)+"/lock", options); + + var response = UrlFetchApp.fetch("https://api.github.com/repos/"+HANDLE+"/"+REPO+"/issues/"+String(issue_number)+"/lock", options); //Logger.log(response.getContentText()) } @@ -431,13 +435,13 @@ repo = parseGithubUrl(repo_url); response = UrlFetchApp.fetch("https://api.github.com/repos/" + repo.owner + "/" + repo.repo); - -if(response.getResponseCode() == 200) { + +if(response.getResponseCode() == 200) { answer.valid = true; answer.payload = JSON.parse(response); } - + return answer; } // ===================================================================== END @@ -447,18 +451,18 @@ return answer; // CRAWL GITHUB REPO TREE // ===================================================================== START function inspectGitHubRepo(formValues){ - + var content_info = ''; var warnings = ''; // Get file tree on master recursively. var response = UrlFetchApp.fetch("https://api.github.com/repos/"+ formValues.REPO_OWNER +"/"+ formValues.REPO_NAME +"/git/trees/master?recursive=true"); var response_object = JSON.parse(response); - + var blob_url = "https://github.com/"+formValues.REPO_OWNER+"/" +formValues.REPO_NAME+ "/blob/master/"; - + var cur_f; // Current file var cur_o; // Current object - + var flag = false; for (var i =0; i < inspectObject.files.length;i++){ cur_f = inspectObject.files[i]; @@ -466,52 +470,52 @@ function inspectGitHubRepo(formValues){ content_info += cur_o; if (String(inspectObject.files[i].name) === "Jupyter Notebook" && cur_o == "") flag=true; } - + response = UrlFetchApp.fetch("https://api.github.com/repos/"+ formValues.REPO_OWNER +"/"+ formValues.REPO_NAME +"/contributors"); response_object = JSON.parse(response); - + var contr_list = ""; - for (var i=0; i"; + for (var i=0; i"; } - - var contributors = + + var contributors = "\n ......." + - "\n
" + "Contributors" + " " + + "\n
" + "Contributors" + " " + "
    " + "
    " + - contr_list + + contr_list + "
" + - "

" + + "

" + "
" + "\n"; - + content_info += contributors; - - if (!flag) { - var verdict = - "\n" + + + if (!flag) { + var verdict = + "\n" + "\n|✅ Provided repository looks good. It will be forked to NeuroLibre!|" + "\n|------------------------|" + - "\n"; + "\n"; }else{ - var verdict = - "\n" + + var verdict = + "\n" + "\n|❌ Provided repository does not contain a Jupyter Notebook, Actions won't be triggered.|" + "\n|------------------------|" + - "\n"; + "\n"; } - return {info: verdict + content_info, status: flag}; + return {info: verdict + content_info, status: flag}; } // ===================================================================== END function sanityCheck(author_github, author_email, repo_url){ // This function is to check if: -// i - Author has a valid Github account +// i - Author has a valid Github account // ii - The URL submitted is a GitHub repository -// iii - The author_github OR the repo_owner are not banned. -// Returns an object with fields: +// iii - The author_github OR the repo_owner allowed. +// Returns an object with fields: // valid: Both (i) and (ii) are met // repo_owner: Owner of the passed repo_url // repo_name: Name of the passed repo_url @@ -522,66 +526,73 @@ function sanityCheck(author_github, author_email, repo_url){ var owner=""; var name=""; var msg =""; - - // Check if author_github exists as a GitHub user + + // Check if author_github exists as a GitHub user response_user = getUserInfo(author_github); if (!response_user.valid){ flag = false; msg = "Provided GitHub user (" + author_github + ") does not exist."; } - + response_repo = getGitHubInfo(repo_url); - if (!response_user.valid){ + if (!response_repo.valid){ flag = false; msg = msg + "\n Provided GitHub repository (" + repo_url + ") does not exist."; }else{ - + owner = response_repo.payload.owner.login; name = response_repo.payload.name; } // Send user an email about the failed submission if (!flag){ - - GmailApp.sendEmail(author_email, "Your NeuroLibre submission has failed!","", {htmlBody:getMailBodyFailure(author_github,msg)}); - + GmailApp.sendEmail(author_email, + "Your NeuroLibre submission has failed!", + "", + {htmlBody:getMailBodyFailure(author_github,msg)} + ); } - - // GET LIST OF BLOCKED USERS + + // GET LIST OF ALLOWED USERS var response={}; - response = getFile(HANDLE,REPO,"editorial/blacklist.json",true, false); + response = getFile(HANDLE,REPO,"editorial/allowed_list.json",true, false); // RAISE THE BYPASS FLAG & SEND EMAIL - if (response.payload.blocked.includes(author_github) || response.payload.blocked.includes(owner)){ - flag = false; - msg = "\n Corresponding author and/or the repo owner are banned. If you think that this is an error, we would very much appreciate to hear from you." + - "You can open an issue on neurolibre/submit repository to reach out to us."; - GmailApp.sendEmail(author_email, "Your NeuroLibre submission has failed!","", {htmlBody:getMailBodyFailure(author_github,msg)}); + if (!response.payload.allowed.includes(author_github) || !response.payload.allowed.includes(owner)){ + flag = false; + msg = "\n Corresponding author and/or the repo owner are not included in the allowed list. " + + "If you think that this is an error, we would very much appreciate to hear from you. " + + "You can open an issue on neurolibre/submit repository to reach out to us."; + GmailApp.sendEmail(author_email, + "Your NeuroLibre submission has failed!", + "", + {htmlBody:getMailBodyFailure(author_github,msg)} + ); }else if (response.payload == null){ //Logger.log("I could not read the json file, you should probably kill the operation."); } -return {valid: flag, repo_owner: owner, repo_name:name }; +return {valid: flag, repo_owner: owner, repo_name: name }; } function getMailBodySuccess(formValues,response_object) { // This functions returns an HTML mail body on a successful submission. -// Mail content is populated by the information fetched from the spreadsheet. - +// Mail content is populated by the information fetched from the spreadsheet. + var html_body= "" + - header + + header + "

Dear " + formValues.AUTHOR_NAME + "


"+ "

This mail is to confirm that we have successfully received your NeuroLibre submission.

" + "

"+ formValues.PUB_TITLE + "

" + "

Your submission ID is #" + String(response_object.number) + ".

" + "
"+ - "

" + - "

We would like to remind you that the reviewing process will happen on .

" + + "

" + + "

We would like to remind you that the reviewing process will happen on .

" + "

To that end, we have automatically created an issue for your submission in the neurolibre/submit repository.

" + "" + "" + @@ -590,8 +601,8 @@ var html_body= "

" + "

Following an automated check, your " + formValues.REPO_OWNER +"/" + formValues.REPO_NAME + " repository will be forked in neurolibre/" + formValues.REPO_NAME + ", if the minimum viable content is available.

" + "

Our system will notify you (@" + formValues.AUTHOR_GITHUB + ") through .

" + - "

For further information, please visit our reviewing workflow." + - "

Best regards,

" + + "

For further information, please visit our reviewing workflow." + + "

Best regards,

" + "
" + "" + footer; @@ -600,17 +611,17 @@ return html_body; } function getMailBodyFailure(author_name,errMsg){ -var html_body = +var html_body = "" + - header + + header + "
" + - "

Dear " + author_name + "


"+ - "

" + - "

" + errMsg + "

" + + "

Dear " + author_name + "


"+ + "

" + + "

" + errMsg + "

" + "

" + - "" + - footer; - + "" + + footer; + return html_body; } @@ -621,7 +632,7 @@ function url_exists(url) { try { var safeurl=url.replace(/[{}]/g,""); var response = UrlFetchApp.fetch(safeurl); - if(response.getResponseCode() == 200) { + if(response.getResponseCode() == 200) { ret_value = true; } } catch (err) { @@ -633,40 +644,40 @@ function url_exists(url) { function getCollapsibleMD(response_object,obj,blob_url){ var items = []; - + if (obj.format instanceof Array && obj.format.length >1){ - + for (var i =0;i < obj.format.length; i++){ var tmp = getFileArray(response_object, String(obj.format[i]),obj.abs_match); if (tmp && tmp.length){ items.push(tmp.slice(0)); } - } - + } + }else{ items = getFileArray(response_object, obj.format,obj.abs_match); } if (items.length!=0){ - - var obj_num = items.length; + + var obj_num = items.length; var title = String(obj_num) + " " + obj.name; - if (items.length > 1) title = title + obj.plural; + if (items.length > 1) title = title + obj.plural; var uList = ''; for (var i = 0; i < items.length; i++) { - if (i==0) uList += "
"; + if (i==0) uList += "
"; uList = uList + "
  • " + items[i] + "
  • "; } - + var collapsible = "\n ......." + - "\n
    " + title + " " + - "
      " + - uList + + "\n
      " + title + " " + + "
        " + + uList + "
      " + - "

      " + + "

      " + "
      "; - + } else{ var collapsible = ""; } @@ -681,40 +692,41 @@ function getFileArray(obj,extension,abs_match) { var count = 0; for (var i = 0; i < obj.tree.length; i++) { curStr = String(obj.tree[i].path); - if (!abs_match){ - if (curStr.indexOf(extension)>-1) - {count++; + if (!abs_match){ + if (curStr.indexOf(extension)>-1) + {count++; file_info.push(curStr);} }else{ if (curStr === extension) - {count++; - file_info.push(curStr);} + {count++; + file_info.push(curStr);} } - + } return file_info; } function getFile(owner,repo,file,isjson,bypass){ -// Add GITHUB API documentation link +// See GitHub API for call details: +// https://docs.github.com/en/rest/reference/repos#get-repository-content // TODO: FIX VARIABLE NAMING HERE - + var answer = {"valid":true, "payload": null}; var decoded; var response = UrlFetchApp.fetch("https://api.github.com/repos/" + owner + "/" + repo + "/contents/" + file); //Logger.log("GETFILE" + response.getContentText()); - + if (response.getResponseCode() == 200){ - + var jsn = JSON.parse(response.getContentText()); if (!bypass){ decoded = Utilities.base64Decode(jsn.content); }else{ - // In case need to keep content untouched. + // In case need to keep content untouched. decoded = jsn.content; } - + if (!bypass){ if (isjson){ answer.payload = JSON.parse(Utilities.newBlob(decoded).getDataAsString()); @@ -724,7 +736,7 @@ function getFile(owner,repo,file,isjson,bypass){ }else{ // IF BYPASS answer.payload = decoded; } - + }else{ // NOT RESPONSE 200 answer.valid = false; } @@ -733,20 +745,21 @@ return answer; } function putFile(owner,repo,content,path, isjson, bypass){ -// Add GITHUB API documentation link - +// See GitHub API for call details: +// https://docs.github.com/en/rest/reference/repos#create-or-update-file-contents + if (isjson) content = JSON.stringify(content); - + if(!bypass){ var encoded = Utilities.base64Encode(content); }else{ // In case need to keep content untouched. var encoded = content; } - + var msg = "🤖 Adding file: " + path; - - var payload = { + + var payload = { // TODO: Update this to roboneuro "message": msg, "committer": { "name": "Agah Karakuzu", @@ -754,7 +767,7 @@ function putFile(owner,repo,content,path, isjson, bypass){ }, "content": encoded }; - + var options = { "method": "PUT", "contentType": "application/json", @@ -763,7 +776,7 @@ function putFile(owner,repo,content,path, isjson, bypass){ Authorization: "token " + TOKEN } }; - + var response = UrlFetchApp.fetch("https://api.github.com/repos/" + owner + "/" + repo + "/contents/" + path,options); //Logger.log("PUTFILE" + response.getContentText()); var status = response.getResponseCode(); @@ -772,15 +785,16 @@ return status; } function openIssue(owner,repo,title,body,label,assignee){ -// Add GITHUB API documentation link - +// See GitHub API documentation for call details: +// https://docs.github.com/en/rest/reference/issues#create-an-issue + var payload = { "title": title, "body": body, "labels": label, "assignees": assignee }; - + var options = { "method": "POST", "contentType": "application/json", @@ -789,20 +803,21 @@ function openIssue(owner,repo,title,body,label,assignee){ Authorization: "token " + TOKEN } }; - - // OPEN THE FIRST ISSUE + + // OPEN THE FIRST ISSUE var response = UrlFetchApp.fetch("https://api.github.com/repos/"+owner+"/"+repo+"/issues", options); - return response; + return response; } function forkRepo(owner,repo,into_orgname){ -// Add GITHUB API documentation link - +// See GitHub API documentation for call details: +// https://docs.github.com/en/rest/reference/repos#create-a-fork + var payload = { "organization": into_orgname }; - + var options = { "method": "post", "contentType": "application/json", @@ -812,16 +827,17 @@ function forkRepo(owner,repo,into_orgname){ }, "muteHttpExceptions": true // Do not break the workflow if cannot fork }; - + var response = UrlFetchApp.fetch("https://api.github.com/repos/"+owner+"/"+repo+"/forks", options); var answer; response.getResponseCode()==202 ? answer = true : answer=false; - + return answer; } function getUserInfo(user_handle){ -// Add GITHUB API documentation link +// See GitHub API documentation for call details: +// https://docs.github.com/en/rest/reference/users#get-a-user var response = UrlFetchApp.fetch("https://api.github.com/users/" + user_handle); var answer = {"valid":true, "payload": null}; @@ -836,46 +852,46 @@ return answer; function getYAML(formValues, issueNumber, assignee){ var yaml; - yaml = + yaml = "title: " + formValues.PUB_TITLE + - "\nsummary: Please add a brief (50-60 words) summary of your work. This summary will appear at the publication card (https://neurolibre.com)" + + "\nsummary: Please add a brief (50-60 words) summary of your work. This summary will appear at the publication card (https://neurolibre.com)" + "\nauthors:" + "\n- name: " + formValues.AUTHOR_NAME + "\n website: https://github.com/" + formValues.AUTHOR_GITHUB + "\n affiliation: Please type in your affiliation here. For multiple affiliations, see the next author entry" + "\n# Please pay attention to indentations when adding multiple authors." + - "\n- name: Another Author" + + "\n- name: Another Author" + "\n website: If availabe, this entry can point to author's GitHub page or personal website. Please delete this line if not available." + - "\n affiliation:" + - "\n - Affiliation 1" + + "\n affiliation:" + + "\n - Affiliation 1" + "\n - Affiliation 2" + "\nkeywords:" + "\n - kw1" + "\n - kw2" + - "\nsubmission:" + - "\n date: " + Utilities.formatDate(new Date(), "GMT-4", "yyyy-MM-dd") + + "\nsubmission:" + + "\n date: " + Utilities.formatDate(new Date(), "GMT-4", "yyyy-MM-dd") + "\n id: " + issueNumber + - "\n assignee: " + assignee + - "\n category: " + formValues.PUB_TYPE + + "\n assignee: " + assignee + + "\n category: " + formValues.PUB_TYPE + "\n upstream: https://github.com/" + formValues.REPO_OWNER + "/" + formValues.REPO_NAME; - + if (formValues.PUB_TYPE == "Publication"){ - yaml = yaml + - "\nassociated_publication:" + - "\n- citation: " + "EDIT" + - "\n url: " + formValues.ARTICLE_URL; + yaml = yaml + + "\nassociated_publication:" + + "\n- citation: " + "EDIT" + + "\n url: " + formValues.ARTICLE_URL; } - + return yaml; } function addCollaborator(org,repo,user){ // PUT /repos/:owner/:repo/collaborators/:username - + var payload = { "permission": "push" }; - + var options = { "method": "put", "contentType": "application/json", @@ -885,12 +901,12 @@ function addCollaborator(org,repo,user){ }, "muteHttpExceptions": true // Do not break the workflow if cannot invite }; - + var response = UrlFetchApp.fetch("https://api.github.com/repos/"+org+"/"+repo+"/collaborators/" + user, options); //Logger.log(response.getContentText()); var answer; response.getResponseCode()==201 ? answer = true : answer=false; - + return answer; } @@ -905,9 +921,9 @@ function syncFiles(org,origin_repo,target_repo,pub_type){ }else{ file_list.push({from: "images/tutorial_template.png", to: target_repo + "_featured.png"}); } - + for (var i =0; i" + "NeuroLibre reviewers" + ""; var iInfo = {}; var experience = ''; - + for (var i = 0; i < team.length; i++) { - + iInfo = getUserInfo(team[i].handle); - - if (i==0) uList += "
      "; - - uList = uList + + + if (i==0) uList += "
      "; + + uList = uList + "
      " + iInfo.payload.name + "" + "
      " + - "" + team[i].affiliation + "
      " + - "Repos: " + iInfo.payload.repos_url + "
      " + + "" + team[i].affiliation + "
      " + + "Repos: " + iInfo.payload.repos_url + "
      " + "Twitter: " + iInfo.payload.twitter_username + "
      " - "Experience: " ; - + "Experience: " ; + experience = ''; for (var j=0; j< team[i].expertise.length; j++){ experience += "" + team[i].expertise[j] + " "; } - + uList = uList + experience + "
      "; - + } - + uList = uList + "
    "; return uList; From ef505f9990017e20365cb91b3de67b0bf94a2608 Mon Sep 17 00:00:00 2001 From: Elizabeth DuPre Date: Tue, 25 Aug 2020 17:12:36 -0400 Subject: [PATCH 2/6] Do not lock conversation, smaller updates --- integration/google/onSubmit.gs | 161 ++++++++++++++++----------------- 1 file changed, 77 insertions(+), 84 deletions(-) diff --git a/integration/google/onSubmit.gs b/integration/google/onSubmit.gs index 89bab93..84213e2 100644 --- a/integration/google/onSubmit.gs +++ b/integration/google/onSubmit.gs @@ -28,7 +28,7 @@ // This script uses GitHub REST API (v3 as of May 2020) to: // - Open an issue on the target repository on form submission (POST) // - Fetch issue number and lock the conversation (PUT) -// - TODO: Update this header.Script got much bigger. +// - TODO: Why do we lock the conversation? // Please make sure that the API calls are up to date with the resources // described by GitHub: https://docs.github.com/. // ------------------------------------------------------------------------- @@ -74,7 +74,7 @@ var HANDLE = "roboneurotest"; var REPO = "submit"; // GitHub Token (of a dev who has write access to the repo) -// This is visible on script.google.com project +// This is visible on the script.google.com project var TOKEN = "REDACTED"; // Note that the variable passed to the scope of this project @@ -253,8 +253,8 @@ function runSubmissionWorkflow(formValues){ // OPEN issue init_response = openIssueForkRepo(formValues); - // LOCK issue - lockGitHubIssue(init_response.issue_details.number); + // // LOCK issue + // lockGitHubIssue(init_response.issue_details.number); // SEND email on success // Fields correspond to (recipient, subject, body, options) @@ -285,7 +285,7 @@ function runSubmissionWorkflow(formValues){ // READY to go message status_comment = makeComment(init_response.issue_details.number,"### We are ready to go!" + - "\n The forked repo has been configured. I am unlocking this conversation." + + // "\n The forked repo has been configured. I am unlocking this conversation." + "\n ***" + "\n @" + welcomer + " please touch base with @" + formValues.AUTHOR_GITHUB + " to assign a reviewer to [" + HANDLE + "/" + formValues.REPO_NAME + "]" + @@ -294,7 +294,7 @@ function runSubmissionWorkflow(formValues){ "\n ***" + "\n" + getReviewerList()); - var status_unlock = unlockIssue(init_response.issue_details.number); + // var status_unlock = unlockIssue(init_response.issue_details.number); }else{ // IF NOT forked status_comment = makeComment(init_response.issue_details.number, @@ -365,9 +365,10 @@ function openIssueForkRepo(formValues){ // THIS MUST BE ARRAY // We should decide if this is gonna be one person every time or multi. - // For now agahkarakuzu only. + // For now random member selected. // We can have a set of rules for this. - var nl_assignee = [response_file.payload.welcome_team[1]]; + var selected_member = getRandomInt(0, response_file.payload.welcome_team.length); + var nl_assignee = [selected_member]; body = body + "\n" + @@ -382,43 +383,40 @@ function openIssueForkRepo(formValues){ var forked = false; // init // FORK THE REPOSITORY + // This should be updated to fork to NeuroLibre once the workflow is finalized if (!inspection_results.status){ forked = forkRepo(formValues.REPO_OWNER,formValues.REPO_NAME,"roboneurotest"); - } - return {issue_details: issue_details, fork_status: forked}; } // ===================================================================== END - // --------------------------------------------------------------------- // LOCK CONVERSATION BY DEFAULT // ===================================================================== START -function lockGitHubIssue(issue_number){ - - // Lock issue, to be unlocked on GitHub. - // https://developer.github.com/v3/issues/#lock-an-issue - - var payload = { - "locked": true, - "active_lock_reason": "resolved" - } - - var options = { - "method": "PUT", - "contentType": "application/vnd.github.sailor-v-preview+json", - "payload": JSON.stringify(payload), - "headers" : { - Authorization: "token " + TOKEN - } - }; - - var response = UrlFetchApp.fetch("https://api.github.com/repos/"+HANDLE+"/"+REPO+"/issues/"+String(issue_number)+"/lock", options); - //Logger.log(response.getContentText()) - -} +// function lockGitHubIssue(issue_number){ + +// // Lock issue, to be unlocked on GitHub. +// // https://developer.github.com/v3/issues/#lock-an-issue + +// var payload = { +// "locked": true, +// "active_lock_reason": "resolved" +// } + +// var options = { +// "method": "PUT", +// "contentType": "application/vnd.github.sailor-v-preview+json", +// "payload": JSON.stringify(payload), +// "headers" : { +// Authorization: "token " + TOKEN +// } +// }; + +// var response = UrlFetchApp.fetch("https://api.github.com/repos/"+HANDLE+"/"+REPO+"/issues/"+String(issue_number)+"/lock", options); +// //Logger.log(response.getContentText()) +// } // ===================================================================== END // --------------------------------------------------------------------- @@ -426,27 +424,22 @@ function lockGitHubIssue(issue_number){ // ===================================================================== START function getGitHubInfo(repo_url){ -var answer = {"valid":false,"payload":null}; -var repo; -var response; - -repo = parseGithubUrl(repo_url); - - -response = UrlFetchApp.fetch("https://api.github.com/repos/" + repo.owner + "/" + repo.repo); - + var answer = {"valid": false, "payload": null}; + var repo; + var response; -if(response.getResponseCode() == 200) { - answer.valid = true; - answer.payload = JSON.parse(response); - } + repo = parseGithubUrl(repo_url); + response = UrlFetchApp.fetch("https://api.github.com/repos/" + repo.owner + "/" + repo.repo); + if(response.getResponseCode() == 200) { + answer.valid = true; + answer.payload = JSON.parse(response); + } return answer; } // ===================================================================== END - // --------------------------------------------------------------------- // CRAWL GITHUB REPO TREE // ===================================================================== START @@ -541,7 +534,6 @@ function sanityCheck(author_github, author_email, repo_url){ flag = false; msg = msg + "\n Provided GitHub repository (" + repo_url + ") does not exist."; }else{ - owner = response_repo.payload.owner.login; name = response_repo.payload.name; } @@ -579,10 +571,8 @@ return {valid: flag, repo_owner: owner, repo_name: name }; function getMailBodySuccess(formValues,response_object) { - // This functions returns an HTML mail body on a successful submission. // Mail content is populated by the information fetched from the spreadsheet. - var html_body= "" + header + @@ -642,7 +632,6 @@ function url_exists(url) { } function getCollapsibleMD(response_object,obj,blob_url){ - var items = []; if (obj.format instanceof Array && obj.format.length >1){ @@ -656,7 +645,6 @@ function getCollapsibleMD(response_object,obj,blob_url){ }else{ items = getFileArray(response_object, obj.format,obj.abs_match); - } if (items.length!=0){ @@ -707,15 +695,19 @@ function getFileArray(obj,extension,abs_match) { return file_info; } +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + function getFile(owner,repo,file,isjson,bypass){ // See GitHub API for call details: // https://docs.github.com/en/rest/reference/repos#get-repository-content -// TODO: FIX VARIABLE NAMING HERE - var answer = {"valid":true, "payload": null}; + var answer = {"valid": true, "payload": null}; var decoded; var response = UrlFetchApp.fetch("https://api.github.com/repos/" + owner + "/" + repo + "/contents/" + file); - //Logger.log("GETFILE" + response.getContentText()); if (response.getResponseCode() == 200){ @@ -723,20 +715,19 @@ function getFile(owner,repo,file,isjson,bypass){ if (!bypass){ decoded = Utilities.base64Decode(jsn.content); }else{ - // In case need to keep content untouched. + // In case we need to keep content untouched, don't decode decoded = jsn.content; } if (!bypass){ - if (isjson){ - answer.payload = JSON.parse(Utilities.newBlob(decoded).getDataAsString()); - }else{ - answer.payload = Utilities.newBlob(decoded).getDataAsString(); - } - }else{ // IF BYPASS - answer.payload = decoded; - } - + if (isjson){ + answer.payload = JSON.parse(Utilities.newBlob(decoded).getDataAsString()); + }else{ + answer.payload = Utilities.newBlob(decoded).getDataAsString(); + } + }else{ // IF BYPASS + answer.payload = decoded; + } }else{ // NOT RESPONSE 200 answer.valid = false; } @@ -762,8 +753,8 @@ function putFile(owner,repo,content,path, isjson, bypass){ var payload = { // TODO: Update this to roboneuro "message": msg, "committer": { - "name": "Agah Karakuzu", - "email": "agahkarakuzu@gmail.com" + "name": "Robo NeuroLibre", + "email": "roboneurolibre@gmail.com" }, "content": encoded }; @@ -777,7 +768,7 @@ function putFile(owner,repo,content,path, isjson, bypass){ } }; - var response = UrlFetchApp.fetch("https://api.github.com/repos/" + owner + "/" + repo + "/contents/" + path,options); + var response = UrlFetchApp.fetch("https://api.github.com/repos/" + owner + "/" + repo + "/contents/" + path, options); //Logger.log("PUTFILE" + response.getContentText()); var status = response.getResponseCode(); @@ -914,7 +905,9 @@ function syncFiles(org,origin_repo,target_repo,pub_type){ // Get some files from the template repo for github actions etc. var answer = {"valid":true, "payload": null}; var response; - var file_list = [{from: "actions/publish.yml", to: ".github/workflows/publish.yml"} + var file_list = [ + { from: "actions/publish.yml", to: ".github/workflows/publish.yml" }, + { from: "build-requirements.txt", to: "build-requirements.txt" } ]; if (pub_type == "Publication"){ file_list.push({from: "images/publication_template.png", to: target_repo + "_featured.png"}); @@ -959,23 +952,23 @@ function makeComment(issue_number,body){ return answer; } -function unlockIssue(issue_number){ -// DELETE /repos/:owner/:repo/issues/:issue_number/lock +// function unlockIssue(issue_number){ +// // DELETE /repos/:owner/:repo/issues/:issue_number/lock - var options = { - "method": "delete", - "contentType": "application/vnd.github.sailor-v-preview+json", - "headers" : { - Authorization: "token " + TOKEN - } - }; +// var options = { +// "method": "delete", +// "contentType": "application/vnd.github.sailor-v-preview+json", +// "headers" : { +// Authorization: "token " + TOKEN +// } +// }; - var response = UrlFetchApp.fetch("https://api.github.com/repos/"+HANDLE+"/"+REPO+"/issues/"+String(issue_number)+"/lock", options); - var answer; - response.getResponseCode()==204 ? answer = true : answer=false; +// var response = UrlFetchApp.fetch("https://api.github.com/repos/"+HANDLE+"/"+REPO+"/issues/"+String(issue_number)+"/lock", options); +// var answer; +// response.getResponseCode()==204 ? answer = true : answer=false; -return answer; -} +// return answer; +// } function getReviewerList(){ From dc7f33cc3226186292c64c6d19a51859250411c9 Mon Sep 17 00:00:00 2001 From: Elizabeth DuPre Date: Tue, 25 Aug 2020 17:12:53 -0400 Subject: [PATCH 3/6] Move to new JB build system --- actions/publish.yml | 77 ++++++++++++++++++++++++++++-------------- build-requirements.txt | 2 ++ 2 files changed, 53 insertions(+), 26 deletions(-) create mode 100644 build-requirements.txt diff --git a/actions/publish.yml b/actions/publish.yml index 484cc0d..5dff563 100755 --- a/actions/publish.yml +++ b/actions/publish.yml @@ -1,51 +1,76 @@ -name: Publish to neurolibre.com +name: deploy-book + on: push: + branches: + - master + # If your git repository has the Jupyter Book within some-subfolder next to + # unrelated files, you can make this run only if a file within that specific + # folder has been modified. + # + # paths: + # - content/** tags: - - "pub-v*" + - "v*" env: PUB_NAME: ${{ github.event.repository.name }} jobs: - dispatch2Website: + + deploy-book: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + # Install dependencies + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + + - name: Install dependencies + run: | + pip install -r build-requirements.txt + + # Build the page + - name: Build the book + run: | + jupyter-book build content/ + + # Push the book's HTML to github-pages + - name: GitHub Pages action + uses: peaceiris/actions-gh-pages@v3.6.1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./content/_build/html + commit_message: 🤖 Deploy Jupyter Book + + publish: + + name: Publish to website + needs: [deploy-book] + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') runs-on: ubuntu-latest steps: - name: Checkout publication repository uses: actions/checkout@v2 - - name: Convert yaml to json (publication info) + + - name: Convert yaml to json (publication info) uses: fabasoad/yaml-json-xml-converter-action@v1.0.0 id: yaml2json with: path: '${{ env.PUB_NAME }}.yml' from: 'yaml' to: 'json' + - name: Resolve release tag run: | echo ::set-env name=PUB_TAG::$(echo ${GITHUB_REF/refs\/tags\//}) - - name: Dispatch event to neurolibre.com + + - name: Dispatch event to neurolibre.com uses: peter-evans/repository-dispatch@v1 with: token: ${{ secrets.PAT }} event-type: publish repository: roboneurotest/website-test - client-payload: '{"pub_info": ${{ steps.yaml2json.outputs.data }}, "pub_name": "${{ env.PUB_NAME }}", "pub_tag": "${{ env.PUB_TAG }}"}' - buildJupyterBook: - runs-on: ubuntu-latest - steps: - - name: Chekout repo - uses: actions/checkout@v2 - - name: Build site HTML - run: | - docker pull agahkarakuzu/jbuild - mkdir _site - chmod 777 -R ./_site - docker run --rm --security-opt label:disable \ - -v ${{ github.workspace }}:/srv/jekyll \ - agahkarakuzu/jbuild - rsync -a $GITHUB_WORKSPACE/_site/ $GITHUB_WORKSPACE/ - - name: Deploy - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.PAT }} - publish_dir: ./ - commit_message: 🤖 Deploy Jupyter Book + client-payload: '{"pub_info": ${{ steps.yaml2json.outputs.data }}, "pub_name": "${{ env.PUB_NAME }}", "pub_tag": "${{ env.PUB_TAG }}"}' \ No newline at end of file diff --git a/build-requirements.txt b/build-requirements.txt new file mode 100644 index 0000000..db03a44 --- /dev/null +++ b/build-requirements.txt @@ -0,0 +1,2 @@ +jupyter-book +jupytext[myst] From 5138ade0459296dabfcffaf606fd1b3436d6dddf Mon Sep 17 00:00:00 2001 From: Elizabeth DuPre Date: Tue, 25 Aug 2020 17:13:22 -0400 Subject: [PATCH 4/6] Tweak editorial for style, testing purposes --- editorial/allowed_list.json | 3 ++- editorial/neurolibre_roles.json | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/editorial/allowed_list.json b/editorial/allowed_list.json index ac781a7..e30c9a9 100644 --- a/editorial/allowed_list.json +++ b/editorial/allowed_list.json @@ -1,6 +1,7 @@ { "allowed": [ "mathieuboudreau", - "TommyBoshkovski" + "TommyBoshkovski", + "emdupre" ] } \ No newline at end of file diff --git a/editorial/neurolibre_roles.json b/editorial/neurolibre_roles.json index fb0d543..81dfe2d 100644 --- a/editorial/neurolibre_roles.json +++ b/editorial/neurolibre_roles.json @@ -1,13 +1,13 @@ { "welcome_team": ["mathieuboudreau", - "agahkarakuzu", - "ltetrel", - "pbellec" + "agahkarakuzu", + "ltetrel", + "pbellec" ], "reviewers": [{"handle":"agahkarakuzu","expertise":["qmri","software"],"affiliation":"NeuroPoly Lab, Polytechnique Montreal"}, {"handle":"mathieuboudreau","expertise":["qmri","software"],"affiliation":"Montreal Heart Institute"}, {"handle":"emdupre","expertise":["fmri","software"],"affiliation":"Montreal Neurological Institute, McGill"}, {"handle":"ltetrel","expertise":["software"],"affiliation":"SIMEXP Lab, University of Montreal"}, - {"handle":"pbellec","expertise":["software","neuroimaging"],"affiliation":"SIMEXP Lab, University of Montreal"} - ] + {"handle":"pbellec","expertise":["software","neuroimaging"],"affiliation":"SIMEXP Lab, University of Montreal"} + ] } From 291a3c46b439c583b23b76fa5bbbea3037584945 Mon Sep 17 00:00:00 2001 From: Elizabeth DuPre Date: Tue, 25 Aug 2020 17:45:05 -0400 Subject: [PATCH 5/6] Move out file types to JSON, prep for new checks --- file-types.json | 77 ++++++++++++++++++++++++++++++++++ integration/google/onSubmit.gs | 58 ++++--------------------- 2 files changed, 84 insertions(+), 51 deletions(-) create mode 100644 file-types.json diff --git a/file-types.json b/file-types.json new file mode 100644 index 0000000..d5cb788 --- /dev/null +++ b/file-types.json @@ -0,0 +1,77 @@ +{ + "Jupyter Notebook": { + "format": ".ipynb", + "icon": "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/i/de920fda-40bd-43e8-9ed3-339bb970c3c4/dd8pdzs-cbc64bcd-86d9-4e22-a415-820e63c4e959.png", + "icon_size": 30, + "plural": "s", + "abs_match": false + }, + "Dockerfile": { + "format": "Dockerfile", + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/97_Docker_logo_logos-512.png", + "icon_size": 30, + "plural": "s", + "abs_match": false + }, + "JupyterBook config file": { + "format": [ + "_config.yml", + "toc.yml", + "_data/toc.yml" + ], + "icon": "https://jupyterbook.org/_static/logo.png", + "icon_size": 30, + "plural": "s", + "abs_match": true + }, + "Pip Requirements": { + "format": "requirements.txt", + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-512.png", + "icon_size": 30, + "plural": "", + "abs_match": true + }, + "Other config file": { + "format": [ + "environment.yml", + "Pipfile", + "Pipfile.lock", + "setup.py", + "Project.toml", + "REQUIRE", + "install.R", + "apt.txt", + "DESCRIPTION", + "manifest.yml", + "postBuild", + "start", + "runtime.txt", + "default.nix" + ], + "icon": "https://avatars3.githubusercontent.com/u/13699731?s=280&v=4", + "icon_size": 30, + "plural": "s", + "abs_match": true + }, + "Readme": { + "format": "README.md", + "icon": "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/273_Readme_logo-512.png", + "icon_size": 30, + "plural": "", + "abs_match": true + }, + "License": { + "format": "LICENSE", + "icon": "https://cdn0.iconfinder.com/data/icons/customicondesign-office7-shadow-png/256/License-manager.png", + "icon_size": 30, + "plural": "", + "abs_match": true + }, + "Repo2Data": { + "format": "data_requirement.json", + "icon": "https://cdn4.iconfinder.com/data/icons/cloud-computing-2/500/cloud-arrow-down-512.png", + "icon_size": 30, + "plural": "", + "abs_match": true + } +} \ No newline at end of file diff --git a/integration/google/onSubmit.gs b/integration/google/onSubmit.gs index 84213e2..4b0453f 100644 --- a/integration/google/onSubmit.gs +++ b/integration/google/onSubmit.gs @@ -45,7 +45,7 @@ // ii - Global variables declared by the script follow camelCase. These variables // are intended for easing access to the auxiliary information. List of global // variable declared by this script are: -// - mapVal, icon*, logo*, header*, footer*, inspectObject, binderConfig +// - mapVal, icon*, logo*, header*, footer* // // iii - Global variables specifying GitHub repository to which authorized // API calls will point (e.g. neurolibre/submit) are CAPITALIZED. @@ -100,64 +100,17 @@ var mapVal = { // --------------------------------------------------------------------- // Global vars for icons and images // ##################################################################### START -var iconBinder = "https://avatars3.githubusercontent.com/u/13699731?s=280&v=4"; -var iconJpbook = "https://jupyterbook.org/_static/logo.png"; -var iconPython = "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/267_Python_logo-512.png"; -var iconNotebook = "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/i/de920fda-40bd-43e8-9ed3-339bb970c3c4/dd8pdzs-cbc64bcd-86d9-4e22-a415-820e63c4e959.png"; var iconGithub = "https://cdn2.iconfinder.com/data/icons/black-white-social-media/64/github_social_media_logo-512.png"; -var iconLicense = "https://cdn0.iconfinder.com/data/icons/customicondesign-office7-shadow-png/256/License-manager.png"; -var iconReadme = "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/273_Readme_logo-512.png"; var iconTwitter = "https://cdn2.iconfinder.com/data/icons/black-white-social-media/32/online_social_media_twitter-512.png"; var iconDev = "https://cdn1.iconfinder.com/data/icons/badges-achievements-001-solid/68/Artboard_8-512.png"; var iconWebsite = "https://cdn3.iconfinder.com/data/icons/black-white-social-media/32/www_logo_social_media-512.png"; -var iconData = "https://cdn4.iconfinder.com/data/icons/cloud-computing-2/500/cloud-arrow-down-512.png"; var logoNeurolibreOutline = "https://github.com/neurolibre/neurolibre.com/blob/master/static/img/favicon.png?raw=true"; var logoNeurolibre = "https://raw.githubusercontent.com/neurolibre/docs.neurolibre.com/master/source/img/logo_neurolibre_old.png"; -var iconDocker = "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/97_Docker_logo_logos-512.png"; var footerPublication = "https://github.com/roboneurotest/submit/blob/master/images/publication_footer.png?raw=true"; var iconReview = "https://cdn0.iconfinder.com/data/icons/job-seeker/256/conversation_job_seeker_employee_unemployee_work-512.png"; var footerTutorial = "https://github.com/roboneurotest/submit/blob/master/images/tutorial_footer.png?raw=true"; // ##################################################################### END - -// Global vars for repo inspection -// ##################################################################### START - -// TODO: PUT THIS SECTION AS A JSON TO THE BASE OF THE SUBMIT REPO. - -var binderConfig = [ - "environment.yml", - "Pipfile", - "Pipfile.lock", - "setup.py", - "Project.toml", - "REQUIRE", - "install.R", - "apt.txt", - "DESCRIPTION", - "manifest.yml", - "postBuild", - "start", - "runtime.txt", - "default.nix" - ]; - -var inspectObject = { - "files": [ - { "name":"Jupyter Notebook","format":".ipynb","icon":iconNotebook, "icon_size":30,"plural":"s", abs_match:false}, - { "name":"Dockerfile","format":"Dockerfile","icon":iconDocker, "icon_size":30, "plural":"s", abs_match:false}, - { "name":"JupyterBook config file","format":["_config.yml","toc.yml","_data/toc.yml"], "icon":iconJpbook, "icon_size":30, "plural":"s",abs_match:true}, - { "name":"Pip Requirements","format":"requirements.txt", "icon":iconPython, "icon_size":30, "plural":"", abs_match:true}, - { "name":"Other config file","format": binderConfig, "icon":iconBinder, "icon_size":30, "plural":"s", abs_match:true}, - { "name":"Readme","format": "README.md", "icon":iconReadme, "icon_size":30, "plural":"", abs_match:true}, - { "name":"License","format": "LICENSE", "icon":iconLicense, "icon_size":30, "plural":"", abs_match:true}, - { "name":"Repo2Data","format": "data_requirement.json", "icon":iconData, "icon_size":30, "plural":"", abs_match:true}, - ] - -}; -// ##################################################################### END - - // --------------------------------------------------------------------- // Global vars for HTML template // ##################################################################### START @@ -457,11 +410,14 @@ function inspectGitHubRepo(formValues){ var cur_o; // Current object var flag = false; - for (var i =0; i < inspectObject.files.length;i++){ - cur_f = inspectObject.files[i]; + var response = {}; + response = getFile(HANDLE, REPO, "file-types.json", true, false); + + for (var key in response.payload){ + cur_f = key; cur_o = getCollapsibleMD(response_object,cur_f,blob_url); content_info += cur_o; - if (String(inspectObject.files[i].name) === "Jupyter Notebook" && cur_o == "") flag=true; + if (String(key.name) === "Jupyter Notebook" && cur_o == "") flag=true; } response = UrlFetchApp.fetch("https://api.github.com/repos/"+ formValues.REPO_OWNER +"/"+ formValues.REPO_NAME +"/contributors"); From d0199178910980b0df688f93663f2c6339cdc0af Mon Sep 17 00:00:00 2001 From: Elizabeth DuPre Date: Tue, 25 Aug 2020 18:18:24 -0400 Subject: [PATCH 6/6] Update to include author's requirements --- build-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/build-requirements.txt b/build-requirements.txt index db03a44..99b648f 100644 --- a/build-requirements.txt +++ b/build-requirements.txt @@ -1,2 +1,3 @@ +-r requirements.txt jupyter-book jupytext[myst]