Skip to content

Commit b7b7819

Browse files
author
Eric Koleda
committed
Merge pull request googleworkspace#13 from hess-g/master
Adding sample for Import/Export API development
2 parents bef4688 + 81d51a3 commit b7b7819

20 files changed

+968
-0
lines changed

import_export_development/.gitignore

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# blog sample files and dirs #
2+
##############################
3+
#This is an example of a file pattern for your personal dev files for a /dev deployment
4+
#Commented here so that a sample file can be included in the blog post repository
5+
#TODO: (sample user) Uncomment to prevent your personal override/test files from being added to git.
6+
#/**/debug.local.*
7+
#TODO: (sample user) Uncomment to prevent the upload tool's staging folders from being added to git.
8+
#build
9+
10+
# npm files and dirs #
11+
######################
12+
node_modules
13+
14+
# OS generated files #
15+
######################
16+
.DS_Store
17+
.DS_Store?
18+
._*
19+
.Spotlight-V100
20+
.Trashes
21+
ehthumbs.db
22+
Thumbs.db

import_export_development/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
This sample shows how to use a task runner and command line tools to develop Apps Script projects. There are quite a few setup steps, but they do mimic some typical one-time tasks you'd be doing in any given development project.
2+
3+
### Getting started
4+
5+
This sample uses the community project [node-google-apps-script](https://www.npmjs.com/package/node-google-apps-script). Before working with the sample, perform the following steps:
6+
7+
1. run `npm install -g node-google-apps-script` to install it globally. This will allow you to run a few of the steps below from the command line.
8+
2. Go through the [configuration and authorization steps](https://www.npmjs.com/package/node-google-apps-script).
9+
2. Run `npm install -g gulp` if you do not already have the [gulp](http://gulpjs.com/) task runner installed globally.
10+
3. Clone this repository, `cd google-apps-script-samples/import_export_development`, and run `npm install`. This will set up all of the local dependencies for the project.
11+
12+
### Demonstrating the developer flow
13+
To get the initial setup working for you, perform the following steps. In a real project, each developer would perform these steps, so that they can do development in isolation from other developers:
14+
15+
1. Create a [new Google Spreadsheet](https://docs.google.com/spreadsheets/create), and copy the ID of the file. The file ID is found in the URL to the spreadsheet:
16+
docs.google.com/spreadsheets/d/***DRIVE_FILE_ID***/edit#gid=123
17+
2. Open the file *src/environments/dev/debug.local.config.js*, and replace DRIVE_FILE_ID with the ID that you copied.
18+
3. Create a new standalone [Google Apps Script](https://script.google.com) project, and copy the ID of the script. The file ID is found in the URL to the script project:
19+
script.google.com/a/macros/google.com/d/***DRIVE_FILE_ID***/edit
20+
4. Perform the following commands:
21+
22+
```
23+
mkdir build
24+
cd build
25+
mkdir dev
26+
cd dev
27+
gapps init *DRIVE_FILE_ID*
28+
cd ../..
29+
gulp upload-latest --env dev
30+
```
31+
32+
5. Refresh your Apps Script project. You should now see a copy of some of the files from the local source location.
33+
34+
You can run the code either by publishing it as a web app, or testing it as an addon (It just counts the number of sheets in your spreadsheet). Because the code finds a valid Spreadsheet ID in the configuration, it uses that instead of `SpreadsheetApp.getActiveSpreadsheet`.
35+
36+
37+
### Deploying for testing
38+
This second phase mimics the setup to isolate testing from development. This would typically be a single Apps Script file for the project, and would have some different code added to enable testing scenarios. In a real project, a testing coordinator or other similar role would perform these steps:
39+
40+
1. Create a [new Google Spreadsheet](https://docs.google.com/spreadsheets/create), and copy the ID of the file. Add 4 additional sheets to the file (the test looks for 5 sheets).
41+
2. Open the file *src/environments/tst/a.myproj.tst.config.js*, and replace DRIVE_FILE_ID with the ID that you copied.
42+
3. Perform the same steps #3 and #4 from above, replacing `dev` with `tst`.
43+
4. Refresh the Apps Script project, open the file `a.myproj.tests.server.main.js`, and then run the function `runAllTests`. Once the run completes, open the log view to see the output.
44+
45+
Once again, this example uses the configured spreadsheet to allow unit testing without having to change code for testing in the primary codebase.
46+
47+
48+
### Deploying for production
49+
This final phase mimics the setup to prepare for a production deployment. This would typically be a single Apps Script file for the project, with the "edit" permission granted to a very limited number of users. In a real project, a deployment coordinator or other similar role would perform these steps:
50+
51+
52+
1. Perform the same steps #3 and #4 from above, replacing `dev` with `prd`.
53+
2. Refresh the Apps Script project, open the project properties (File --> Project properties), and click on the "Scopes" tab. You will see that the spreadsheet scope now only allows the current attached doc (`spreadsheets.currentonly`), which is what we would want for production.
54+
3. You can also create a new spreadsheet, set up for add-on testing, and the code will run successfully.
55+
56+
For production, the configuration file does *not* have a specific spreadsheet, and has the annotation @onlycurrent doc. That will ensure that only Spreadsheets that the code has been linked via the Add-on can be accessed. This limiting of scope is a good practice to provide more confidence to your users that you are only working on sheets that they have linked to your add-on.
57+

import_export_development/gulpfile.js

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
var gulp = require('gulp');
18+
var jshint = require('gulp-jshint');
19+
var shell = require('gulp-shell');
20+
var minimist = require('minimist');
21+
var rename = require('gulp-rename');
22+
var debug = require('gulp-debug');
23+
var del = require('del');
24+
25+
// minimist structure and defaults for this task configuration
26+
var knownOptions = {
27+
string: ['env'],
28+
'default': {
29+
env: 'dev'
30+
}
31+
};
32+
var options = minimist(process.argv.slice(2), knownOptions);
33+
34+
// The root working directory where code is edited
35+
var srcRoot = 'src';
36+
// The root staging folder for gapps configurations
37+
var dstRoot = 'build/' + options.env + '/src';
38+
39+
// Runs the copy-latest task, then calls gapps upload in the correct
40+
// configuration directory based on the target environment
41+
gulp.task('upload-latest', ['copy-latest'], shell.task(['gapps upload'],
42+
{cwd: 'build/' + options.env}));
43+
44+
// Copies all files based on the current target environment.
45+
// Completion of "clean-deployment" is a prerequisite for starting the copy
46+
// process.
47+
gulp.task('copy-latest', ['clean-deployment'], function() {
48+
copyEnvironmentSpecific();
49+
copyServerCode();
50+
copyClientCode();
51+
});
52+
53+
// Copies all .js that will be run by the Apps Script runtime
54+
function copyServerCode() {
55+
return gulp.src([
56+
srcRoot + '/server/*.js',
57+
srcRoot + '/libs/*.js',
58+
srcRoot + '/ui/*.server.js'])
59+
.pipe(gulp.dest(dstRoot));
60+
}
61+
62+
// Appends ".html" to any css, and any js that will be included in client code
63+
// Then copies those .html files to the upload staging folder.
64+
function copyClientCode() {
65+
return gulp.src([
66+
srcRoot + '/ui/*.html',
67+
srcRoot + '/ui/*.css',
68+
srcRoot + '/ui/*.client.js'])
69+
.pipe(
70+
rename(function(path) {
71+
if (path.extname !== '.html') {
72+
path.extname = path.extname + '.html';
73+
}
74+
return path;
75+
}))
76+
.pipe(gulp.dest(dstRoot));
77+
}
78+
79+
// Does any environment specific work.
80+
// the "lint" step is also here, as that is only done on "dev"
81+
// targeted updates.
82+
function copyEnvironmentSpecific() {
83+
// Do target environment specific work
84+
switch (options.env) {
85+
case 'dev':
86+
gulp.src(srcRoot + '/**/*.js')
87+
.pipe(jshint())
88+
.pipe(jshint.reporter('jshint-stylish'));
89+
break;
90+
91+
case 'tst':
92+
//Copy test scripts, if target is "tst"
93+
gulp.src(srcRoot + '/tests/*.js')
94+
.pipe(gulp.dest(dstRoot));
95+
break;
96+
97+
default:
98+
break;
99+
}
100+
101+
return gulp.src(srcRoot + '/environments/' + options.env + '/*.js')
102+
.pipe(gulp.dest(dstRoot));
103+
}
104+
105+
// Utility tasks
106+
gulp.task('clean-deployment', function(cb) {
107+
return del([
108+
dstRoot + '/*.*'
109+
]);
110+
});
111+
112+
gulp.task('clean-deployments', function(cb) {
113+
return del([
114+
'build/dev/src/*.*',
115+
'build/tst/src/*.*' ,
116+
'build/prd/src/*.*'
117+
]);
118+
});
119+
120+
gulp.task('lint', function() {
121+
return gulp.src(srcRoot + '/**/*.js')
122+
.pipe(jshint())
123+
.pipe(jshint.reporter('jshint-stylish'));
124+
});
125+
126+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"author": "[email protected]",
3+
"dependencies": {
4+
"del": "^2.2.0",
5+
"gulp": "^3.9.0",
6+
"gulp-debug": "^2.1.2",
7+
"gulp-jshint": "^1.12.0",
8+
"gulp-rename": "^1.2.2",
9+
"gulp-shell": "^0.5.1",
10+
"jshint-stylish": "^2.0.1",
11+
"minimist": "^1.2.0",
12+
"node-google-apps-script": "^1.1.3",
13+
"vinyl-paths": "^2.1.0"
14+
},
15+
"description": "A sample showing command line tool techniques that can be used when developing for Google Apps Script projects.",
16+
"keywords": [
17+
"google",
18+
"apps-script"
19+
],
20+
"license": "SEE LICENSE IN FILE license.txt",
21+
"main": "gulpfile.js",
22+
"name": "dev-with-apps-script",
23+
"repository": {
24+
"type": "git",
25+
"url": "https://github.com/tbd"
26+
},
27+
"scripts": {},
28+
"version": "1.0.0"
29+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
16+
// For testing - broadens the OAuth scope to allow opening any
17+
// Spreadsheet on the current user's Drive
18+
/** @NotOnlyCurrentDoc */
19+
20+
21+
/**
22+
* @param {myproj.json.Configuration} configuration
23+
* The current configuration settings.
24+
* @return {myproj.json.Configuration} configuration
25+
* The current configuration settings, updated with test settings.
26+
*/
27+
function provideEnvironmentConfiguration_(configuration) {
28+
//TODO: (blog post reader) Change ID below to a Spreadsheet ID you can read
29+
configuration.sheets.debugSpreadsheetId =
30+
'DRIVE_FILE_ID';
31+
configuration.debug = true;
32+
return configuration;
33+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// For production, this script will now only be able to act on Spreadsheets that
16+
// it is attached to via a user installing and activating the add-on.
17+
/** @OnlyCurrentDoc */
18+
// Put additional production configuration here
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2013 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// For testing - broadens the OAuth scope to allow opening any
16+
// Spreadsheet on the current user's Drive
17+
/** @NotOnlyCurrentDoc */
18+
19+
20+
/**
21+
* @param {myproj.json.Configuration} configuration
22+
* The current configuration settings.
23+
* @return {myproj.json.Configuration} configuration
24+
* The current configuration settings, updated with test settings.
25+
*/
26+
function provideEnvironmentConfiguration_(configuration) {
27+
//TODO: (blog post reader) Change ID below to a Spreadsheet ID you can read
28+
configuration.sheets.debugSpreadsheetId = 'DRIVE_FILE_ID';
29+
return configuration;
30+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
var Configuration = {
16+
/**
17+
* Returns the default global settings object. If a developer has added
18+
* function 'provideEnvironmentConfiguration_(globals)' to their project, that
19+
* will be added to the global namespace, and will be visible here to allow
20+
* the dev to set specific values for their run.
21+
* @return {myproj.json.Configuration}
22+
*/
23+
getCurrent: function() {
24+
if (typeof getDefaultConfiguration_ === 'undefined') {
25+
throw 'You must provide an implementation of getDefaultConfiguration_' +
26+
'to use this configuration library.';
27+
}
28+
var defaultConfiguration = getDefaultConfiguration_();
29+
if (typeof provideEnvironmentConfiguration_ !== 'undefined') {
30+
return provideEnvironmentConfiguration_(defaultConfiguration);
31+
} else {
32+
return defaultConfiguration;
33+
}
34+
}
35+
};
36+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
16+
/**
17+
* Logs an Apps Script exception, including the call stack
18+
* @private
19+
* @param {Object} e Apps Script runtime error object
20+
*/
21+
function logException_(e) {
22+
Logger.log('Apps Script runtime exception:');
23+
Logger.log(e.message);
24+
Logger.log('\n' + e.stack + '\n');
25+
}

0 commit comments

Comments
 (0)