Build LMS Scheduler #105
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build LMS Scheduler | |
on: | |
workflow_dispatch: | |
schedule: | |
- cron: '40 2 * * *' | |
jobs: | |
check: | |
name: Check whether build is needed | |
if: ${{ github.repository_owner == 'LMS-Community' || github.event_name == 'workflow_dispatch' }} | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/github-script@v7 | |
with: | |
script: | | |
const repoStatus = await github.request('GET https://lms-community.github.io/lms-server-repository/servers.json'); | |
if (repoStatus.status !== 200) { | |
return false; | |
} | |
// get the oldest timestamp for each version from previous builds | |
const candidates = []; | |
Object.keys(repoStatus.data).forEach(version => { | |
const matches = version.match(/(\d+\.\d+)\.\d+/); | |
if (matches && matches.length == 2) { | |
const versionBuilds = repoStatus.data[version]; | |
candidates.push({ | |
v: matches[1], | |
r: Object.keys(versionBuilds).reduce((accumulator, build) => { | |
const buildInfo = versionBuilds[build]; | |
accumulator = accumulator || parseInt(buildInfo.revision); | |
return Math.min(accumulator, parseInt(buildInfo.revision)); | |
}, 0) | |
}) | |
} | |
else { | |
delete repoStatus.data[version]; | |
} | |
}); | |
const sleep = (s) => { | |
return new Promise(resolve => setTimeout(resolve, s * 1000)); | |
} | |
// for each version see whether there's a more recent commit than the revision of the previous build | |
let buildsRunning = 0; | |
for (let i = 0; i < candidates.length; i++) { | |
const latestBuildTimestamp = candidates[i].r * 1000; | |
const commitStatus = await github.rest.repos.listCommits({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
sha: 'public/' + candidates[i].v, | |
per_page: 1, | |
sort: 'created', | |
order: 'asc', | |
}); | |
if (commitStatus.status !== 200) { | |
console.log(JSON.stringify(commitStatus, null, 2)); | |
continue; | |
} | |
// see whether there's really been a commit since that timestamp - above "since" would be inclusive | |
const needsBuild = commitStatus.data.find(commit => new Date(commit.commit.committer.date).getTime() > latestBuildTimestamp); | |
if (needsBuild) { | |
console.log(`${candidates[i].v}: needs a build (${new Date(needsBuild.commit.committer.date).getTime()} > ${latestBuildTimestamp})`); | |
if (buildsRunning > 0) { | |
console.log('Delaying build as there is already a build running'); | |
// wait about Xs per build | |
await sleep(buildsRunning * 90); | |
} | |
const workflowStatus = await github.rest.actions.createWorkflowDispatch({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
workflow_id: '00_build.yaml', | |
ref: 'public/' + candidates[i].v, | |
inputs: { | |
branch: 'public/' + candidates[i].v, | |
build_type: 'nightly', | |
}, | |
}); | |
if (workflowStatus.status < 200 || workflowStatus.status > 204) { | |
console.log(workflowStatus); | |
} | |
buildsRunning++; | |
} | |
else { | |
console.log(`${candidates[i].v}: is up to date (${candidates[i].r})`); | |
} | |
} |