gasを使ってDriveのフォルダーコピー&ファイルのURL一覧取得

#環境
2017/7/23時点の Google Apps Script

#はじめに

###普段やっていること
業務で施策毎に以下のような作業を行っています。

- Drive上で施策ごとにフォーマットディレクトリをコピーする。
    - 仕様書、設計などをまとめる書類のフォーマットファイルがある。
- 各ファイルのURLを取得してチケットに貼り付ける。

▽こんな感じのファイル管理です
![スクリーンショット 2017-07-23 10.35.53.png](https://qiita-image-store.s3.amazonaws.com/0/44990/68990a74-1661-299f-b9e1-b93d155ca09c.png)

###問題
Google Driveはディレクトリのコピーに対応していません。そのため手動で以下を行う必要がありました。面倒！！

- フォーマットのファイルをコピーする。
- フォルダーを作成する。
- コピーしたファイルを作成したフォルダーに移す。
- フォルダーと各ファイルの名前を1つずつ変更する。
- 各ファイルのURLを1つずつ取得してチケットに貼り付ける。


###解決方法
下記の手順に圧縮するためのgasを作成しました。

- getFeatureName関数にプロジェクト名を指定する。
- gasを実行する。
- テキストからURL一覧をコピーしてチケットに貼り付ける。


#先にまとめ
```js

/* 
・使い方
getFeatureName に名前をつけて startCopy 実行します。

・成果物
フォーマットフォルダ内をコピーした新規フォルダを作成し、すべてのURLを記載したテキストを出力します。
ログにテキストのURLを出力します。
*/

// 施策名を取得する
function getFeatureName(){
  return "サンプル施策";
}

//この関数を実行する
function startCopy() {
  var parentFolder = DriveApp.getFolderById(getFolderId("Parent"));
  var sourceFolder = DriveApp.getFolderById(getFolderId("Source"));
  var createdFolder = parentFolder.createFolder(getFeatureName());

  // フォルダの中身をコピー
  folderCopy(sourceFolder, createdFolder);    
  // URL一覧のテキスト作成
  createFileDescribedAllURL(createdFolder);
  // ファイル名に施策名をつける
  setFeatureNameToFiles(createdFolder);
}

// フォルダーのIDを取得する　定数管理用
function getFolderId(type){
  switch(type){
    case "Source":
      // フォーマットとなるディレクトリのID
      return "aaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    case "Parent":
      // 作成したフォルダを置くディレクトリのID
      return "aaaaaaaaaaaaaaaaaaaaaaaaaaaa";
  }
}

// sourceFolder 内のファイルを createdFolder にコピーする
function folderCopy(sourceFolder, createdFolder) {
  var sourceFiles = sourceFolder.getFiles();
  while(sourceFiles.hasNext()) {
    var sourceFile = sourceFiles.next();
    sourceFile.makeCopy(sourceFile.getName(), createdFolder);
  }
}

// フォルダ内にあるファイルのURLを列挙したテキストファイルを作成する
function createFileDescribedAllURL(createdFolder){
  var createdFiles = createdFolder.getFiles();
  var text = "";
  while(createdFiles.hasNext()){
    var file = createdFiles.next();
    var fileName = file.getName();
    text += "・" + fileName + "\n";
    text += file.getUrl() + "\n";
    text += "\n";
  }
  if(text == null){
    return;
  }
  var textFile = createdFolder.createFile("url一覧", text, MimeType.PLAIN_TEXT);
  Logger.log(textFile.getUrl());　// ログにテキストのURLを出力する
}

// フォルダ内にあるファイルの頭に「施策名_」を追加する
function setFeatureNameToFiles(createdFolder){
  var createdFiles = createdFolder.getFiles();
  while(createdFiles.hasNext()){
    var file = createdFiles.next();
    var fileName = file.getName();
    file.setName(getFeatureName() + "_" + fileName);
  }
}
```
▽ログにURL一覧テキストへのURL出力
![スクリーンショット 2017-07-23 10.54.58.png](https://qiita-image-store.s3.amazonaws.com/0/44990/c6298428-0a36-47d2-2723-7670f1b0b3f6.png)

▽URL一覧テキスト
![スクリーンショット 2017-07-23 10.56.01.png](https://qiita-image-store.s3.amazonaws.com/0/44990/44ec4fe8-a6a2-4201-a472-284d9ac6423b.png)

▽作成されたフォルダ内
![スクリーンショット 2017-07-23 11.43.28.png](https://qiita-image-store.s3.amazonaws.com/0/44990/e49f6bae-1482-fa62-7d93-ac6729ab7f09.png)

#解説
###ディレクトリを特定するためにIDを指定する
getFolderId にDriveのフォルダーIDを指定して使います。一度設定したら固定の運用イメージです。
IDを指定する理由は下記の2点です。

- 同じ名前が認められている。
    - そのため名前検索だと複数ヒットすることがあり、どれを使えば良いかわからなくなる。
- フォルダーは単にリンクを持っているだけ。
    - 1つのファイルに複数の親ディレクトリということがありうる。
    - そのため、ファイルの名前や形式から特定しづらい。

###ディレクトリのコピーは別
```js
// sourceFolder 内のファイルを createdFolder にコピーする
function folderCopy(sourceFolder, createdFolder) {
  var sourceFiles = sourceFolder.getFiles();
  while(sourceFiles.hasNext()) {
    var sourceFile = sourceFiles.next();
    sourceFile.makeCopy(sourceFile.getName(), createdFolder);
  }
}
```
ここで行っているのはファイルのコピーのみです。
フォルダーもコピーしたいのであれば
sourceFolder.getFolders()した結果を回す必要があります。


#さいごに
今の状態だと完全にエンジニアが使う前提です。しかし、書類はディレクターやプランナーが管理をしていることが多いです。もしGUIを作るのであればスプレッドシートを使えば良いと思います。施策名やIDの入力はセルに書いてもらえばよいし、結果はBrowserクラスで表示してあげれば親切です。ネタが切れたら作るかも...