Add update helper script (#117)

* Squashed commit from 'helper' branch

* CI: run "update-helper" script on cron

* Update index.js

* disable proxy test

* lint

* re-add proxy test with delay

* lint

* Fix cron time
This commit is contained in:
extremeheat 2021-08-07 17:41:01 -04:00 committed by GitHub
commit 254dbefcd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 226 additions and 2 deletions

59
.github/helper-bot/github-helper.js vendored Normal file
View file

@ -0,0 +1,59 @@
if (!process.env.CI) {
// mock a bunch of things for testing locally -- https://github.com/actions/toolkit/issues/71
process.env.GITHUB_REPOSITORY = 'PrismarineJS/bedrock-protocol'
process.env.GITHUB_EVENT_NAME = 'issue_comment'
process.env.GITHUB_SHA = 'cb2fd97b6eae9f2c7fee79d5a86eb9c3b4ac80d8'
process.env.GITHUB_REF = 'refs/heads/master'
process.env.GITHUB_WORKFLOW = 'Issue comments'
process.env.GITHUB_ACTION = 'run1'
process.env.GITHUB_ACTOR = 'test-user'
module.exports = { getIssueStatus: () => ({}), updateIssue: () => {}, createIssue: () => {} }
return
}
// const { Octokit } = require('@octokit/rest') // https://github.com/octokit/rest.js
const github = require('@actions/github')
const token = process.env.GITHUB_TOKEN
const octokit = github.getOctokit(token)
const context = github.context
async function getIssueStatus (title) {
// https://docs.github.com/en/rest/reference/search#search-issues-and-pull-requests
const existingIssues = await octokit.rest.search.issuesAndPullRequests({
q: `is:issue repo:${process.env.GITHUB_REPOSITORY} in:title ${title}`
})
// console.log('Existing issues', existingIssues)
const existingIssue = existingIssues.data.items.find(issue => issue.title === title)
if (!existingIssue) return {}
return { open: existingIssue.state === 'open', closed: existingIssue.state === 'closed', id: existingIssue.number }
}
async function updateIssue (id, payload) {
const issue = await octokit.rest.issues.update({
...context.repo,
issue_number: id,
body: payload.body
})
console.log(`Updated issue ${issue.data.title}#${issue.data.number}: ${issue.data.html_url}`)
}
async function createIssue (payload) {
const issue = await octokit.rest.issues.create({
...context.repo,
...payload
})
console.log(`Created issue ${issue.data.title}#${issue.data.number}: ${issue.data.html_url}`)
}
async function close (id, reason) {
if (reason) await octokit.rest.issues.createComment({ ...context.repo, issue_number: id, body: reason })
const issue = await octokit.rest.issues.update({ ...context.repo, issue_number: id, state: 'closed' })
console.log(`Closed issue ${issue.data.title}#${issue.data.number}: ${issue.data.html_url}`)
}
if (process.env.CI) {
module.exports = { getIssueStatus, updateIssue, createIssue, close }
}

137
.github/helper-bot/index.js vendored Normal file
View file

@ -0,0 +1,137 @@
// Automatic version update checker for Minecraft bedrock edition.
const fs = require('fs')
const cp = require('child_process')
const helper = require('./github-helper')
const latestVesionEndpoint = 'https://itunes.apple.com/lookup?bundleId=com.mojang.minecraftpe'
const changelogURL = 'https://feedback.minecraft.net/hc/en-us/sections/360001186971-Release-Changelogs'
// Relevant infomation for us is:
// "version": "1.17.10",
// "currentVersionReleaseDate": "2021-07-13T15:35:49Z",
// "releaseNotes": "What's new in 1.17.10:\nVarious bug fixes",
function buildFirstIssue (title, result, externalPatches) {
let commitData = ''
let protocolVersion = '?'
const date = new Date(result.currentVersionReleaseDate).toUTCString()
for (const name in externalPatches) {
commitData += '### ' + name + '\n'
const [patches, diff] = externalPatches[name]
for (const [name, url] of patches) {
commitData += `<a href="${url}">${name}</a>\n`
}
commitData += `\n**[See the diff between *${result.currentVersionReleaseDate}* and now](${diff})**\n`
}
try { protocolVersion = getProtocolVersion() } catch (e) { console.log(e) }
return {
title,
body: `
A new Minecraft Bedrock version is available (as of ${date}), version **${result.version}**
## Official Changelog
* ${result.releaseNotes} *(via App Store)*
* ${changelogURL}
## 3rd party protocol patches
${commitData}
## Protocol Details
(I will close this issue automatically if "${result.version}" is added to index.d.ts on "master" and there are no X's below)
<table>
<tr><td><b>Name</b></td><td>${result.version}</td>
<tr><td><b>Protocol ID</b></td><td>${protocolVersion}</td>
<!-- TODO ... automatically fetch server, test and grab relevant information and dump
<tr><td><b>Partly Already Compatible</b></td><td></td>
<tr><td><b>Protocol Dumpers Work</b></td><td></td>
-->
</table>
-----
🤖 I am a bot, I check for updates every 2 hours without a trigger. You can close this PR to prevent any further updates.
`
}
}
function getCommitsInRepo (repo, containing, since) {
const endpoint = `https://api.github.com/repos/${repo}/commits`
console.log('Getting', endpoint)
cp.execSync(`curl -L ${endpoint} -o commits.json`, { stdio: 'inherit', shell: true })
const commits = JSON.parse(fs.readFileSync('./commits.json', 'utf-8'))
const relevant = []
for (const commit of commits) {
if (commit.commit.message.includes(containing)) {
console.log('commit url', commit.html_url)
relevant.push([commit.commit.message, commit.html_url])
}
}
if (since) {
cp.execSync(`curl -L ${endpoint}?since=${since} -o commits.json`, { stdio: 'inherit', shell: true })
const commits = JSON.parse(fs.readFileSync('./commits.json', 'utf-8'))
const head = commits[0].sha
const tail = commits[commits.length - 1].sha
return [relevant, `https://github.com/${repo}/compare/${tail}..${head}`]
}
return [relevant]
}
function getProtocolVersion () {
if (!fs.existsSync('./ProtocolInfo.php')) cp.execSync('curl -LO https://raw.githubusercontent.com/pmmp/PocketMine-MP/stable/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php', { stdio: 'inherit', shell: true })
const currentApi = fs.readFileSync('./ProtocolInfo.php', 'utf-8')
const [, latestProtocolVersion] = currentApi.match(/public const CURRENT_PROTOCOL = (\d+);/)
return latestProtocolVersion
}
async function fetchLatest () {
if (!fs.existsSync('./results.json')) cp.execSync(`curl -L ${latestVesionEndpoint} -o results.json`, { stdio: 'inherit', shell: true })
const json = require('./results.json')
const result = json.results[0]
// console.log(json)
if (!fs.existsSync('./index.d.ts')) cp.execSync('curl -LO https://raw.githubusercontent.com/PrismarineJS/bedrock-protocol/master/index.d.ts', { stdio: 'inherit', shell: true })
const currentApi = fs.readFileSync('./index.d.ts', 'utf-8')
const supportedVersions = currentApi.match(/type Version = ([^\n]+)/)[1].replace(/\||'/g, ' ').split(' ').map(k => k.trim()).filter(k => k.length)
console.log(supportedVersions)
let { version, currentVersionReleaseDate, releaseNotes } = result
console.log(version, currentVersionReleaseDate, releaseNotes)
const title = `Support Minecraft ${result.version}`
const issueStatus = await helper.getIssueStatus(title)
if (supportedVersions.includes(version)) {
if (issueStatus.open) {
helper.close(issueStatus.id, `Closing as ${version} is now supported`)
}
console.log('Latest version is supported.')
return
}
if (issueStatus.closed) {
// We already made an issue, but someone else already closed it, don't do anything else
console.log('I already made an issue, but it was closed')
return
}
version = version.replace('.0', '')
const issuePayload = buildFirstIssue(title, result, {
PocketMine: getCommitsInRepo('pmmp/PocketMine-MP', version, currentVersionReleaseDate),
gophertunnel: getCommitsInRepo('Sandertv/gophertunnel', version, currentVersionReleaseDate),
CloudburstMC: getCommitsInRepo('CloudburstMC/Protocol', version, currentVersionReleaseDate)
})
if (issueStatus.open) {
helper.updateIssue(issueStatus.id, issuePayload)
} else {
helper.createIssue(issuePayload)
}
fs.writeFileSync('./issue.md', issuePayload.body)
console.log('OK, wrote to ./issue.md', issuePayload)
}
fetchLatest()

View file

@ -14,8 +14,6 @@ jobs:
strategy:
matrix:
node-version: [14.x]
env:
FORCE_BUILD: true
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}

24
.github/workflows/update-helper.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: Update Helper
on:
workflow_dispatch:
schedule:
- cron: "0 */2 * * *"
jobs:
helper:
name: update-checker
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@master
- name: Set up Node.js
uses: actions/setup-node@master
with:
node-version: 16.0.0
- name: Install Github Actions toolkit
run: npm i @actions/github
# The env vars contain the relevant trigger information, so we don't need to pass it
- name: Runs helper
run: cd .github/helper-bot && node index.js
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}