📁
GASで自身のプロジェクトファイルを取得したい
こんにちは、luthです
GASからプログラミングに入門し、Vue/React、Typescriptを勉強していったノンプログラマーですが、チーム内で利用する、社内ツール開発を4年ほどやってきました
チーム内で開発していく中で、以下課題がありました
- Nodeを扱えるレベルの開発者がチームにいない
- Githubは社内ルールにより利用できない(開発部門ではないため)
- DriveAPI系(GASのDriveApp含む)はドメインレベルで一部規制あり
- 上記から、スクリプトのバックアップ/更新履歴は手動コピー以外に残す手段なし
色々と模索する中で、上記課題には「GASプロジェクトから、自身/別のGASプロジェクトを取得させて、スプレッドシートでGit管理」とかいう荒業を見出しました…!(強引)
この中の「GASプロジェクトから、自身/別のGASプロジェクトを取得させる」ところは他に記事を見なかったので、まとめてみます
*スプシ管理のところの仕様は各人のスキルレベル・チーム内リテラシに依存するかと思いますので、本稿の対象外としました
GASプロジェクトから、自身/別のGASプロジェクトを取得するコード
scriptFiles.gs
/**
* [型定義用定数のためjsDoc外で利用しない] 取得したプロジェクトファイルデータ群の型定義
* @type {{ projectName: string, scriptId: string, files: { id: string, name: string, type: 'json'|'gs'|'html', source: string }[] }}
*/
const ProjectFileType_ = undefined;
/**
* [権限追加用定数のため利用しない] GAS側に「DriveAppのOAuth権限が必要!」と伝えるためだけの定数定義。
*/
const _drive_ = DriveApp.getStorageUsed;
/**
*
* @param {string} scriptId スクリプトID。プロジェクト自身から取得するなら`ScriptApp.getScriptId()`等で取得
* @param {string} accessToken アクセストークン。対象プロジェクトにアクセス権を持つアカウントから`ScriptApp.getOAuthToken()`で取得
* @returns {ProjectFileType_ || {}} `ProjectFileType_.files[].source`が各ファイル内のソースコード
*/
function getScriptFiles(scriptId, accessToken) {
const downloadUrl = `https://script.google.com/feeds/download/export?id=${scriptId}&format=json`;
let projectName;
try {
const res = UrlFetchApp.fetch(downloadUrl, {
method: 'get',
headers: {
authorization: 'Bearer ' + accessToken,
muteHttpExceptions: true
}
});
const responseCode = res.getResponseCode();
const responseHeaders = res.getHeaders();
if (responseCode !== 200 || responseHeaders['Content-Type'] !== 'application/json') throw Error(res.getContentText());
json = res.getContentText();
json = JSON.parse(json);
json.files = json.files.map(file => {
file.type = file.type === 'server_js' ? 'gs' : file.type;
file.name = `${file.name}.${file.type}`;
return file;
});
projectName = (
responseHeaders['Content-Disposition']
.match(/filename\*=UTF\-8''(.+)\.json/i)
|| [, null]
)[1];
projectName = decodeURI(projectName);
} catch (e) {
console.error(e.stack);
return {};
}
return {
projectName,
scriptId,
files: json.files
}
}
スクリプト取得例:実行ファイル自身
getOwnScript.gs
function getOwnScript() {
const scriptId = ScriptApp.getScriptId();
const accessToken = ScriptApp.getOAuthToken();
const { files } = getScriptFiles(scriptId, accessToken);
if (!files) throw Error('スクリプトファイル取得失敗');
files.forEach(({ name, source }) => {
console.log({ name });
console.log(source);
});
}
スクリプト取得例:他ファイルを複数管理
getOtherScripts.gs
function getOtherScripts() {
const scriptIds = [
'abcde01234fghijkl56789',
'abcde01234fghijkl56780',
'abcde01234fghijkl56781',
]
const accessToken = ScriptApp.getOAuthToken();
scriptIds.forEach(scriptId => {
const { projectName, files } = getScriptFiles(scriptId, accessToken);
if (!files) throw Error('スクリプトファイル取得失敗');
files.forEach(({ name, source }) => {
console.log({ projectName, fileName: name });
console.log(source);
});
});
}
活用方法
- スプレッドシートなどに書き込み、バックアップや編集履歴として利用する
- diff系ライブラリを参考にして、バージョン間差分を取得する
https://github.com/cemerick/jsdifflib
-
scriptFiles.gs
について、file.type
が設計と異なっていたため修正
Discussion