This project works as a bootstrap to start a new Google Apps Script project or attach it to an existing one.
It will give you, out of the box, a well defined develop flow for your GAS project.
This workflow will let you to:
- Use the latest TypeScript features.
- Use the latest EcmaScript features.
- Easily unit test your project, even if your are using the Google-related interfaces (SpreadsheetApp, DriveApp, DataStudioApp, etc.).
- Maintain your code always formatted and linted in your workspace.
- Manage your code using versioning tools.
- Easily make usage of environment variables.
- Treeshake your code to only deploy the one that is being used.
Welcome to your new EZ CLASP life 🚀
-
Use this template by clicking the "Use this template" button over repository files.
You can use
npx degit
way instead:npx degit cristobalgvera/ez-clasp YOUR_REPOSITORY_NAME
-
Using the new created repository URL, clone it following next steps
If you used the
template
way:git clone https://github.com/YOUR_USER_NAME/YOUR_REPOSITORY_NAME.git cd YOUR_REPOSITORY_NAME npm install npm run clasp:login # And access to your Google account
If you used
npx degit
way:cd YOUR_REPOSITORY_NAME git init npm install npm run clasp:login # And access to your Google account
-
If you DO NOT have an existing project, run
npm run clasp:create
to create a new project. CLASP CLI will prompt some project types, you should select one of them. -
If you have an existing project, add your Apps Script ID inside
.clasp.json
in the scriptId key. -
Create a
.env
file copying the .env.example file.cp .env.example .env
Then your can make proper usage of environemnt variables in case you want. If you don't, simply remove all environment variable related stuff.
-
Push your project to Google Apps Script using
npm run deploy
The first time you execute this command, CLASP CLI will ask you to overwrite manifest file
appsscript.json
, inserty
key and pressenter
. This will let you to fully control your project from your local environment.The
appsscript.json
file contains configuration required by Google to manage permissions used by your users related to your project. -
Test the code opening your Google Apps Script projects dashboard!
There you can change your project name to the name you want (by default will be called
CHANGE_MY_NAME
, in order to remember you to change it).
If you need to push some other files that will not be included in transpilation
process, you can put them into app
folder (or whatever location you
want if you change .claspignore
configuration).
You can put your assets in there, e.g. some HTML or any JavaScript file you need to be pushed to Google Apps Script.
.html
, .js
. If you need files like .css
, see Google Apps Script
HTML best practices page.
Google provide us a way to handle environment variables using the PropertiesService. This way of handling environment variables can easily transform in a mess if you are working in a developers team. You can check this way in order to follow Google's approach.
This project gives you a way to handle environment variables directly
inside your local development using Rollup's plugins. You just need to create
a .env
file located in the root directory of your project and then
use the secret values simply using the process.env.YOUR_SECRET_KEY
approach.
You are free to create wrapper services to avoid repeating this pattern and
give plenty type safety to your environment variables.
In order to test the code that make usage of environment variables, you just need to add all your required environment variables to the env.setup.js file. This will make your entire process of testing to use those variables.
If you want to have detailed control over environment variables, you will
need to control it from your tests directly, e.g. modifying the process.env
object to include an specific value. Take care about how to make this
mocking process, remember the isolation of unit tests. Check
this article.
When you add a Google service (Gmail, Google Sheets, etc.) which require some
kind of permissions, e.g. permissions to read your email or write in a
spreadsheet, you will need to add those specific permissions
(a.k.a. OAuthScopes) in the file called appsscript.json
,
in the oauthScope
array as a string. The list of all OAuthScopes can be
found in here.
Similarly, when you need to use an advanced service, like Drive
(the old version), or a third party library, you will need to add those,
using the required format, in the appsscript.json
file,
inside the dependencies object, in one of the arrays. See the required structure
in this link
Google libraries use namespaces as a resource to be imported, meaning there will
no be imported through import
syntax. This adds a complexity when testing it.
In order to easily tests those kind of libraries, you will have to mock the global object, like so:
// my-class.service.ts
// In this example `GoogleService` is the service in use provided by Google
export class MyClassService {
someMethodThatUseAnyGoogleService(body: BodyType) {
const childGoogleService = GoogleService.anyMethod();
return childGoogleService.childMethod(body);
}
}
// my-class.service.spec.ts
import { createMock } from '@golevelup/ts-jest';
import { MyClassService } from './my-class.service.ts';
describe('MyClassService', () => {
let underTest: MyClassService;
beforeEach(() => {
underTest = new MyClassService();
});
describe('someMethodThatUseAnyGoogleService', () => {
const originalService = global.GoogleService;
let googleService: typeof GoogleService;
let childGoogleService: ReturnType<(typeof googleService)['anyMethod']>;
beforeEach(() => {
childGoogleService = createMock<typeof childGoogleService>();
googleService = createMock<typeof googleService>({
anyMethod: () => childGoogleService,
});
global.GoogleService = googleService;
});
afterEach(() => {
global.GoogleService = originalService;
});
it('should call ChildGoogleService with correct parameters', () => {
const expected = { any: 'parameter' };
const childGoogleServiceSpy = jest.spyOn(
childGoogleService,
'childMethod',
);
underTest.someMethodThatUseAnyGoogleService(expected as any);
expect(childGoogleServiceSpy).toHaveBeenCalledWith(expected);
});
it('should return the value', () => {
const expected = { any: 'parameter' };
jest
.spyOn(childGoogleService, 'childMethod')
.mockReturnValueOnce(expected);
const actual = underTest.someMethodThatUseAnyGoogleService({} as any);
expect(actual).toEqual(expected);
});
});
});
This project contain these libraries that will help you to have a better development experience:
- TypeScript (Development).
- ESLint + Prettier (Format and linting).
- Babel + Rollup (Building).
- Husky + Lint-Staged (Commit).
- Jest (Testing).
In order to improve commitment flow when working with teams, template has a pre configured Husky implementation. The pre-commit flow is:
- Fix ESLint issues if possible.
- Fix Prettier issues if possible.
- Build the code.
All tasks but build run only for the staged changes.
In case you want ignore certain files to be pushed, you can add them to the
.claspignore
file. You can see in it some already ignored
base directories.
P.D.: Of course you can delete this README file and the assets
folder.
You can found here some practical example usages of this template in order to help you to understand better how to link it to a Google Apps Script project:
- Automatic FUP (include connection to Firebase)
- Open Orders Update
- CMIC Credentials
- Expeditures Projection