瀏覽代碼

Automate release publishing

Caleb Porzio 3 年之前
父節點
當前提交
7d635a939a
共有 5 個文件被更改,包括 133 次插入24 次删除
  1. 47 2
      package-lock.json
  2. 1 0
      package.json
  3. 70 11
      scripts/release.js
  4. 2 11
      scripts/update-docs.js
  5. 13 0
      scripts/utils.js

+ 47 - 2
package-lock.json

@@ -8,6 +8,7 @@
                 "packages/*"
                 "packages/*"
             ],
             ],
             "devDependencies": {
             "devDependencies": {
+                "axios": "^0.21.1",
                 "brotli-size": "^4.0.0",
                 "brotli-size": "^4.0.0",
                 "chalk": "^4.1.1",
                 "chalk": "^4.1.1",
                 "cypress": "^5.5.0",
                 "cypress": "^5.5.0",
@@ -1393,6 +1394,15 @@
             "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
             "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
             "dev": true
             "dev": true
         },
         },
+        "node_modules/axios": {
+            "version": "0.21.1",
+            "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+            "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+            "dev": true,
+            "dependencies": {
+                "follow-redirects": "^1.10.0"
+            }
+        },
         "node_modules/babel-jest": {
         "node_modules/babel-jest": {
             "version": "26.6.3",
             "version": "26.6.3",
             "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
             "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
@@ -2958,6 +2968,26 @@
                 "node": ">=8"
                 "node": ">=8"
             }
             }
         },
         },
+        "node_modules/follow-redirects": {
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
+            "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
+            "dev": true,
+            "funding": [
+                {
+                    "type": "individual",
+                    "url": "https://github.com/sponsors/RubenVerborgh"
+                }
+            ],
+            "engines": {
+                "node": ">=4.0"
+            },
+            "peerDependenciesMeta": {
+                "debug": {
+                    "optional": true
+                }
+            }
+        },
         "node_modules/for-in": {
         "node_modules/for-in": {
             "version": "1.0.2",
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
             "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -7677,7 +7707,7 @@
             }
             }
         },
         },
         "packages/alpinejs": {
         "packages/alpinejs": {
-            "version": "3.0.1",
+            "version": "3.0.6",
             "license": "MIT",
             "license": "MIT",
             "dependencies": {
             "dependencies": {
                 "@vue/reactivity": "^3.0.2"
                 "@vue/reactivity": "^3.0.2"
@@ -7693,7 +7723,7 @@
         },
         },
         "packages/docs": {
         "packages/docs": {
             "name": "@alpinejs/docs",
             "name": "@alpinejs/docs",
-            "version": "3.0.1-revision.4",
+            "version": "3.0.6-revision.2",
             "license": "MIT"
             "license": "MIT"
         },
         },
         "packages/history": {
         "packages/history": {
@@ -8888,6 +8918,15 @@
             "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
             "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
             "dev": true
             "dev": true
         },
         },
+        "axios": {
+            "version": "0.21.1",
+            "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+            "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+            "dev": true,
+            "requires": {
+                "follow-redirects": "^1.10.0"
+            }
+        },
         "babel-jest": {
         "babel-jest": {
             "version": "26.6.3",
             "version": "26.6.3",
             "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
             "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
@@ -10141,6 +10180,12 @@
                 "path-exists": "^4.0.0"
                 "path-exists": "^4.0.0"
             }
             }
         },
         },
+        "follow-redirects": {
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
+            "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
+            "dev": true
+        },
         "for-in": {
         "for-in": {
             "version": "1.0.2",
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
             "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",

+ 1 - 0
package.json

@@ -4,6 +4,7 @@
         "packages/*"
         "packages/*"
     ],
     ],
     "devDependencies": {
     "devDependencies": {
+        "axios": "^0.21.1",
         "brotli-size": "^4.0.0",
         "brotli-size": "^4.0.0",
         "chalk": "^4.1.1",
         "chalk": "^4.1.1",
         "cypress": "^5.5.0",
         "cypress": "^5.5.0",

+ 70 - 11
scripts/release.js

@@ -1,7 +1,10 @@
-let { runFromPackage, writeToPackageDotJson } = require('./utils')
+let { runFromPackage, writeToPackageDotJson, ask, run } = require('./utils')
 let chalk = require('chalk');
 let chalk = require('chalk');
 let log = message => console.log(chalk.green(message))
 let log = message => console.log(chalk.green(message))
 let version = process.argv[2]
 let version = process.argv[2]
+let axios = require('axios').create({
+    headers: { Authorization: `Bearer ${require('./.env.json').GITHUB_TOKEN}` }
+})
 
 
 if (! version) {
 if (! version) {
     return console.log('Whoops, you must pass in a version number to this command as the argument')
     return console.log('Whoops, you must pass in a version number to this command as the argument')
@@ -15,17 +18,12 @@ writeNewAlpineVersion()
 writeNewDocsVersion()
 writeNewDocsVersion()
 buildAssets()
 buildAssets()
 
 
-let readline = require('readline').createInterface({
-    input: process.stdin,
-    output: process.stdout
-});
-
 setTimeout(() => {
 setTimeout(() => {
-    readline.question('Are you sure you want to publish this release: '+version+'?', answer => {
-        if (['y', 'Y', 'yes', 'Yes', 'YES'].includes(answer)) publish()
-
-        readline.close();
-    });
+    ask('Have you reviewed, committed, and pushed all the files for this release?', () => {
+        draftRelease(version, () => {
+            ask('Are you sure you want to publish this release: '+version+'?', () => publish())
+        })
+    })
 }, 1000)
 }, 1000)
 
 
 function writeNewAlpineVersion() {
 function writeNewAlpineVersion() {
@@ -54,3 +52,64 @@ function publish() {
 
 
     log('\n\nFinished!')
     log('\n\nFinished!')
 }
 }
+
+async function draftRelease(name, after = () => {}) {
+    let lastRelease = await getLastRelease()
+
+    let since = lastRelease.published_at
+
+    let pulls = await getPullRequestsSince(since)
+
+    let output = ''
+
+    output += "## Added\n\n## Fixed\n\n"
+
+    output += pulls.map(pull => `* ${pull.title} [#${pull.number}](${pull.html_url})`).join('')
+
+    let fs = require('fs')
+
+    fs.writeFileSync('./changelog.tmp', output)
+
+    run('code ./changelog.tmp')
+
+    ask('Are you finished editing the changelog?', () => {
+        let content = fs.readFileSync('./changelog.tmp', 'utf8')
+
+        fs.unlinkSync('./changelog.tmp')
+
+        tagNewRelease(name, content).then(() => after)
+    })
+}
+
+async function getLastRelease() {
+    let { data: releases } = await axios.get('https://api.github.com/repos/alpinejs/alpine/releases')
+
+    let lastRelease = releases.find(release => {
+        return release.target_commitish === 'main'
+            && release.draft === false
+    })
+
+    return lastRelease
+}
+
+async function getPullRequestsSince(since) {
+    let { data: pulls } = await axios.get('https://api.github.com/repos/alpinejs/alpine/pulls?state=closed&sort=updated&direction=desc&base=main')
+
+    let pullsSince = pulls.filter(pull => {
+        if (! pull.merged_at) return false
+
+        return pull.merged_at > since
+    })
+
+    return pullsSince
+}
+
+async function tagNewRelease(name, content) {
+    await axios.post('https://api.github.com/repos/alpinejs/alpine/releases', {
+        name: name,
+        tag_name: name,
+        target_commitish: 'main',
+        body: content,
+        draft: true,
+    })
+}

+ 2 - 11
scripts/update-docs.js

@@ -1,4 +1,4 @@
-let { runFromPackage, getFromPackageDotJson, writeToPackageDotJson } = require('./utils')
+let { runFromPackage, getFromPackageDotJson, writeToPackageDotJson, ask } = require('./utils')
 
 
 let version = getFromPackageDotJson('docs', 'version')
 let version = getFromPackageDotJson('docs', 'version')
 
 
@@ -14,17 +14,8 @@ console.log('Publishing on NPM...');
 
 
 runFromPackage('docs', 'npm publish --access public')
 runFromPackage('docs', 'npm publish --access public')
 
 
-let readline = require('readline').createInterface({
-    input: process.stdin,
-    output: process.stdout
-});
-
 setTimeout(() => {
 setTimeout(() => {
-    readline.question('Do you want to deploy this new version to the docs site?', answer => {
-        if (['y', 'Y', 'yes', 'Yes', 'YES'].includes(answer)) deploy()
-
-        readline.close();
-    });
+    ask('Do you want to deploy this new version to the docs site?', () => deploy())
 }, 1000)
 }, 1000)
 
 
 function deploy() {
 function deploy() {

+ 13 - 0
scripts/utils.js

@@ -20,3 +20,16 @@ module.exports.getFromPackageDotJson = function (package, key) {
 
 
     return dotJson.get(key)
     return dotJson.get(key)
 }
 }
+
+module.exports.ask = async function (message, callback) {
+    let readline = require('readline').createInterface({
+        input: process.stdin,
+        output: process.stdout
+    })
+
+    readline.question(message, answer => {
+        if (['y', 'Y', 'yes', 'Yes', 'YES'].includes(answer)) callback()
+
+        readline.close()
+    })
+}