Giter Site home page Giter Site logo

node-google-apps-script's Introduction


โš ๏ธ๐Ÿšจ DEPRECATION NOTICE ๐Ÿšจโš ๏ธ

Google has released clasp, please use it instead.

As per the discussion in issue #86, it does not make sense for these two projects to co-exist. This project is locked into it's final version and will receive no future updates.

Happy scripting!


gapps (Google Apps Script)

The easiest way to develop Google Apps Script projects

Using gapps, you can develop your Apps Script locally and push files to the Apps Script servers. This allows you to use any editor of your choice, version control, and other modern webdev patterns in to Apps Script development.

Requirements

  • node >= 8
  • npm install -g node-google-apps-script

Quickstart

1. Get Google Drive Credentials

To use gapps you need access to your files on your Google Drive through the API provided by Google. To make this happen you have to create a Developer Console Project.

You can do this one of two ways:

  1. Use the existing 'API Project' in the Developer Console
  2. Create an independent Developer Console Project (choose this when the default project is not available)

1.1 Use the existing 'API Project' in the Developer Console

This is the easiest approach because you don't need to create a new project. You will use the default Developer Console Project API Project, enable Google Drive and get credentials.

  1. While working in the editor on script.google.com select Resources > Cloud Platform Project... otherwise, go to the Google Cloud Platform
  2. Access the automatically created Google Apps Script Project API Project: click on the blue button at the top and select (API Project - api-project-##########) from the list.
  3. Enable the Google Drive API
    1. Click APIs & services in the left nav and then select Library
    2. Search for Drive and select the Google Drive API listing.
    3. Click Enable API
  4. Acquire Google Drive Client Secret Credentials
    1. If you just enabled the Drive API, hit Create Credentials, otherwise , go to Credentials in the left menu, select Create credentials and choose OAuth client ID
    2. Select your email address from the dropdown OAuth consent screen and assign your add-on a Project Name i.e. My API access project. This can always be changed later.
    3. In the menu that appears, choose Other for the Application type.
    4. Give it any name you like (i.e. Macbook) and click Create.
    5. Finally, download your credentials using the Download as JSON button to the right. Save these credentials to a location of your choosing; ~/Downloads is fine.
    6. You may close the Developer Console window.

1.2 Create an independent Developer Console Project

Use an independent Developer Console Project if the default API Project is deleted, in use or if you want to keep permissions separated.

  1. Create a new Dev Console Project
    1. Use this link to create the project. It will auto-activate the Google Drive API. If you have multiple Google Accounts, append &authuser=1 to the end of the url to choose which account to login with. Note that authuser is zero-indexed.
    2. Make sure Create a New Project is selected and hit Continue.
    3. Once the project has been created, click Go to Credentials.
  2. Acquire Google Drive Client Secret Credentials
    1. Click client-ID in the grey paragraph
    2. Select your email address from the dropdown OAuth consent screen and assign your add-on a Project Name i.e. My API access project. This can always be changed later.
    3. In the menu that appears, choose Other for the Application type.
    4. Give it any name you like (i.e. Macbook) and click Create.
    5. Finally, download your credentials using the Download as JSON button to the right. Save these credentials to a location of your choosing; ~/Downloads is fine.
    6. You may close the Developer Console window.

To return to this project later, select Resources > Developer Console Project while editing your script. Then click the link at the top of the dialog to open the Developer Console with this project selected.

2. Authenticate gapps

This process will set up Google Drive authentication to allow uploading and importing of the Apps Script project.

  1. Run gapps auth path/to/client_secret_abcd.json i.e. gapps auth ~/Downloads/client_secret_1234567890-abcd.apps.googleusercontent.com.json
  2. Follow the directions by clicking on the link generated by the script.
  3. After you're successfully authenticated, feel free to delete the client_secret.json credentials file.

You can pass the option --no-launch-browser to generate a url that will give you a code to paste back into the console. This is useful if you're using ssh to develop.

3. Initialize your project

This proces will create gapps.config.json and a sub-directory where all Apps Script project files will be downloaded to. You can either use an existing project or create a new one.

3.1 An existing Apps Script project

  1. Navigate to your Apps Script project from Google Drive (must be a standalone script)
  2. Get your project ID from the address bar, located after /d/ and before /edit i.e. '//script.google.com/a/google.com/d/abc123-xyz098/edit?usp=drive_web'
  3. Navigate to a directory where your Apps Script project will live
  4. Run gapps init <fileId> within your project directory i.e. gapps init abc123-xyz098

3.2 A new Apps Script project

  1. Head to https://script.google.com and create a new blank project.
  2. Save the mostly empty project and give it a name. Saving is important; the project is not in your Google Drive until it is saved.
  3. Get your project ID from the address bar, located after /d/ and before /edit i.e. '//script.google.com/a/google.com/d/abc123-xyz098/edit?usp=drive_web'
  4. Navigate to a directory where your Apps Script project will live
  5. Run gapps init <fileId> within your project directory i.e. example, gapps init abc123-xyz098

4. Develop locally

Start scripting and enjoy total freedom of your local dev environment and source control options! Create script files with a .gs or .js extension and html files with a .html extension

5. Upload New Files

Run gapps upload from within your project directory. You should then be able to reload your Apps Script project in the browser and see the changes.

Best Practices

Check out Matt Hessinger's blog post: Advanced development process with apps

Docs

gapps auth

  Usage: gapps auth [options] <path/to/client/secret.json>

  Authorize gapps to use the Google Drive API

  Options:

    -b, --no-launch-browser  Do not use a local webserver to capture oauth code
                              and instead require copy/paste of key returned in
                              the browser after authorization completes.
    -p, --port [port]        Port to use for webserver

Performs the authentication flow described in the quickstart above.

gapps init

  Usage: gapps init|clone <fileId> [options]

  Initialize project locally. The external Apps Script project must exist.

  Options:
    -k, --key [key]
    -s, --subdir [subdir]
    -o, --overwrite

Creates gapps.config.json, which contains information about your Apps Script project and downloads all project files into a subdirectory (default: src/)

gapps upload

  Usage: gapps upload|push

  Upload back to Google Drive. Run from root of project directory

Upload the project to Google Drive. Sources files from ./src or the configured subdirectory.

gapps oauth-callback-url

  Usage: gapps deployment oauth-callback-url

  Get the OAuth Callback URL for a project

Returns the OAuth Callback URL required by most 3rd-party OAuth services.

Development

Please submit any bugs to the Issues page. Pull Requests also welcome.

If you want to develop, clone down the repo and have at it! You can run npm link from the root directory of the repo to symlink to your local copy. You'll have to uninstall the production version first npm uninstall -g node-google-apps-script.

Limitations

gapps allows you to nest files in folders, but the Apps Script platform expects a flat file structure. Because of this, no files can have the same name, even if they are in separate directories. One file will overwrite the other, making debugging difficult.

Your add-on must be developed as a standalone script and tested within Doc or Sheet. This means that it cannot use certain functions of bound scripts, namely installable triggers. While testing within a Doc, you have access to the "Special methods" mentioned in the docs, though. If you followed the quickstart above, you should be set up correctly.

Common Issues

The Google Drive API frequently returns a 400 error without a helpful error message. Common causes for this are:

  • javascript formatting errors
    • The server-side javascript code (.js or .gs) is validated upon upload.
    • If there is a syntax error, the upload will fail.
  • The project does not exist yet.
    • Verify that the project exists in your Google Drive folder.
    • If you have been added to an existing project, verify that the owner has shared the file with you with the "can edit" permission.
  • Missing server-side libraries
    • verify that any required Libraries (frequently Underscore or OAuth2) have been added to the Apps Script project
  • Authentication error
    • Verify that ~/.gapps exists and has 4 values: client_id, client_secret, redirect_uri, and refresh_token
    • To reset authentication, 'rm ~/.gapps' and then perform the authentication steps in part #2 of the quickstart again.

Acknowledgements

Huge thanks to Shrugs for a massive PR that bumped this project to v1.0

Extra Resources

node-google-apps-script's People

Contributors

aduston avatar aledlewis avatar alexisgo avatar cwarden avatar danthareja avatar hess-g avatar jceelen avatar lricoy avatar sheetsaddons1 avatar shrugs avatar stvhwrd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-google-apps-script's Issues

gaps download invalid_string should return an error

I accidentally copied an incorrect ID, and it executed seemingly successful, but there was no files. It took me some time to figure out what was the cause. If the script returned an error, I'd know it immediately.

Initializing git repo causes gaps upload error

Hi there,

I successfully ran gaps download and gaps upload on an existing project, then tried to gaps upload after initializing my local git repo. It's now throwing an "Unsupported file type found" error. I think it's because of the .git file, which is the only file that isn't .js or .html.

Am I missing something? I will try putting the directory in a parent and initialize that as a repo..

Is there a way to automate `Publish>Deploy as API executable...`

Currently when working on REST script execution targets, after running gulp upload-latest --env dev I have to go to the script project in a browser and run Publish>Deploy as API executable..., and name the version.

Is there any way to automate this as part of pushing the code up?

Can no longer 'download' files

It seems like you've removed the ability to pull files down from the Apps Script project to a local directory. You used to have a download terminal command, which is no longer working for me. Is this still possible?

Note on multiple Google logins

I use multiple Google logins, for personal & work. When I clicked the link in Step 1:

Create a new project in the Google Developer Console for this tool to access your Google drive. Using this link guides you through the process and activates the Drive API automatically.

It began configuring access for one of my accounts, but not the one I needed. This became clear later on when choosing my email address from the dropdown (3 sub-bullets later).

I was able to get around this issue by appending &authuser=1 (it's 0-indexed) as an extra parameter to the link from the instructions, like so:

https://console.developers.google.com/start/api?id=drive&credential=client_key&authuser=1

Putting this here in case others run into the same issue. ๐Ÿ˜„

"Bad request" issue when uploading: Use of reserved words as object properties

In node, the following js does not result in any errors:

obj = {};
obj.const = {};
obj = {};
obj.function = {};

However, in App Script it does. Line 2 in both examples would generate error "Missing name after . operator" in apps script online editor. Nor is this detected in any linters. Unexpected consequence is that we get "Bad Error" when attempting to upload.

Documenting for reference; the problem really isn't with this package. Hopefully documenting here may save hours of head-scratching.

Downloading container bound projects

Hi,

I know about the limitation specified in the documentation regarding container bound "scripts" (not projects) https://developers.google.com/apps-script/import-export, but actually the download of the project files of an cotainer bound project is actually working.

The current implementation fails to fetch the project files of such a project because the getProjectTitle() method from download.js fails to find the flle with the id equal to the project id. But ignoring this error (e.g. considering a static or argument-passed project name) would cause the download of the files to work.

function getProjectTitle(fileId, auth) {
var deferred = Q.defer();
var drive = google.drive({ version: 'v2', auth: auth });
drive.files.get({ fileId: fileId }, function(err, res) {
//if (err) return deferred.reject('Error getting project');
title = null;
if(err) {
title = "project";
} else {
title = res.title;
}

console.log('Cloning into \'' + title + '\'...');
deferred.resolve(title);

});
return deferred.promise;
}

Furthermore I don't think it should impact the upload functionality, which btw I could not get working so far.

Thanks,
Ado

"Google Drive returned a fatal error" when running upload

I'm not able to run the upload for my project. I successfully pulled down an existing (and working) project via gapps init, and when I immediately try to run the upload without changing any files I get the following error:

Google Drive returned a fatal error.
Error running upload command

My .gapps file looks correct, I have all necessary libraries added to the project, and running eslint on the project doesn't show any syntax errors.

Trouble with gapps auth

Hi! sorry cause I'm real beginner with node, npm and so on
I tried to auth a project both on Windows and Mac. On windows no problem, on mac instead I have a command not found when I launch gapps auth ~/Downloads/client_secret.json, I tried also with sudo but nothing to do I always obtain -bash: gapps: command not found
Could you help me please ?

Internal Error when push

$ gapps push
Pushing back up to Google Drive...
An error occured while running upload command: Internal Error
Upload failed.

Is it possible to know what is the internal error?

gapps init causes syntax error if response body is not JSON

I got a syntax error from the command gapps init 123...xyz (with "123...xyz" substituted by my real project ID). Here's the error:

[jack@mycomputer myproject]$ gapps init 123...xyz
Error parsing project files
Script file ID not found. Please input an ID and try again.
Error running init command
Unhandled rejection SyntaxError: Unexpected token <
    at Object.parse (native)
    at /usr/lib/node_modules/node-google-apps-script/lib/manifestor.js:79:19
    at tryCatcher (/usr/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/util.js:26:23)
    at Promise._settlePromiseFromHandler (/usr/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/promise.js:505:31)
    at Promise._settlePromiseAt (/usr/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/promise.js:581:18)
    at Promise._settlePromises (/usr/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/promise.js:697:14)
    at Async._drainQueue (/usr/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/async.js:123:16)
    at Async._drainQueues (/usr/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/async.js:133:10)
    at Immediate.Async.drainQueues [as _onImmediate] (/usr/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/async.js:15:14)
    at processImmediate [as _immediateCallback] (timers.js:383:17)

After some digging, I found that JSON.parse in line 79 of manifestor.js was expecting JSON but actually received an HTML page. The HTML page was one saying "You need permission ... Want in? Ask the owner for access, or switch to an account with permission." I think I may have made a mistake when getting my credentials in the Google Developer Console, hence the authentication error.

It would be nice to handle this more elegantly, as the error message is pretty confusing - it makes it seem like the error is something to do with the project ID itself, when it is actually an authentication problem.

Error code 400 when pushing

I'have successfully cloned, added files and pushed them. Now when I try to update existing files i get this:

Pushing /home/fredrik/src/CRM-Data back up to Google Drive...
Error running upload command { [Error: Bad Request]
  code: 400,
  errors: 
   [ { domain: 'global',
       reason: 'badRequest',
       message: 'Bad Request' } ] }

Just ask if you need more information.

Fredrik

Installation fails with yarn global

I ran yarn global add node-google-apps-script
and got in return

yarn global v1.1.0
[1/4] ๐Ÿ”  Resolving packages...
warning [email protected]: Use uuid module instead
warning [email protected]: Use uuid module instead
warning [email protected]: ReDoS vulnerability parsing Set-Cookie https://nodesecurity.io/advisories/130
[2/4] ๐Ÿšš  Fetching packages...
[3/4] ๐Ÿ”—  Linking dependencies...
warning "[email protected]" has unmet peer dependency "coffee-script@>=1.6.2 <2".
[4/4] ๐Ÿ“ƒ  Building fresh packages...
[-/3] โ  waiting...
[2/3] โ  v8-debug: Failed to execute '/Users/aymericbouzy/.nvm/versions/node/v8.6.0/bin/node /Users/aymericbouzy/.config/yarn/global/node_modules/node-gyp/bin/node-gyp.js bu
[3/3] โ  v8-profiler: CXX(target) Release/obj.target/profiler/src/profiler.o
[-/3] โ  waiting...
error /Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug: Command failed.
Exit code: 1
Command: node-pre-gyp install --fallback-to-build
Arguments: 
Directory: /Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug
Output:
node-pre-gyp info it worked if it ends with ok
node-pre-gyp info using [email protected]
node-pre-gyp info using [email protected] | darwin | x64
node-pre-gyp info check checked for "/Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug/build/debug/v1.0.1/node-v57-darwin-x64/debug.node" (not found)
node-pre-gyp http GET https://node-inspector.s3.amazonaws.com/debug/v1.0.1/node-v57-darwin-x64.tar.gz
node-pre-gyp http 404 https://node-inspector.s3.amazonaws.com/debug/v1.0.1/node-v57-darwin-x64.tar.gz
node-pre-gyp ERR! Tried to download(404): https://node-inspector.s3.amazonaws.com/debug/v1.0.1/node-v57-darwin-x64.tar.gz 
node-pre-gyp ERR! Pre-built binaries not found for [email protected] and [email protected] (node-v57 ABI) (falling back to source compile with node-gyp) 
node-pre-gyp http 404 status code downloading tarball https://node-inspector.s3.amazonaws.com/debug/v1.0.1/node-v57-darwin-x64.tar.gz 
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | x64
gyp info ok 
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | x64
gyp WARN download NVM_NODEJS_ORG_MIRROR is deprecated and will be removed in node-gyp v4, please use NODEJS_ORG_MIRROR
gyp WARN download NVM_NODEJS_ORG_MIRROR is deprecated and will be removed in node-gyp v4, please use NODEJS_ORG_MIRROR
gyp info spawn /usr/local/bin/python2
gyp info spawn args [ '/Users/aymericbouzy/.config/yarn/global/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args   '/Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/Users/aymericbouzy/.config/yarn/global/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/Users/aymericbouzy/.node-gyp/8.6.0/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/Users/aymericbouzy/.node-gyp/8.6.0',
gyp info spawn args   '-Dnode_gyp_dir=/Users/aymericbouzy/.config/yarn/global/node_modules/node-gyp',
gyp info spawn args   '-Dnode_lib_file=/Users/aymericbouzy/.node-gyp/8.6.0/<(target_arch)/node.lib',
gyp info spawn args   '-Dmodule_root_dir=/Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.' ]
gyp info ok 
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | x64
gyp WARN download NVM_NODEJS_ORG_MIRROR is deprecated and will be removed in node-gyp v4, please use NODEJS_ORG_MIRROR
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
  CXX(target) Release/obj.target/debug/src/debug.o
../src/debug.cc:41:20: warning: 'Call' is deprecated [-Wdeprecated-declarations]
        v8::Debug::Call(context, fn);
                   ^
/Users/aymericbouzy/.node-gyp/8.6.0/include/node/v8-debug.h:193:42: note: 'Call' has been explicitly marked deprecated here
                static MaybeLocal<Value> Call(
                                         ^
../src/debug.cc:52:45: warning: 'GetDebugContext' is deprecated [-Wdeprecated-declarations]
        Isolate* debug_isolate = v8::Debug::GetDebugContext(Isolate::GetCurrent())->GetIsolate();
                                            ^
/Users/aymericbouzy/.node-gyp/8.6.0/include/node/v8-debug.h:209:39: note: 'GetDebugContext' has been explicitly marked deprecated here
                static Local<Context> GetDebugContext(Isolate* isolate));
                                      ^
../src/debug.cc:57:20: warning: 'SendCommand' is deprecated [-Wdeprecated-declarations]
        v8::Debug::SendCommand(debug_isolate, *command, command.length());
                   ^
/Users/aymericbouzy/.node-gyp/8.6.0/include/node/v8-debug.h:170:29: note: 'SendCommand' has been explicitly marked deprecated here
                static void SendCommand(Isolate* isolate,
                            ^
../src/debug.cc:71:51: warning: 'GetDebugContext' is deprecated [-Wdeprecated-declarations]
        Local<Context> debug_context = v8::Debug::GetDebugContext(Isolate::GetCurrent());
                                                  ^
/Users/aymericbouzy/.node-gyp/8.6.0/include/node/v8-debug.h:209:39: note: 'GetDebugContext' has been explicitly marked deprecated here
                static Local<Context> GetDebugContext(Isolate* isolate));
                                      ^
../src/debug.cc:78:22: error: no member named 'GetMirror' in 'v8::Debug'
          v8::Debug::GetMirror(info.GetIsolate()->GetCurrentContext(), info[0]);
          ~~~~~~~~~~~^
../src/debug.cc:80:38: warning: 'GetDebugContext' is deprecated [-Wdeprecated-declarations]
          debug_context = v8::Debug::GetDebugContext(Isolate::GetCurrent());
                                     ^
/Users/aymericbouzy/.node-gyp/8.6.0/include/node/v8-debug.h:209:39: note: 'GetDebugContext' has been explicitly marked deprecated here
                static Local<Context> GetDebugContext(Isolate* isolate));
                                      ^
5 warnings and 1 error generated.
make: *** [Release/obj.target/debug/src/debug.o] Error 1
gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/Users/aymericbouzy/.config/yarn/global/node_modules/node-gyp/lib/build.js:258:23)
gyp ERR! stack     at emitTwo (events.js:125:13)
gyp ERR! stack     at ChildProcess.emit (events.js:213:7)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
gyp ERR! System Darwin 16.7.0
gyp ERR! command "/Users/aymericbouzy/.nvm/versions/node/v8.6.0/bin/node" "/Users/aymericbouzy/.config/yarn/global/node_modules/node-gyp/bin/node-gyp.js" "build" "--fallback-to-build" "--module=/Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug/build/debug/v1.0.1/node-v57-darwin-x64/debug.node" "--module_name=debug" "--module_path=/Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug/build/debug/v1.0.1/node-v57-darwin-x64"
gyp ERR! cwd /Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug
gyp ERR! node -v v8.6.0
gyp ERR! node-gyp -v v3.6.2
gyp ERR! not ok 
node-pre-gyp ERR! build error 
node-pre-gyp ERR! stack Error: Failed to execute '/Users/aymericbouzy/.nvm/versions/node/v8.6.0/bin/node /Users/aymericbouzy/.config/yarn/global/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug/build/debug/v1.0.1/node-v57-darwin-x64/debug.node --module_name=debug --module_path=/Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug/build/debug/v1.0.1/node-v57-darwin-x64' (1)
node-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/Users/aymericbouzy/.config/yarn/global/node_modules/node-pre-gyp/lib/util/compile.js:83:29)
node-pre-gyp ERR! stack     at emitTwo (events.js:125:13)
node-pre-gyp ERR! stack     at ChildProcess.emit (events.js:213:7)
node-pre-gyp ERR! stack     at maybeClose (internal/child_process.js:927:16)
node-pre-gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
node-pre-gyp ERR! System Darwin 16.7.0
node-pre-gyp ERR! command "/Users/aymericbouzy/.nvm/versions/node/v8.6.0/bin/node" "/Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /Users/aymericbouzy/.config/yarn/global/node_modules/v8-debug
node-pre-gyp ERR! node -v v8.6.0
node-pre-gyp ERR! node-pre-gyp -v v0.6.38
node-pre-gyp ERR! not ok 

Change path to credentials file

Hi!

  • How to change path to credentials file?
  • Is there the best way to override defaults.STORAGE_FILE there ?

I work with local installations. I can not use the% USERPATH%.

Your apps is great & helpful. Thanks.

gapps init throws error if there is .json manifest file in the project

Because of Gmail add-ons project has appsmanifest.json file I faced with the following issue:

  1. Create an empty Gmail add-ons project.
  2. Click View -> Show manifest file
  3. execute gapps init 'project_id'
  4. See an error:
    Error running init command Unhandled rejection Error: Unsupported file type found at Object.getFileExtension (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/lib/util.js:60:9) at writeExternalFile (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/lib/commands/init.js:48:35) at /home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/lib/commands/init.js:39:14 at tryCatcher (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/util.js:26:23) at MappingPromiseArray._promiseFulfilled (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/map.js:56:38) at MappingPromiseArray.init (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/promise_array.js:92:18) at Promise._settlePromiseAt (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/promise.js:582:21) at Promise._settlePromises (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/promise.js:700:14) at Async._drainQueue (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/async.js:123:16) at Async._drainQueues (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/async.js:133:10) at Immediate.Async.drainQueues [as _onImmediate] (/home/vitalybevzik/.nvm/versions/node/v5.12.0/lib/node_modules/node-google-apps-script/node_modules/bluebird/js/main/async.js:15:14) at tryOnImmediate (timers.js:534:15) at processImmediate [as _immediateCallback] (timers.js:514:5)

Upload project fails

I've been able to init and download, but upload fails. I've tried gaps upload both in my git project and in the subdirectory in it that has the GAS scripts. If I try in the git directory, I get:

Pushing /home/emile/github/DoCMS back up to Google Drive...
Error running upload command { [Error: ENOENT, open '/home/emile/github/DoCMS/.manifest.json']
  errno: 34,
  code: 'ENOENT',
  path: '/home/emile/github/DoCMS/.manifest.json' }

if I try in the GAS subdir created by the download action, I get

Pushing /home/emile/github/DoCMS/DoCMS back up to Google Drive...

/home/emile/github/DoCMS/node_modules/node-google-apps-script/lib/utils/manifestor.js:18
      file = path.parse(filename);
                  ^
TypeError: Object #<Object> has no method 'parse'
    at /home/emile/github/DoCMS/node_modules/node-google-apps-script/lib/utils/manifestor.js:18:19
    at /home/emile/github/DoCMS/node_modules/node-google-apps-script/node_modules/node-dir/lib/readfiles.js:99:34
    at fs.js:268:14
    at Object.oncomplete (fs.js:107:15)

How to run Google Apps Script projects on my local machine?

NEED:
The ability to run google scripts that is currently written for google spreadsheets but on my local machine rather than through the web interface.

EXPECTATION:
Using node-google-apps-script I can edit my scripts locally using Sublime text editor, test them locally and then push those online through Google script API integration.

PROBLEM:
The readme information is missing some steps for example.
When in google spreadsheets click on Tools > script editor
Once in Script editor click on Publish > Deploy as API executable...

These are not currently informations I can even read from your documentation...

Any help would be very helpful.

Project Needs Automated Test Framework

The project should have an automated test framework that gives at least basic coverage, if if it can't be perfect. This will both help reduce tedious manual testing and make it easier for new developers to contribute.

As a side note, introducing automated testing in projects not originally designed for it typically introduces major structural changes to accommodate the extra functionality needed to support automated testing.

Auto-completion

Hello,

I just wanted to know if there were a way to get an auto-completion system (for API methods etc.), as the one you can get on the online editor, when you develop on your local IDE or text editor.

Thank you.

Feature Brainstorm: support duplicate filenames when in separate directories

gapps allows you to nest files in folders, but the Apps Script platform expects a flat file structure. Because of this, no files can have the same name, even if they are in separate directories. One file will overwrite the other, making debugging difficult.

Here's my brainstorm of a solution to the enable duplicate filenames when in separate local directories:

Say we add a couple keys to gapps.config.json

  • "enable_dirs" : false, and
  • "seperator_placeholder" : "_"

then create a flag for the upload/push commands to collapse of the directory structure within /src:

-d, --enable-dirs=PLACEHOLDER - enables local diretory support by prefixing each 
        filename with its path once all instances of the value of path.separator() 
        has been converted using to the default placeholder "_" or PLACEHOLDER,  
        if supplied.

Now, let's suppose I have a gapps project:

my-gapps-project
โ”œโ”€โ”€ src/
โ”‚ย ย  โ”œโ”€โ”€ lib/
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ foo.js
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ utils.js
โ”‚ย ย  โ”œโ”€โ”€ foo.js
โ”‚ย ย  โ””โ”€โ”€ utils.js
โ””โ”€โ”€ gapps.config.json

With the new behavior, if I call

$ gapps upload -d

My project will upload as such:

my-gapps-project
โ”œโ”€โ”€ foo.gs
โ”œโ”€โ”€ lib_foo.gs
โ”œโ”€โ”€ lib_utils.gs
โ””โ”€โ”€ utils.gs

The same flag could be added to the init/clone commands to request the reciprocal effect--convert the default/specified PLACEHOLDER with path.separator(), then create files/folder accordingly.

Also, if a person wants to do this folder conversion at all, they probably want it done automatically, so --enable-dirs=PLACEHOLDER would update the gapps.config.json key "enable_dirs" to true and update "separator_placeholder" with PLACEHOLDER, if specified.

If we are going to have a sticky flag to enable diretory support, we should also have --disable-dirs to disable directory support which would essentially set "enable_dirs" to false.

I hope to submit a pull request once I spend the time to wrap my head around the code, but I figured I would see if anywone else is interested in this!

Thanks for all the hard work!

Lack of "download" Command

(Note: I believe that what I'm looking for here is not at all the same thing as #19, in particular because I'm looking for functionality that is not the same as the 'clone' command.)

Let me start by saying that I agree that, generally, the git repo should be the authoritative source of the code for a GAS project.

However, I'd like to be able to check that, when I have checked out what is supposed to be the released version of the source, the actual released version matches that. The first idea that comes to mind is to be able to run "gapps download", which would use the information from the gapps.config.json file to download the currently released copies of the project, and then a "git diff" would tell me my version is inconsistent and, if so, what those inconsistencies are.

I'm open to other ideas for how to do this, though.

A further extension of this would be the ability to download specific versions of the project as saved in "File / Manage Versions..." dialogue. However, I don't see any API that would let us do this, nor am I sure that the usefulness of this would justify more than very minimal expense.

A Wiki page 'An error occured while running upload command: Bad Request'

I would like to create a wiki page regards an issue. Should I do it?
The draft of page below.

Some times you can catch An error occured while running upload command

User@BIGPC MINGW64 /c/dev/7e96514c3cb3075dde02 (master)
$ ./node_modules/.bin/gapps upload
Pushing back up to Google Drive...
An error occured while running upload command: Bad Request
Upload failed.

Here is the error object

{
 "cause": {
  "code": 400,
  "errors": [
   {
    "domain": "global",
    "reason": "badRequest",
    "message": "Bad Request"
   }
  ]
 },
 "isOperational": true,
 "code": 400,
 "errors": [
  {
   "domain": "global",
   "reason": "badRequest",
   "message": "Bad Request"
  }
 ]
}

This can happen because that is checked code syntax when uploading files. Try to check syntax your code locally.

gapps upload fails if .html and .js/.gs files collide on either side

First, Apps Script appears to not allow two files differing only in .gs and .html extensions. The Apps Script UI itself handles this really poorly: if you attempt to create a Foo.html, and you already have a Foo.gs, the request to have Foo.html created will silently fail, with no error messages.

gapps upload also fails if you try to upload both a Foo.js and Foo.html; I'm okay lumping this in with all the other "gapps will fail if you do anything unusual" cases that exist. However, if you attempt to upload only a Foo.html file (no Foo.js), but Foo.gs exists in Drive/server side, the request will fail.

Does gapps upload remove files prior to attempting to add news ones? (Is this even how this operation works? Looking at the docs, it wasn't particularly clear if it was.) If not, this could avoid erroring out despite the state that we want to sync being completely valid.

(Also, is it possible to get gapps upload to output any sort of error message about why it fails?)

upload command error: null

Trying to push local changes up to the stand-alone drive file, but encountering this error:

Pushing back up to Google Drive...
An error occured while running upload command: null
Upload failed.

This happens on both my mac and PC. I have deleted the auth .json file and re-authorized. It will init the project without any issue, but can't seem to push back up to drive.

Any help would be greatly appreciated!

push fails

We are working with Google Apps Script for non-profit business. I believe it's different that the regular google apps.

With the current gapps code, I can pull projects but push always shows Upload Failed because of File Not Found.

Have you heard of this issue? Looking for a work-a-around if possible.

Thanks!

gapps auth not finding variable tokens

Whe I run gapps auth, it gives me a url, I go to the google page, click to allow permissions, and then get an error in the console:

whlt@myUbuntuBox:~$ gapps auth ~/Downloads/client_secret_123456789.apps.googleusercontent.com.json 

Please visit the following url in your browser (you'll only have to do this once): https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.scripts&response_type=code&client_id=123456789.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A2386
/usr/local/lib/node_modules/node-google-apps-script/lib/commands/auth.js:89
        credentials.refresh_token = tokens.refresh_token;
                                          ^

TypeError: Cannot read property 'refresh_token' of undefined
    at /usr/local/lib/node_modules/node-google-apps-script/lib/commands/auth.js:89:43
    at /usr/local/lib/node_modules/node-google-apps-script/node_modules/google-auth-library/lib/auth/oauth2client.js:154:5
    at Request._callback (/usr/local/lib/node_modules/node-google-apps-script/node_modules/google-auth-library/lib/transporters.js:70:30)
    at self.callback (/usr/local/lib/node_modules/node-google-apps-script/node_modules/google-auth-library/node_modules/request/request.js:198:22)
    at emitOne (events.js:77:13)
    at Request.emit (events.js:169:7)
    at Request.onRequestError (/usr/local/lib/node_modules/node-google-apps-script/node_modules/google-auth-library/node_modules/request/request.js:861:8)
    at emitOne (events.js:77:13)
    at ClientRequest.emit (events.js:169:7)
    at ClientRequest.onError (/usr/local/lib/node_modules/node-google-apps-script/node_modules/tunnel-agent/index.js:178:21)
    at ClientRequest.g (events.js:260:16)
    at emitOne (events.js:77:13)
    at ClientRequest.emit (events.js:169:7)
    at TLSSocket.socketErrorListener (_http_client.js:258:9)
    at emitOne (events.js:77:13)
    at TLSSocket.emit (events.js:169:7)
whlt@myUbuntuBox:~$ 

My client_secret_blahblah.json looks like this:
{"installed":{"client_id":"123456-qwerty987654321.apps.googleusercontent.com","project_id":"project-id-2468101214","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"QwErTy123456","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}

Should I be calling the auth command differently?

Error running init command { [Error: EISDIR... }

After creating the API keys, downloading the JSON, running gaps init, and visiting the one-time authorization page, I pasted in the ?code= parameter, as the README instructs. But I was given the following error:

Error running init command { [Error: EISDIR, open '/Users/dsernst/.gaps'] errno: 28, code: 'EISDIR', path: '/Users/dsernst/.gaps' }

It turns out we were thinking along similar lines: these config files belong in a place like .gaps in the Home Directory. The problem was I had assumed this .json file was going to be needed for the long-term, so I had already manually created my own ~/.gaps folder and stuck it in there.

I was able to get past this error by moving the .json file out of that folder, deleting the folder, and then re-running gaps init. There might be an opportunity there for more clear error handing, if this issue continues to come up for other users. ๐Ÿ˜„

Cannot push with non-standalone file

I have a script bound to a spreadsheet file, and I was able to gapps init id using the script id from the Project properties. It downloaded my files without any problems.

On the other side, when trying to gapps push, it returns the File not found error. Is that why you recommended to only use standalone scripts ? I'm a newbie with google scripts, what would then be the good practice to access a spreadsheet's data from a standalone script ?

Thanks in advance for the support

can't change type of existing file

Thank you! Thank you! Thank you!

I needed this so badly to be able to do GIT version control for my GAS project. Previous version did not work for uploading. This time it works as expected!

Just one thing - for every file that is uploaded it says can't change type of existing file. Should it be ignored?

xguntis@EliteBook:~/Downloads/temp/gapstest$ gas upload
can't change type of existing file
...
can't change type of existing file
Success uploading for gss

Can't initialize project

  1. node -v: v0.12.18
  2. npm -v: 2.15.11
  3. npm install -g node-google-apps-script
  4. gapps init ${fileId}:
Object.assign(exports, dirpaths)
       ^
TypeError: undefined is not a function
    at Object.<anonymous> (/Users/alexf/.nvm/versions/node/v0.12.18/lib/node_modules/node-google-apps-script/node_modules/node-dir/index.js:3:8)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at Object.<anonymous> (/Users/alexf/.nvm/versions/node/v0.12.18/lib/node_modules/node-google-apps-script/lib/util.js:2:11)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at Object.<anonymous> (/Users/alexf/.nvm/versions/node/v0.12.18/lib/node_modules/node-google-apps-script/lib/manifestor.js:9:12)
    at Module._compile (module.js:460:26)

Am I doing something wrong?

Push Fails on standalone Script in Team Drive

gapps push

Pushing back up to Google Drive...
An error occured while running upload command: File not found: 1FYwO4nDv9vC8t9X8S3qpya3QFhbqehM_wYcJlpuGaV1EjewaNCMdx6-e
Upload failed.

All worked well until I moved the script into a team drive. I notice that the Drive API has a property called supportsTeamDrives for update and get calls. Is it possible that this property is required in the update for it to work?

I did re-authenticate everything after moving the script to the team drive.

gapps auth command will fail and not show error if call to Oauth.getToken fails

Essentially, I think there's a missing else block around the
credentials.refresh_token = tokens.refresh_token; resolve(credentials);
At auth.js:90.
This masks any issues with communicating with Google (in my case there was a proxy issue). I believe this issue occurs in other places in the project (I deleted my auth and re-authed as I was getting errors running upload/push.

Clarify bound script limitations

Currently, it reads:

Your add-on must be developed as a standalone script and tested within Doc or Sheet. This means that it cannot use certain functions of bound scripts, namely installable triggers. While testing within a Doc, you have access to the "Special methods" mentioned in the docs, though. If you followed the quickstart above, you should be set up correctly.

The "While testing within a Doc, you have access to the Special methods" part confuses me: for my script I absolutely need the getActiveRange() special method. I can use it during testing indeed, but is that relevant if the script must be ultimately deployed as a standalone script?

FYI @pietergreyling

Can't download even though Authentication successful

$ gaps init ~/Downloads/client_secret_361575934155-vc7kl330k14upfnddddddddddf8kl0fjm.apps.googleusercontent.com.json

Please visit the following url in your browser (you'll only have to do this once): https://accounts.google.com/o/oauth2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.scripts&response_type=code&client_id=361575934155-vxxxxxxxxxxxxxxxxxxxxxupfnp8ogir69mf8kl0fjm.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fwww.example.com%2Foauth2callback

Look in the url for ?code=XXXXXXXXX and copy everything after the '='
Enter the code here: 4/xxxxxxxxxxxxxxxxxxxxxxxxxxxnKH-jRlhP5guNABYf7LJScV6Y.0kYFEdqDmYEXrjMoGjtSfTo-mI7RmgI#
Authentication successful! Ready to sync.

$ gaps download MZjBBzk9OmQAiUEj17zVxxxxxxxxxxxxxxxxxxxx                                                                  
Error in authenticate module [Error: No refresh token is set.]

I'm on Arch Linux with
$ node --version && npm --version
v0.12.3
2.10.0

Let me know if I can provide any more info to help out.

gapps auth doesn't allow multiple projects

I noticed that when I tried to auth a second AppsScript project I was given the message that the ~/.gapps file already existed, and that I needed to remove it so that I could authenticate the connection with the current project.

Is there a reason why we couldn't move the .gapps file to the project root rather than the machine's user directory? That way we could authenticate multiple gapps projects.

Upload/push fails "File not found: [Script Id]

I have installed node-google-apps-script and have followed the guide for setting up drive API access and Oauth client authentication. Everything has worked like a charm and have done "gapps init " on several of my script projects, all code files in a project is downloaded as expected. A gapps.config.json is also created.

However, doing a "gapps upload" always fails with:
An error occured while running upload command: File not found: [scriptID]

The script projects are stand alone scripts residing in a google website i have created.

I have reviewed the configuration several times, but cant get upload/push to work.

Is there a log file somewhere I can check to see whats happening?

The only thing during setup i have noticed as being a little off is the where the documentation (3 -> 3.1 -> 2.) states that you should use get the project ID from the address bar between /d/ to /edit. This ID does not work when trying to do gapps init. Instead I used the Script ID in File->Project properties. This works for init, but cant upload/push changes.

Rejecting file ID on `gapps init` when ID begins with M

You guys have committed a version that block gapps innit when ID begins with M, but all my bounded scripts starts with M. I know I can't push code to bounded scripts, but I could pull it. I used to backup my bounded scripts this way. Any work around?

Error on gapps push

I get the following error when trying to gapps push:

> gapps push
Pushing back up to Google Drive...

/usr/local/lib/node_modules/node-google-apps-script/lib/util.js:18
        file = path.parse(filename);
                    ^
TypeError: Object #<Object> has no method 'parse'
    at /usr/local/lib/node_modules/node-google-apps-script/lib/util.js:18:21
    at /usr/local/lib/node_modules/node-google-apps-script/node_modules/node-dir/lib/readfiles.js:110:34
    at fs.js:272:14
    at Object.oncomplete (fs.js:108:15)

Trouble authenticating with client_secret.json

I'm having trouble successfully authenticating.

My first problem I think is that I'd set the project type to web application and therefore my JSON file had no redirect URL:

Here's the error output there:
$ gaps init /home/tom/client_secret.json

/usr/local/lib/node_modules/node-google-apps-script/lib/commands/init.js:34
auth.redirect_uri = credentials.web.redirect_uris[0];
^
TypeError: Cannot read property '0' of undefined
at /usr/local/lib/node_modules/node-google-apps-script/lib/commands/init.js:34:54
at fs.js:268:14
at Object.oncomplete (fs.js:107:15)

A little detective work shows that my JSON file in fact had no redirect_utis, so that makes sense.

I then discovered if I downloaded a key for an "Other" application I got a key with a localhost redirect value, which seems like the right thing. However, this time I get a less helpful error from gaps:

$ gaps init /home/tom/Downloads/otherother.json
Error running init command Path did not include correct credentials. Please check that you downloaded the right JSON credentials.

Any help would be appreciated. I'd also suggest adding clarity in the docs about what kind of project to create in the google developer console.

gapps auth [options] <path/to/client/secret.json> is not recognized

gapps auth [options] <path/to/client/secret.json> is not recognized. Instead you should use gapps auth <path/to/client/secret.json> [options]

Just the example:

There is the error

user@nodejs:~$ gapps auth --no-launch-browser ~/.auth/client_secret.json 
No command specified.

All is fine

user@nodejs:~$ gapps auth ~/.auth/client_secret.json --no-launch-browser
Please visit the following url in your browser (you'll only have to do this once):

git and .manifest.json

Hi

Your project is great and exactly what I have been looking for!

I have been trying to download a project and put it into git. Everything works fine but I have a problem with the file .manifest.json. It looks like git is adding \r .

Is the file .manifest.json supposed to be in the git or can it be ignored (in .gitinore).

Maybe you have a recommended way how to handle .manifest.json?

Thanks
Anders Sneckenborg

Referencing several OAuth2 clients?

Hi,
When launching an authentication step with an already existing .gapps folder, we get a message with the impossibility to finish the authentication.
That means that to push several appscript projects, it needs to belong to the same Google project.
Do we plan to allow several authentications to allow a push on several projects (a prompt being displayed if we need to choose which project we have to push the modifications)

thx!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.