-
Notifications
You must be signed in to change notification settings - Fork 4
Add makesheet package: Google Apps Script web app for sheet timestamp tracking #75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 4 commits
eb9780f
78784ca
1c60517
b3bfb59
ee3ee2e
b20f099
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| { | ||
| "type": "module", | ||
| "devDependencies": {}, | ||
| "dependencies": { | ||
| "csv-parse": "^5.4.0", | ||
| "jstoxml": "^3.2.7" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| .git/** | ||
| node_modules/** | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| { | ||
| "extends": [ | ||
| "airbnb-base" | ||
| ], | ||
| "env": { | ||
| "es6": true | ||
| }, | ||
| "rules": { | ||
| "quotes": [ | ||
| "error", | ||
| "single", | ||
| { | ||
| "avoidEscape": true, | ||
| "allowTemplateLiterals": true | ||
| } | ||
| ], | ||
| "comma-dangle": ["error", "always-multiline"], | ||
| "no-console": "off", | ||
| "no-unused-vars": [ | ||
| "error", | ||
| { | ||
| "argsIgnorePattern": "^_", | ||
| "varsIgnorePattern": "^_" | ||
| } | ||
| ], | ||
| "no-undef": "off", | ||
| "no-underscore-dangle": [ | ||
| "error", | ||
| { | ||
| "allowAfterThis": false, | ||
| "allowAfterSuper": false, | ||
| "enforceInMethodNames": false, | ||
| "allow": ["_testDoGet", "_testCreateJsonResponse"] | ||
| } | ||
| ] | ||
| } | ||
| } | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # makesheet | ||
|
|
||
| Google Sheets timestamp service for Make-based workflows. | ||
|
|
||
| ## Overview | ||
|
|
||
| This package provides a Google Apps Script web app that returns the modification timestamp of a Google Sheet. This is useful for Make-based build systems that need to track when a sheet has been modified to trigger downstream processing. | ||
|
|
||
| ## Setup | ||
|
|
||
| 1. Install clasp globally if you haven't already: | ||
| ```bash | ||
| npm install -g @google/clasp | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any particular reason to do it globally rather than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added note that clasp can be installed as devDependency if preferred, though global installation is common for deployment tools. Commit ee3ee2e |
||
| ``` | ||
|
|
||
| 2. Login to Google Apps Script: | ||
| ```bash | ||
| yarn login | ||
| ``` | ||
|
|
||
| 3. Create a new Google Apps Script project and note the script ID. | ||
|
||
|
|
||
| 4. Update `.clasp.json` with your script ID: | ||
| ```json | ||
| { | ||
| "scriptId": "your-script-id-here", | ||
| "rootDir": "." | ||
| } | ||
| ``` | ||
|
|
||
| 5. Push the code to Google Apps Script: | ||
| ```bash | ||
| yarn push | ||
| ``` | ||
|
|
||
| 6. Deploy as a web app and note the deployment ID: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cite (link) docs for how to deploy it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added links to Google Apps Script documentation and clasp deployment documentation. Commit ee3ee2e |
||
| ```bash | ||
| yarn deploy | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| Once deployed, you can query the modification time of a Google Sheet using: | ||
|
|
||
| ```bash | ||
| curl -s "https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec?sheetId=YOUR_SHEET_ID" | ||
| ``` | ||
|
|
||
| This returns a JSON response: | ||
| ```json | ||
| { | ||
| "modifiedTime": "2023-12-01T15:30:45.123Z" | ||
| } | ||
| ``` | ||
|
|
||
| Or an error response: | ||
| ```json | ||
| { | ||
| "error": "sheetId parameter required" | ||
| } | ||
| ``` | ||
|
|
||
| ## Integration with Make | ||
|
|
||
| Use the provided `example-usage.mk` file as a reference for integrating with Make-based workflows. | ||
|
|
||
| ## Scripts | ||
|
|
||
| - `yarn push` - Push code to Google Apps Script | ||
| - `yarn deploy` - Push and deploy as web app (requires DEPLOYMENT_ID env var) | ||
|
||
| - `yarn curl` - Test the deployed web app (requires DEPLOYMENT_ID and SHEET_ID env vars) | ||
| - `yarn login` - Login to Google Apps Script | ||
| - `yarn lint` - Run ESLint to check code style (Airbnb style) | ||
| - `yarn lint-fix` - Run ESLint and automatically fix issues | ||
|
|
||
| ## Testing | ||
|
|
||
| The code includes test functions that can be used with the Google Apps Script debugger: | ||
|
|
||
| - `_testDoGet()` - Tests the main `doGet` function with various input scenarios | ||
| - `_testCreateJsonResponse()` - Tests the JSON response creation function | ||
|
|
||
| To run tests in the Google Apps Script editor: | ||
| 1. Open your script in the Google Apps Script editor | ||
| 2. Select one of the test functions from the function dropdown | ||
| 3. Click the run button to execute the test | ||
| 4. View the output in the console | ||
|
|
||
| This approach follows the pattern suggested for testing Google Apps Script functions without requiring external test frameworks. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "webapp": { | ||
| "access": "ANYONE_ANONYMOUS", | ||
| "executeAs": "USER_DEPLOYING" | ||
| }, | ||
| "timeZone": "America/Chicago", | ||
| "dependencies": { | ||
| }, | ||
| "exceptionLogging": "STACKDRIVER", | ||
| "runtimeVersion": "V8" | ||
| } | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # Example usage of makesheet package in Makefile workflows | ||
| # | ||
| # Set these environment variables: | ||
| # DEPLOYMENT_ID = your Google Apps Script deployment ID | ||
| # SHEET_ID = the Google Sheet ID you want to track | ||
|
|
||
| # Target file to store the sheet's timestamp | ||
| SHEET_TIMESTAMP_FILE = sheet.timestamp | ||
|
|
||
| # URL for the deployed makesheet web app | ||
| SHEET_INFO_URL = https://script.google.com/macros/s/$(DEPLOYMENT_ID)/exec | ||
|
|
||
| # Create a timestamp file based on the sheet's last modification time | ||
| $(SHEET_TIMESTAMP_FILE): | ||
| curl -s "$(SHEET_INFO_URL)?sheetId=$(SHEET_ID)" | \ | ||
| jq -r '.modifiedTime' | \ | ||
| xargs -I {} touch -d {} $@ | ||
|
|
||
| # Example target that depends on the sheet timestamp | ||
| data-processing: $(SHEET_TIMESTAMP_FILE) | ||
| @echo "Processing data from sheet (last modified: $$(cat $(SHEET_TIMESTAMP_FILE)))" | ||
| # Your data processing commands here | ||
|
|
||
| # Clean up timestamp file | ||
| clean: | ||
| rm -f $(SHEET_TIMESTAMP_FILE) | ||
|
|
||
| # Check if sheet has been modified since last processing | ||
| check-sheet-status: $(SHEET_TIMESTAMP_FILE) | ||
| @if [ -f $(SHEET_TIMESTAMP_FILE) ]; then \ | ||
| echo "Sheet timestamp file exists: $$(ls -la $(SHEET_TIMESTAMP_FILE))"; \ | ||
| else \ | ||
| echo "Sheet timestamp file does not exist, will be created"; \ | ||
| fi | ||
|
|
||
| # Alternative approach: always check and update if sheet is newer | ||
| update-if-newer: | ||
| @CURRENT_TIME=$$(curl -s "$(SHEET_INFO_URL)?sheetId=$(SHEET_ID)" | jq -r '.modifiedTime'); \ | ||
| if [ ! -f $(SHEET_TIMESTAMP_FILE) ] || [ "$$(date -r $(SHEET_TIMESTAMP_FILE) -u +%Y-%m-%dT%H:%M:%S.%3NZ)" != "$$CURRENT_TIME" ]; then \ | ||
| echo "Sheet has been modified, updating timestamp"; \ | ||
| echo "$$CURRENT_TIME" | xargs -I {} touch -d {} $(SHEET_TIMESTAMP_FILE); \ | ||
| else \ | ||
| echo "Sheet has not been modified since last check"; \ | ||
| fi | ||
|
|
||
| .PHONY: data-processing clean check-sheet-status update-if-newer | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "name": "makesheet", | ||
| "version": "0.1.0", | ||
| "description": "Google Sheets timestamp service for Make-based workflows", | ||
| "main": "sheetInfo.js", | ||
|
||
| "author": "Dan Connolly", | ||
|
||
| "license": "MIT", | ||
| "scripts": { | ||
| "push": "clasp push", | ||
| "deploy": "clasp push; clasp deploy --deploymentId $DEPLOYMENT_ID", | ||
| "curl": "curl -L https://script.google.com/macros/s/$DEPLOYMENT_ID/exec?sheetId=$SHEET_ID", | ||
| "login": "clasp login", | ||
| "lint": "eslint *.js", | ||
| "lint-fix": "eslint --fix *.js" | ||
| }, | ||
| "devDependencies": { | ||
| "@google/clasp": "^2.3.0", | ||
| "@types/google-apps-script": "^1.0.17", | ||
| "typescript": "^4.0.5" | ||
| } | ||
| } | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| function createJsonResponse(data) { | ||
| return ContentService.createTextOutput(JSON.stringify(data)).setMimeType( | ||
| ContentService.MimeType.JSON, | ||
| ); | ||
| } | ||
|
|
||
| function doGet(e) { | ||
|
||
| const { sheetId } = e.parameter; | ||
| if (!sheetId) { | ||
| return createJsonResponse({ error: 'sheetId parameter required' }); | ||
| } | ||
|
|
||
| try { | ||
| const file = DriveApp.getFileById(sheetId); | ||
|
||
| const modifiedTime = file.getLastUpdated().toISOString(); | ||
| return createJsonResponse({ modifiedTime }); | ||
| } catch (error) { | ||
| return createJsonResponse({ error: error.toString() }); | ||
| } | ||
| } | ||
|
|
||
| // Test functions for use with Google Apps Script debugger | ||
| function _testDoGet() { | ||
| console.log('Testing doGet with missing sheetId...'); | ||
| const resultMissing = doGet({ parameter: {} }); | ||
| console.log('Result:', resultMissing.getContent()); | ||
|
|
||
| console.log('Testing doGet with invalid sheetId...'); | ||
| const resultInvalid = doGet({ parameter: { sheetId: 'invalid-id' } }); | ||
| console.log('Result:', resultInvalid.getContent()); | ||
|
|
||
| // Note: To test with a valid sheet ID, replace 'your-test-sheet-id' | ||
| // with an actual Google Sheets ID you have access to | ||
| console.log('Testing doGet with valid sheetId (uncomment to test)...'); | ||
| // const resultValid = doGet({ parameter: { sheetId: 'your-test-sheet-id' } }); | ||
| // console.log('Result:', resultValid.getContent()); | ||
| } | ||
|
|
||
| function _testCreateJsonResponse() { | ||
| console.log('Testing createJsonResponse...'); | ||
| const testData = { test: 'value', timestamp: new Date().toISOString() }; | ||
| const response = createJsonResponse(testData); | ||
| console.log('Response content:', response.getContent()); | ||
| console.log('Response MIME type:', response.getMimeType()); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this out of scope? drop it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted the out-of-scope changes to discover-dl/package.json. Commit ee3ee2e