{"action":"created","comment":{"url":"https://api.github.com/repos/serverless/components/pulls/comments/241359011","pull_request_review_id":184602687,"id":241359011,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI0MTM1OTAxMQ==","diff_hunk":"@@ -0,0 +1,175 @@\n+import crypto from 'crypto'\n+import path from 'path'\n+import { tmpdir } from 'os'\n+import { readFileSync } from 'fs'\n+import {\n+  equals,\n+  get,\n+  isArray,\n+  isEmpty,\n+  isArchivePath,\n+  keys,\n+  not,\n+  packDir,\n+  pick,\n+  resolve\n+} from '@serverless/utils'\n+\n+const publishLayerVersion = async (\n+  Lambda,\n+  { layerName, zip, layerDescription, licenseInfo, compatibleRuntimes }\n+) => {\n+  const params = {\n+    LayerName: layerName,\n+    Content: {\n+      ZipFile: zip\n+    },\n+    Description: layerDescription,\n+    LicenseInfo: licenseInfo,\n+    CompatibleRuntimes: compatibleRuntimes\n+  }\n+\n+  return await Lambda.publishLayerVersion(params).promise()\n+}\n+\n+const deleteLayerVersion = async (Lambda, layerName, version) => {\n+  const params = { LayerName: layerName, VersionNumber: version }\n+  await Lambda.deleteLayerVersion(params).promise()\n+}\n+\n+const AwsLambdaLayerVersion = async (SuperClass) => {\n+  return class extends SuperClass {\n+    hydrate(prevInstance) {\n+      super.hydrate(prevInstance)\n+      this.arn = get('arn', prevInstance)\n+      this.zip = get('zip', prevInstance)\n+      this.layerVersion = get('layerVersion', prevInstance)\n+      this.versions = get('versions', prevInstance)\n+    }\n+\n+    async shouldDeploy(prevInstance, context) {\n+      if (isArchivePath(this.content)) {\n+        this.zip = readFileSync(this.content)\n+      } else {\n+        await this.pack(context)\n+      }\n+\n+      const hash = crypto.createHash('sha256')\n+      hash.update(this.zip)\n+      this.hash = hash.digest('base64')\n+\n+      const currentConfig = pick(\n+        ['layerName', 'layerDescription', 'content', 'compatibleRuntimes', 'licenseInfo', 'hash'],\n+        this\n+      )\n+      const prevConfig = prevInstance ? pick(keys(currentConfig), prevInstance) : {}\n+      const configChanged = not(equals(currentConfig, prevConfig))\n+\n+      if (\n+        prevInstance &&\n+        ((this.retain === false && configChanged) ||\n+          (prevInstance.layerName !== currentConfig.layerName && this.retain !== true))\n+      ) {\n+        return 'replace'\n+      } else if (!prevInstance || configChanged) {\n+        return 'deploy'\n+      }\n+    }\n+\n+    getId() {\n+      return this.arn\n+    }\n+\n+    async pack() {\n+      let inputDirPath = this.content\n+\n+      if (isArray(this.content)) {\n+        inputDirPath = this.content[0] // first item is path to content dir\n+      }\n+\n+      const outputFileName = `${this.instanceId}-${Date.now()}.zip`\n+      const outputFilePath = path.join(tmpdir(), outputFileName)\n+\n+      await packDir(inputDirPath, outputFilePath)\n+      this.zip = readFileSync(outputFilePath)\n+      return this.zip\n+    }\n+\n+    async sync() {\n+      let { provider } = this\n+      provider = resolve(provider)\n+      const AWS = provider.getSdk()\n+      const Lambda = new AWS.Lambda()\n+\n+      const { LayerVersions } = await Lambda.listLayerVersions({\n+        LayerName: resolve(this.layerName)\n+      }).promise()\n+      if (isEmpty(LayerVersions)) {\n+        return 'removed'\n+      }\n+      this.versions = LayerVersions.map(({ Version }) => Version)\n+      this.layerVersion = Math.max(...this.versions)\n+      this.arn = LayerVersions.filter(\n+        ({ Version }) => Version === this.layerVersion\n+      )[0].LayerVersionArn\n+\n+      const layerVersionInfo = await Lambda.getLayerVersion({\n+        LayerName: resolve(this.layerName),\n+        VersionNumber: this.layerVersion\n+      }).promise()\n+      this.hash = layerVersionInfo.Content.CodeSha256\n+    }\n+\n+    async deploy(prevInstance, context) {\n+      const { provider } = this\n+      const AWS = provider.getSdk()\n+      const Lambda = new AWS.Lambda()\n+\n+      context.log(`Publishing Lambda Layer Version: ${this.layerName}`)\n+      const newLayerVersion = await publishLayerVersion(Lambda, this)\n+      this.arn = newLayerVersion.LayerArn\n+      this.layerVersion = newLayerVersion.Version\n+      if (!this.versions) {\n+        this.versions = []\n+      }\n+      this.versions.push(this.layerVersion)\n+    }\n+\n+    async remove(context) {\n+      const { layerName, versions, retain, provider } = this\n+      const AWS = provider.getSdk()\n+      const Lambda = new AWS.Lambda()\n+\n+      if (retain === true) {\n+        context.log(`Skipping removing(per retention policy) Lambda Layer Version: ${layerName}`)\n+        return\n+      }\n+\n+      context.log(`Removing Lambda Layer Versions: ${layerName}`)\n+\n+      for (const version of versions) {","path":"registry/AwsLambdaLayerVersion/src/index.js","position":150,"original_position":150,"commit_id":"b499ca09a39c90e0a2e09f71bfe79b82a70abf8f","original_commit_id":"b499ca09a39c90e0a2e09f71bfe79b82a70abf8f","user":{"login":"pmuens","id":1606004,"node_id":"MDQ6VXNlcjE2MDYwMDQ=","avatar_url":"https://avatars3.githubusercontent.com/u/1606004?v=4","gravatar_id":"","url":"https://api.github.com/users/pmuens","html_url":"https://github.com/pmuens","followers_url":"https://api.github.com/users/pmuens/followers","following_url":"https://api.github.com/users/pmuens/following{/other_user}","gists_url":"https://api.github.com/users/pmuens/gists{/gist_id}","starred_url":"https://api.github.com/users/pmuens/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pmuens/subscriptions","organizations_url":"https://api.github.com/users/pmuens/orgs","repos_url":"https://api.github.com/users/pmuens/repos","events_url":"https://api.github.com/users/pmuens/events{/privacy}","received_events_url":"https://api.github.com/users/pmuens/received_events","type":"User","site_admin":false},"body":"Using `async` / `await` inside of `for` / `forEach` loops can be tricky (see https://serverless.com/blog/common-node8-mistakes-in-lambda/ and https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404).\r\n\r\nWe might want to use `Promise.all` with a `catch` here (or Bluebirds `Promise.mapSeries` if sequential processing is needed).","created_at":"2018-12-13T11:05:33Z","updated_at":"2018-12-13T11:08:23Z","html_url":"https://github.com/serverless/components/pull/382#discussion_r241359011","pull_request_url":"https://api.github.com/repos/serverless/components/pulls/382","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/serverless/components/pulls/comments/241359011"},"html":{"href":"https://github.com/serverless/components/pull/382#discussion_r241359011"},"pull_request":{"href":"https://api.github.com/repos/serverless/components/pulls/382"}}},"pull_request":{"url":"https://api.github.com/repos/serverless/components/pulls/382","id":238066696,"node_id":"MDExOlB1bGxSZXF1ZXN0MjM4MDY2Njk2","html_url":"https://github.com/serverless/components/pull/382","diff_url":"https://github.com/serverless/components/pull/382.diff","patch_url":"https://github.com/serverless/components/pull/382.patch","issue_url":"https://api.github.com/repos/serverless/components/issues/382","number":382,"state":"open","locked":false,"title":"Lambda layers","user":{"login":"dschep","id":667763,"node_id":"MDQ6VXNlcjY2Nzc2Mw==","avatar_url":"https://avatars0.githubusercontent.com/u/667763?v=4","gravatar_id":"","url":"https://api.github.com/users/dschep","html_url":"https://github.com/dschep","followers_url":"https://api.github.com/users/dschep/followers","following_url":"https://api.github.com/users/dschep/following{/other_user}","gists_url":"https://api.github.com/users/dschep/gists{/gist_id}","starred_url":"https://api.github.com/users/dschep/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dschep/subscriptions","organizations_url":"https://api.github.com/users/dschep/orgs","repos_url":"https://api.github.com/users/dschep/repos","events_url":"https://api.github.com/users/dschep/events{/privacy}","received_events_url":"https://api.github.com/users/dschep/received_events","type":"User","site_admin":false},"body":"## What has been implemented?\r\n\r\nAdded and `AwsLambdaLayerVersion` component.\r\n\r\nAlso refactored boiler plate in `loadTypeMetaFromName`\r\n\r\n## Steps to verify\r\n\r\ncreate a service using it. minimum config is `content` key pointing to a path\r\n\r\n## Todos:\r\n\r\n* [x] Write tests\r\n* [x] Write / update documentation\r\n* [x] Run Prettier\r\n","created_at":"2018-12-12T14:57:09Z","updated_at":"2018-12-13T11:08:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"20bdf3d08c0a8103ca9840331e68c896d494a972","assignee":null,"assignees":[],"requested_reviewers":[{"login":"brianneisler","id":1471972,"node_id":"MDQ6VXNlcjE0NzE5NzI=","avatar_url":"https://avatars1.githubusercontent.com/u/1471972?v=4","gravatar_id":"","url":"https://api.github.com/users/brianneisler","html_url":"https://github.com/brianneisler","followers_url":"https://api.github.com/users/brianneisler/followers","following_url":"https://api.github.com/users/brianneisler/following{/other_user}","gists_url":"https://api.github.com/users/brianneisler/gists{/gist_id}","starred_url":"https://api.github.com/users/brianneisler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brianneisler/subscriptions","organizations_url":"https://api.github.com/users/brianneisler/orgs","repos_url":"https://api.github.com/users/brianneisler/repos","events_url":"https://api.github.com/users/brianneisler/events{/privacy}","received_events_url":"https://api.github.com/users/brianneisler/received_events","type":"User","site_admin":false},{"login":"eahefnawy","id":2312463,"node_id":"MDQ6VXNlcjIzMTI0NjM=","avatar_url":"https://avatars1.githubusercontent.com/u/2312463?v=4","gravatar_id":"","url":"https://api.github.com/users/eahefnawy","html_url":"https://github.com/eahefnawy","followers_url":"https://api.github.com/users/eahefnawy/followers","following_url":"https://api.github.com/users/eahefnawy/following{/other_user}","gists_url":"https://api.github.com/users/eahefnawy/gists{/gist_id}","starred_url":"https://api.github.com/users/eahefnawy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eahefnawy/subscriptions","organizations_url":"https://api.github.com/users/eahefnawy/orgs","repos_url":"https://api.github.com/users/eahefnawy/repos","events_url":"https://api.github.com/users/eahefnawy/events{/privacy}","received_events_url":"https://api.github.com/users/eahefnawy/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/serverless/components/pulls/382/commits","review_comments_url":"https://api.github.com/repos/serverless/components/pulls/382/comments","review_comment_url":"https://api.github.com/repos/serverless/components/pulls/comments{/number}","comments_url":"https://api.github.com/repos/serverless/components/issues/382/comments","statuses_url":"https://api.github.com/repos/serverless/components/statuses/b499ca09a39c90e0a2e09f71bfe79b82a70abf8f","head":{"label":"serverless:lambda-layers","ref":"lambda-layers","sha":"b499ca09a39c90e0a2e09f71bfe79b82a70abf8f","user":{"login":"serverless","id":13742415,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNzQyNDE1","avatar_url":"https://avatars0.githubusercontent.com/u/13742415?v=4","gravatar_id":"","url":"https://api.github.com/users/serverless","html_url":"https://github.com/serverless","followers_url":"https://api.github.com/users/serverless/followers","following_url":"https://api.github.com/users/serverless/following{/other_user}","gists_url":"https://api.github.com/users/serverless/gists{/gist_id}","starred_url":"https://api.github.com/users/serverless/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serverless/subscriptions","organizations_url":"https://api.github.com/users/serverless/orgs","repos_url":"https://api.github.com/users/serverless/repos","events_url":"https://api.github.com/users/serverless/events{/privacy}","received_events_url":"https://api.github.com/users/serverless/received_events","type":"Organization","site_admin":false},"repo":{"id":117983079,"node_id":"MDEwOlJlcG9zaXRvcnkxMTc5ODMwNzk=","name":"components","full_name":"serverless/components","private":false,"owner":{"login":"serverless","id":13742415,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNzQyNDE1","avatar_url":"https://avatars0.githubusercontent.com/u/13742415?v=4","gravatar_id":"","url":"https://api.github.com/users/serverless","html_url":"https://github.com/serverless","followers_url":"https://api.github.com/users/serverless/followers","following_url":"https://api.github.com/users/serverless/following{/other_user}","gists_url":"https://api.github.com/users/serverless/gists{/gist_id}","starred_url":"https://api.github.com/users/serverless/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serverless/subscriptions","organizations_url":"https://api.github.com/users/serverless/orgs","repos_url":"https://api.github.com/users/serverless/repos","events_url":"https://api.github.com/users/serverless/events{/privacy}","received_events_url":"https://api.github.com/users/serverless/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/serverless/components","description":"An easier way to build applications with serverless services –","fork":false,"url":"https://api.github.com/repos/serverless/components","forks_url":"https://api.github.com/repos/serverless/components/forks","keys_url":"https://api.github.com/repos/serverless/components/keys{/key_id}","collaborators_url":"https://api.github.com/repos/serverless/components/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/serverless/components/teams","hooks_url":"https://api.github.com/repos/serverless/components/hooks","issue_events_url":"https://api.github.com/repos/serverless/components/issues/events{/number}","events_url":"https://api.github.com/repos/serverless/components/events","assignees_url":"https://api.github.com/repos/serverless/components/assignees{/user}","branches_url":"https://api.github.com/repos/serverless/components/branches{/branch}","tags_url":"https://api.github.com/repos/serverless/components/tags","blobs_url":"https://api.github.com/repos/serverless/components/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/serverless/components/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/serverless/components/git/refs{/sha}","trees_url":"https://api.github.com/repos/serverless/components/git/trees{/sha}","statuses_url":"https://api.github.com/repos/serverless/components/statuses/{sha}","languages_url":"https://api.github.com/repos/serverless/components/languages","stargazers_url":"https://api.github.com/repos/serverless/components/stargazers","contributors_url":"https://api.github.com/repos/serverless/components/contributors","subscribers_url":"https://api.github.com/repos/serverless/components/subscribers","subscription_url":"https://api.github.com/repos/serverless/components/subscription","commits_url":"https://api.github.com/repos/serverless/components/commits{/sha}","git_commits_url":"https://api.github.com/repos/serverless/components/git/commits{/sha}","comments_url":"https://api.github.com/repos/serverless/components/comments{/number}","issue_comment_url":"https://api.github.com/repos/serverless/components/issues/comments{/number}","contents_url":"https://api.github.com/repos/serverless/components/contents/{+path}","compare_url":"https://api.github.com/repos/serverless/components/compare/{base}...{head}","merges_url":"https://api.github.com/repos/serverless/components/merges","archive_url":"https://api.github.com/repos/serverless/components/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/serverless/components/downloads","issues_url":"https://api.github.com/repos/serverless/components/issues{/number}","pulls_url":"https://api.github.com/repos/serverless/components/pulls{/number}","milestones_url":"https://api.github.com/repos/serverless/components/milestones{/number}","notifications_url":"https://api.github.com/repos/serverless/components/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/serverless/components/labels{/name}","releases_url":"https://api.github.com/repos/serverless/components/releases{/id}","deployments_url":"https://api.github.com/repos/serverless/components/deployments","created_at":"2018-01-18T12:57:56Z","updated_at":"2018-12-11T17:59:28Z","pushed_at":"2018-12-13T06:01:49Z","git_url":"git://github.com/serverless/components.git","ssh_url":"git@github.com:serverless/components.git","clone_url":"https://github.com/serverless/components.git","svn_url":"https://github.com/serverless/components","homepage":"https://www.serverless.com","size":11625,"stargazers_count":743,"watchers_count":743,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":67,"mirror_url":null,"archived":false,"open_issues_count":79,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":67,"open_issues":79,"watchers":743,"default_branch":"master"}},"base":{"label":"serverless:type-system","ref":"type-system","sha":"59583efc21f75a815e883b74488782bb0b910c59","user":{"login":"serverless","id":13742415,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNzQyNDE1","avatar_url":"https://avatars0.githubusercontent.com/u/13742415?v=4","gravatar_id":"","url":"https://api.github.com/users/serverless","html_url":"https://github.com/serverless","followers_url":"https://api.github.com/users/serverless/followers","following_url":"https://api.github.com/users/serverless/following{/other_user}","gists_url":"https://api.github.com/users/serverless/gists{/gist_id}","starred_url":"https://api.github.com/users/serverless/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serverless/subscriptions","organizations_url":"https://api.github.com/users/serverless/orgs","repos_url":"https://api.github.com/users/serverless/repos","events_url":"https://api.github.com/users/serverless/events{/privacy}","received_events_url":"https://api.github.com/users/serverless/received_events","type":"Organization","site_admin":false},"repo":{"id":117983079,"node_id":"MDEwOlJlcG9zaXRvcnkxMTc5ODMwNzk=","name":"components","full_name":"serverless/components","private":false,"owner":{"login":"serverless","id":13742415,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEzNzQyNDE1","avatar_url":"https://avatars0.githubusercontent.com/u/13742415?v=4","gravatar_id":"","url":"https://api.github.com/users/serverless","html_url":"https://github.com/serverless","followers_url":"https://api.github.com/users/serverless/followers","following_url":"https://api.github.com/users/serverless/following{/other_user}","gists_url":"https://api.github.com/users/serverless/gists{/gist_id}","starred_url":"https://api.github.com/users/serverless/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serverless/subscriptions","organizations_url":"https://api.github.com/users/serverless/orgs","repos_url":"https://api.github.com/users/serverless/repos","events_url":"https://api.github.com/users/serverless/events{/privacy}","received_events_url":"https://api.github.com/users/serverless/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/serverless/components","description":"An easier way to build applications with serverless services –","fork":false,"url":"https://api.github.com/repos/serverless/components","forks_url":"https://api.github.com/repos/serverless/components/forks","keys_url":"https://api.github.com/repos/serverless/components/keys{/key_id}","collaborators_url":"https://api.github.com/repos/serverless/components/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/serverless/components/teams","hooks_url":"https://api.github.com/repos/serverless/components/hooks","issue_events_url":"https://api.github.com/repos/serverless/components/issues/events{/number}","events_url":"https://api.github.com/repos/serverless/components/events","assignees_url":"https://api.github.com/repos/serverless/components/assignees{/user}","branches_url":"https://api.github.com/repos/serverless/components/branches{/branch}","tags_url":"https://api.github.com/repos/serverless/components/tags","blobs_url":"https://api.github.com/repos/serverless/components/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/serverless/components/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/serverless/components/git/refs{/sha}","trees_url":"https://api.github.com/repos/serverless/components/git/trees{/sha}","statuses_url":"https://api.github.com/repos/serverless/components/statuses/{sha}","languages_url":"https://api.github.com/repos/serverless/components/languages","stargazers_url":"https://api.github.com/repos/serverless/components/stargazers","contributors_url":"https://api.github.com/repos/serverless/components/contributors","subscribers_url":"https://api.github.com/repos/serverless/components/subscribers","subscription_url":"https://api.github.com/repos/serverless/components/subscription","commits_url":"https://api.github.com/repos/serverless/components/commits{/sha}","git_commits_url":"https://api.github.com/repos/serverless/components/git/commits{/sha}","comments_url":"https://api.github.com/repos/serverless/components/comments{/number}","issue_comment_url":"https://api.github.com/repos/serverless/components/issues/comments{/number}","contents_url":"https://api.github.com/repos/serverless/components/contents/{+path}","compare_url":"https://api.github.com/repos/serverless/components/compare/{base}...{head}","merges_url":"https://api.github.com/repos/serverless/components/merges","archive_url":"https://api.github.com/repos/serverless/components/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/serverless/components/downloads","issues_url":"https://api.github.com/repos/serverless/components/issues{/number}","pulls_url":"https://api.github.com/repos/serverless/components/pulls{/number}","milestones_url":"https://api.github.com/repos/serverless/components/milestones{/number}","notifications_url":"https://api.github.com/repos/serverless/components/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/serverless/components/labels{/name}","releases_url":"https://api.github.com/repos/serverless/components/releases{/id}","deployments_url":"https://api.github.com/repos/serverless/components/deployments","created_at":"2018-01-18T12:57:56Z","updated_at":"2018-12-11T17:59:28Z","pushed_at":"2018-12-13T06:01:49Z","git_url":"git://github.com/serverless/components.git","ssh_url":"git@github.com:serverless/components.git","clone_url":"https://github.com/serverless/components.git","svn_url":"https://github.com/serverless/components","homepage":"https://www.serverless.com","size":11625,"stargazers_count":743,"watchers_count":743,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":67,"mirror_url":null,"archived":false,"open_issues_count":79,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":67,"open_issues":79,"watchers":743,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/serverless/components/pulls/382"},"html":{"href":"https://github.com/serverless/components/pull/382"},"issue":{"href":"https://api.github.com/repos/serverless/components/issues/382"},"comments":{"href":"https://api.github.com/repos/serverless/components/issues/382/comments"},"review_comments":{"href":"https://api.github.com/repos/serverless/components/pulls/382/comments"},"review_comment":{"href":"https://api.github.com/repos/serverless/components/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/serverless/components/pulls/382/commits"},"statuses":{"href":"https://api.github.com/repos/serverless/components/statuses/b499ca09a39c90e0a2e09f71bfe79b82a70abf8f"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"pmuens"}}