GithubにPushしたファイルをCacheControl付きでS3に自動アップロードする

4 min read読了の目安(約4300字

この記事は何

  • GithubにPush(または任意のトリガー)されたファイルを自動的にS3にアップロードするGithub actionは既存のものがある。リンク
  • 大変素晴らしい…!
  • ただ、こちらのシステムのようにS3に上げたファイルを配信したい場合、適切なCacheControlを付与しておきたい。(付けないとPage Speed Insightさんとかにも怒られるし…)
  • もとのactionからfolkして、CacheControlを付けられるものをちゃちゃっと作りました。

結論

こちらに置いてあります。

https://github.com/tenkoh/upload-s3-action

メモ

もとのアクションに対する追加は下記です。

index.js
index.js
const core = require('@actions/core');
const S3 = require('aws-sdk/clients/s3');
const fs = require('fs');
const path = require('path');
const shortid = require('shortid');
const klawSync = require('klaw-sync');
const { lookup } = require('mime-types');

const AWS_KEY_ID = core.getInput('aws_key_id', {
  required: true
});
const SECRET_ACCESS_KEY = core.getInput('aws_secret_access_key', {
  required: true
});
const BUCKET = core.getInput('aws_bucket', {
  required: true
});
const SOURCE_DIR = core.getInput('source_dir', {
  required: true
});
const DESTINATION_DIR = core.getInput('destination_dir', {
  required: false
});
+ const CACHE_MAX_AGE = core.getInput('cache_max_age', {
+   required: false
+ })

const s3 = new S3({
  accessKeyId: AWS_KEY_ID,
  secretAccessKey: SECRET_ACCESS_KEY
});
const destinationDir = DESTINATION_DIR === '/' ? shortid() : DESTINATION_DIR;
+ const maxAge = 'max-age='+CACHE_MAX_AGE
const paths = klawSync(SOURCE_DIR, {
  nodir: true
});

function upload(params) {
  return new Promise(resolve => {
    s3.upload(params, (err, data) => {
      if (err) core.error(err);
      core.info(`uploaded - ${data.Key}`);
      core.info(`located - ${data.Location}`);
      resolve(data.Location);
    });
  });
}

function run() {
  const sourceDir = path.join(process.cwd(), SOURCE_DIR);
  return Promise.all(
    paths.map(p => {
      const fileStream = fs.createReadStream(p.path);
      const bucketPath = path.join(destinationDir, path.relative(sourceDir, p.path));
      const params = {
        Bucket: BUCKET,
        ACL: 'public-read',
        Body: fileStream,
        Key: bucketPath,
        ContentType: lookup(p.path) || 'text/plain',
+       CacheControl: maxAge
      };
      return upload(params);
    })
  );
}

run()
  .then(locations => {
    core.info(`object key - ${destinationDir}`);
    core.info(`object locations - ${locations}`);
    core.setOutput('object_key', destinationDir);
    core.setOutput('object_locations', locations);
  })
  .catch(err => {
    core.error(err);
    core.setFailed(err.message);
  });
action.yml
action.yml
name: Upload S3
description: 'Upload directory to S3'
author: 'Dong Keon Kim'
branding:
  icon: 'upload-cloud'
  color: 'orange'
inputs:
  aws_key_id:
    description: 'aws key id'
    required: true
  aws_secret_access_key:
    description: 'aws secret access key'
    required: true
  aws_bucket:
    description: 'aws bucket name'
    required: true
  source_dir:
    required: true
    description: 'directory to upload'
  destination_dir:
    required: false
    default: /
    description: 'destination directory for upload'
+ cache_max_age:
+   required: false
+   default: 0
+   description: 'add cache control to uploaded files'
outputs:
  object_key:
    description: 'object key'
  object_locations:
    description: 'object locations'
runs:
  using: 'node12'
  main: 'dist/index.js'

使い方例

  1. 事前にGithubリポジトリにsecretを設定する。(IAMのもろもろ、bucket名など)
  2. リポジトリ直下に.github/workflowsディレクトリを作成して、適当な名前で.ymlファイルを作成する。例えばメインブランチにpushした時にアップロードする場合の記載内容は下記の通り(一番シンプルなケースです)。
hogehoge.yml
name: Upload to S3

on:
  push:
      branches:
        - main

jobs:
  upload:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - uses: tenkoh/upload-s3-action@master
        with:
          aws_key_id: ${{ secrets.IAM_ACCESS_KEY }}
          aws_secret_access_key: ${{ secrets.IAM_SECRET}}
          aws_bucket: ${{ secrets.AWS_BUCKET }}
          source_dir: 'fugafuga'
          destination_dir: 'hogefuga'
+         cache_max_age: 86400

こうして記事にして見ると、使っているアクションの中に@masterが残ってますね…。actions/checkoutは現在のデフォルトブランチはmainになっているようですが、ファイルの差分は無さそうなので据え置きでも実質問題ないかと…。upload-s3-actionの方はmainという名前のブランチを作ってないので時流に乗り遅れてます^^;