upload-to-cdn.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #!/usr/bin/env node
  2. // Upload Uppy releases to Edgly.net CDN. Copyright (c) 2018, Transloadit Ltd.
  3. //
  4. // This file:
  5. //
  6. // - Assumes EDGLY_KEY and EDGLY_SECRET are available (e.g. set via Travis secrets)
  7. // - Tries to load env.sh instead, if not
  8. // - Checks if a tag is being built (on Travis - otherwise opts to continue execution regardless)
  9. // - Assumed a fully built uppy is in root dir (unless a specific tag was specified, then it's fetched from npm)
  10. // - Runs npm pack, and stores files to e.g. https://transloadit.edgly.net/releases/uppy/v1.0.1/uppy.css
  11. // - Uses local package by default, if [version] argument was specified, takes package from npm
  12. //
  13. // Run as:
  14. //
  15. // ./upload-to-cdn.sh [version]
  16. //
  17. // To upload all versions in one go (DANGER):
  18. //
  19. // git tag |awk -Fv '{print "./bin/upload-to-cdn.sh "$2}' |bash
  20. //
  21. // Authors:
  22. //
  23. // - Kevin van Zonneveld <kevin@transloadit.com>
  24. const path = require('path')
  25. const AWS = require('aws-sdk')
  26. const packlist = require('npm-packlist')
  27. const tar = require('tar')
  28. const pacote = require('pacote')
  29. const concat = require('concat-stream')
  30. const { promisify } = require('util')
  31. const readFile = promisify(require('fs').readFile)
  32. const finished = promisify(require('stream').finished)
  33. function delay (ms) {
  34. return new Promise(resolve => setTimeout(resolve, ms))
  35. }
  36. const AWS_REGION = 'us-east-1'
  37. const AWS_BUCKET = 'crates.edgly.net'
  38. const AWS_DIRECTORY = '756b8efaed084669b02cb99d4540d81f/default'
  39. async function getRemoteDistFiles (packageName, version) {
  40. const files = new Map()
  41. const tarball = pacote.tarball.stream(`${packageName}@${version}`)
  42. .pipe(new tar.Parse())
  43. tarball.on('entry', (readEntry) => {
  44. if (readEntry.path.startsWith('package/dist/')) {
  45. readEntry
  46. .pipe(concat((buf) => {
  47. files.set(readEntry.path.replace(/^package\/dist\//, ''), buf)
  48. }))
  49. .on('error', (err) => {
  50. tarball.emit('error', err)
  51. })
  52. } else {
  53. readEntry.resume()
  54. }
  55. })
  56. await finished(tarball)
  57. return files
  58. }
  59. async function getLocalDistFiles (packagePath) {
  60. const files = (await packlist({ path: packagePath }))
  61. .filter(f => f.startsWith('dist/'))
  62. .map(f => f.replace(/^dist\//, ''))
  63. const entries = await Promise.all(
  64. files.map(async (f) => [
  65. f,
  66. await readFile(path.join(packagePath, 'dist', f))
  67. ])
  68. )
  69. return new Map(entries)
  70. }
  71. async function main (packageName, version) {
  72. if (!packageName) {
  73. console.error('usage: upload-to-cdn <packagename> [version]')
  74. console.error('Must provide a package name')
  75. process.exit(1)
  76. }
  77. if (!process.env.EDGLY_KEY || !process.env.EDGLY_SECRET) {
  78. console.error('Missing EDGLY_KEY or EDGLY_SECRET env variables, bailing')
  79. process.exit(1)
  80. }
  81. const s3 = new AWS.S3({
  82. credentials: new AWS.Credentials({
  83. accessKeyId: process.env.EDGLY_KEY,
  84. secretAccessKey: process.env.EDGLY_SECRET
  85. }),
  86. region: AWS_REGION
  87. })
  88. const remote = !!version
  89. if (!remote) {
  90. version = require(`../packages/${packageName}/package.json`).version
  91. }
  92. // Warn if uploading a local build not from CI:
  93. // - If we're on CI, this should be a release commit.
  94. // - If we're local, normally we should upload a released version, not a local build.
  95. if (!remote && !process.env.CI) {
  96. console.log('Warning, writing a local build to the CDN, this is usually not what you want. Sleeping 3s. Press CTRL+C!')
  97. await delay(3000)
  98. }
  99. const packagePath = remote
  100. ? `${packageName}@${version}`
  101. : path.join(__dirname, '..', 'packages', packageName)
  102. const files = remote
  103. ? await getRemoteDistFiles(packageName, version)
  104. : await getLocalDistFiles(packagePath)
  105. // uppy → releases/uppy/
  106. // @uppy/robodog → releases/uppy/robodog/
  107. // @uppy/locales → releases/uppy/locales/
  108. const dirName = packageName.startsWith('@uppy/')
  109. ? packageName.replace(/^@/, '')
  110. : 'uppy'
  111. const outputPath = path.posix.join('releases', dirName, `v${version}`)
  112. for (const [filename, buffer] of files.entries()) {
  113. const key = path.posix.join(AWS_DIRECTORY, outputPath, filename)
  114. console.log(`pushing s3://${AWS_BUCKET}/${key}`)
  115. await s3.putObject({
  116. Bucket: AWS_BUCKET,
  117. Key: key,
  118. Body: buffer
  119. }).promise()
  120. }
  121. }
  122. main(...process.argv.slice(2)).catch((err) => {
  123. console.error(err.stack)
  124. process.exit(1)
  125. })