Merge pull request #25 from SpraxDev/prepare-v1
Prepare for v1 * Use SpraxDev/Spgito-BuildTools by default * Allow choosing between SpraxDev and SpigotMC BuildTools * Improve logging and error handling * Fix build being skipped when only one version should be build * README.md: Fixed typos and updated description * Improve GitHub-Actions
This commit is contained in:
commit
fc9adaeb2e
|
@ -10,24 +10,43 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- run: |
|
- name: Install dependencies and build
|
||||||
|
run: |
|
||||||
npm i
|
npm i
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
# Make sure the action works on a clean machine without building
|
# Make sure the action works on a clean machine without building it
|
||||||
run:
|
run:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: ./
|
|
||||||
|
- name: Compile 2 spigot version
|
||||||
|
uses: ./
|
||||||
with:
|
with:
|
||||||
versions: latest, 1.8
|
versions: latest, 1.8
|
||||||
|
|
||||||
|
# Run again. The Action should detect that the requested versions are already inside the local maven repo
|
||||||
|
- name: Compile the same versions agains
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
# These versions should match the ones above
|
||||||
|
versions: latest, 1.8
|
||||||
|
|
||||||
|
- name: Upload logs
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: /tmp/SpraxDev-Action-SpigotMC/logs/
|
||||||
|
|
||||||
# Run the original BuildTools in GitHub Actions to easily compare the build times etc.
|
# Run the original BuildTools in GitHub Actions to easily compare the build times etc.
|
||||||
original-run:
|
original-run:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Run original Spigot-BuildTools
|
- name: Run original Spigot-BuildTools
|
||||||
|
# These versions should match the ones from the 'run'-job
|
||||||
|
# Using '--compile Spigot' as this action does the same by default
|
||||||
run: |
|
run: |
|
||||||
wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O BuildTools.jar
|
wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O BuildTools.jar
|
||||||
java -jar BuildTools.jar --rev latest --compile Spigot
|
java -jar BuildTools.jar --rev latest --compile Spigot
|
||||||
|
|
22
README.md
22
README.md
|
@ -18,10 +18,14 @@
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# Action-Spigot
|
# Action-SpigotMC
|
||||||
This Action allows you to easily compile Minecraft Spigot
|
This Action allows you to easily compile Minecraft Spigot or Paper
|
||||||
and install it in your runners local maven repository.
|
and install it in your runners local maven repository.
|
||||||
|
|
||||||
|
Supported:
|
||||||
|
* SpigotMC (using official BuildTools or my modified one)
|
||||||
|
* ~~PaperMC~~ (coming soon #26)
|
||||||
|
|
||||||
You configure all the versions you want, and it'll compile all the missing versions automatically.
|
You configure all the versions you want, and it'll compile all the missing versions automatically.
|
||||||
By checking for a file in the local maven repository beforehand, build times can be reduces drastically.
|
By checking for a file in the local maven repository beforehand, build times can be reduces drastically.
|
||||||
|
|
||||||
|
@ -37,7 +41,7 @@ If you don't change them, you can remove them from your workflow,
|
||||||
as they are set automatically.
|
as they are set automatically.
|
||||||
|
|
||||||
```YAML
|
```YAML
|
||||||
- uses: SpraxDev/Action-Spigot@v1
|
- uses: SpraxDev/Action-SpigotMC@v1
|
||||||
with:
|
with:
|
||||||
# A comma-separated list of Spigot version that should be compiled
|
# A comma-separated list of Spigot version that should be compiled
|
||||||
# These values are later given to the BuildTools.jar as '--rev' argument
|
# These values are later given to the BuildTools.jar as '--rev' argument
|
||||||
|
@ -45,13 +49,6 @@ as they are set automatically.
|
||||||
# Example: latest, 1.14.4, 1.8.8
|
# Example: latest, 1.14.4, 1.8.8
|
||||||
versions: latest
|
versions: latest
|
||||||
|
|
||||||
# A comma-separated list of build targets
|
|
||||||
# This value is later given to the BuildTools.jar as '--compile' argument
|
|
||||||
#
|
|
||||||
# Available: None, Spigot, CraftBukkit
|
|
||||||
# Example: Spigot, CraftBukkit
|
|
||||||
target: Spigot
|
|
||||||
|
|
||||||
# Should sources be generated?
|
# Should sources be generated?
|
||||||
# If enabled, BuildTools is provided the '--generate-source' argument
|
# If enabled, BuildTools is provided the '--generate-source' argument
|
||||||
generateSrc: false
|
generateSrc: false
|
||||||
|
@ -72,4 +69,9 @@ as they are set automatically.
|
||||||
# The amount of builds allowed to run at the same time
|
# The amount of builds allowed to run at the same time
|
||||||
# Set to '-1' to use system's cpu core count
|
# Set to '-1' to use system's cpu core count
|
||||||
threads: -1
|
threads: -1
|
||||||
|
|
||||||
|
# You can choose between different BuildTools to be used by this action
|
||||||
|
# 'SpraxDev' is my fork of SpigotMC's that introduces some changes (https://github.com/SpraxDev/Spigot-BuildTools/#breaking-changes)
|
||||||
|
# Available: SpraxDev, SpigotMC
|
||||||
|
buildToolProvider: SpraxDev
|
||||||
```
|
```
|
12
action.yml
12
action.yml
|
@ -1,5 +1,5 @@
|
||||||
name: Compile Minecraft Spigot (BuildTools)
|
name: Compile Minecraft Spigot or Paper (BuildTools)
|
||||||
description: Makes it easier to compile multiple Spigot versions at the same time and speed up clean builds
|
description: Makes it easier to compile multiple Spigot/Paper versions at the same time and speed up clean builds
|
||||||
author: Christian Koop
|
author: Christian Koop
|
||||||
|
|
||||||
branding:
|
branding:
|
||||||
|
@ -11,10 +11,6 @@ inputs:
|
||||||
required: false
|
required: false
|
||||||
default: latest
|
default: latest
|
||||||
description: Versions to build (sperate multiple with ',')
|
description: Versions to build (sperate multiple with ',')
|
||||||
target:
|
|
||||||
required: false
|
|
||||||
default: Spigot
|
|
||||||
description: Select what exactly you want to compile (none, Spigot, CraftBukkit) (sperate multiple with ',')
|
|
||||||
generateSrc:
|
generateSrc:
|
||||||
required: false
|
required: false
|
||||||
default: 'false'
|
default: 'false'
|
||||||
|
@ -35,6 +31,10 @@ inputs:
|
||||||
required: false
|
required: false
|
||||||
default: '-1'
|
default: '-1'
|
||||||
description: The amount of builds allowed to run at a time, set to '-1' to use system's cpu count
|
description: The amount of builds allowed to run at a time, set to '-1' to use system's cpu count
|
||||||
|
buildToolProvider:
|
||||||
|
required: false
|
||||||
|
default: SpraxDev
|
||||||
|
description: Whose BuildTool should be used? (SpraxDev [default], SpigotMC)
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: node12
|
using: node12
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -33,12 +33,14 @@
|
||||||
"@actions/core": "^1.2.6",
|
"@actions/core": "^1.2.6",
|
||||||
"async": "^3.2.0",
|
"async": "^3.2.0",
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^9.0.1",
|
||||||
"read-last-lines": "^1.7.2"
|
"n-readlines": "^1.0.1",
|
||||||
|
"xml-js": "^1.6.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node12": "^1.0.7",
|
"@tsconfig/node12": "^1.0.7",
|
||||||
"@types/async": "^3.2.4",
|
"@types/async": "^3.2.4",
|
||||||
"@types/fs-extra": "^9.0.4",
|
"@types/fs-extra": "^9.0.4",
|
||||||
|
"@types/n-readlines": "^1.0.1",
|
||||||
"@types/node": "~12.19.6",
|
"@types/node": "~12.19.6",
|
||||||
"@vercel/ncc": "^0.25.1",
|
"@vercel/ncc": "^0.25.1",
|
||||||
"ts-node": "^9.0.0",
|
"ts-node": "^9.0.0",
|
||||||
|
|
|
@ -30,6 +30,15 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/n-readlines": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/n-readlines/-/n-readlines-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-n1ND4k+9hgtil2HnHK+1tIj1UWchsD+RwoH7eVQqLbUe8AxwLuqDEnx3Riq+twHoMTjP80Q/ilB3LGdyXKfTEg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "12.19.6",
|
"version": "12.19.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.6.tgz",
|
||||||
|
@ -42,11 +51,6 @@
|
||||||
"integrity": "sha512-dGecC5+1wLof1MQpey4+6i2KZv4Sfs6WfXkl9KfO32GED4ZPiKxRfvtGPjbjZv0IbqMl6CxtcV1RotXYfd5SSA==",
|
"integrity": "sha512-dGecC5+1wLof1MQpey4+6i2KZv4Sfs6WfXkl9KfO32GED4ZPiKxRfvtGPjbjZv0IbqMl6CxtcV1RotXYfd5SSA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"any-promise": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
|
||||||
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
|
|
||||||
},
|
|
||||||
"arg": {
|
"arg": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||||
|
@ -113,28 +117,15 @@
|
||||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mz": {
|
"n-readlines": {
|
||||||
"version": "2.7.0",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/n-readlines/-/n-readlines-1.0.1.tgz",
|
||||||
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
"integrity": "sha512-z4SyAIVgMy7CkgsoNw7YVz40v0g4+WWvvqy8+ZdHrCtgevcEO758WQyrYcw3XPxcLxF+//RszTz/rO48nzD0wQ=="
|
||||||
"requires": {
|
|
||||||
"any-promise": "^1.0.0",
|
|
||||||
"object-assign": "^4.0.1",
|
|
||||||
"thenify-all": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"sax": {
|
||||||
"version": "4.1.1",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||||
},
|
|
||||||
"read-last-lines": {
|
|
||||||
"version": "1.7.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/read-last-lines/-/read-last-lines-1.7.2.tgz",
|
|
||||||
"integrity": "sha512-K0yUvTYAYn6qpyLJufaJ7yC6BeL23qpgZ8SKM7/fA1R1rHotCDxB/zDp9i1I2JHvexWBW6/35jkt07iiIKKp4g==",
|
|
||||||
"requires": {
|
|
||||||
"mz": "^2.7.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
|
@ -152,22 +143,6 @@
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"thenify": {
|
|
||||||
"version": "3.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
|
||||||
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
|
|
||||||
"requires": {
|
|
||||||
"any-promise": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"thenify-all": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
|
||||||
"integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
|
|
||||||
"requires": {
|
|
||||||
"thenify": ">= 3.1.0 < 4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz",
|
||||||
|
@ -192,6 +167,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
|
||||||
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
|
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
|
||||||
},
|
},
|
||||||
|
"xml-js": {
|
||||||
|
"version": "1.6.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
||||||
|
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
|
||||||
|
"requires": {
|
||||||
|
"sax": "^1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"yn": {
|
"yn": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||||
|
|
|
@ -33,12 +33,14 @@
|
||||||
"@actions/core": "^1.2.6",
|
"@actions/core": "^1.2.6",
|
||||||
"async": "^3.2.0",
|
"async": "^3.2.0",
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^9.0.1",
|
||||||
"read-last-lines": "^1.7.2"
|
"n-readlines": "^1.0.1",
|
||||||
|
"xml-js": "^1.6.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node12": "^1.0.7",
|
"@tsconfig/node12": "^1.0.7",
|
||||||
"@types/async": "^3.2.4",
|
"@types/async": "^3.2.4",
|
||||||
"@types/fs-extra": "^9.0.4",
|
"@types/fs-extra": "^9.0.4",
|
||||||
|
"@types/n-readlines": "^1.0.1",
|
||||||
"@types/node": "~12.19.6",
|
"@types/node": "~12.19.6",
|
||||||
"@vercel/ncc": "^0.25.1",
|
"@vercel/ncc": "^0.25.1",
|
||||||
"ts-node": "^9.0.0",
|
"ts-node": "^9.0.0",
|
||||||
|
|
287
src/index.ts
287
src/index.ts
|
@ -1,130 +1,225 @@
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import { join as joinPath, resolve as resolvePath } from 'path';
|
|
||||||
import { copy } from 'fs-extra';
|
|
||||||
import { rmdirSync } from 'fs';
|
|
||||||
|
|
||||||
import { cpuCount, downloadFile, exit, fixArgArr, isNumeric, resetWorkingDir, runCmd } from './utils';
|
|
||||||
import { parallelLimit } from 'async';
|
import { parallelLimit } from 'async';
|
||||||
|
import { createWriteStream, existsSync, rmdirSync } from 'fs';
|
||||||
|
import { copy } from 'fs-extra';
|
||||||
|
import { join as joinPath, resolve as resolvePath } from 'path';
|
||||||
|
import { xml2js } from 'xml-js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
cpuCount,
|
||||||
|
downloadFile,
|
||||||
|
exit,
|
||||||
|
fixArgArr,
|
||||||
|
isNumeric,
|
||||||
|
readLastLines,
|
||||||
|
resetWorkingDir,
|
||||||
|
runCmd,
|
||||||
|
userHomeDir
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
const rll = require('read-last-lines');
|
const supportedBuildTools: { [key: string]: { url: string, prepareArgs: string[] } } = {
|
||||||
|
spraxdev: {
|
||||||
|
url: 'https://github.com/SpraxDev/Spigot-BuildTools/releases/latest/download/BuildTools.jar',
|
||||||
|
prepareArgs: ['--exit-after-fetch']
|
||||||
|
},
|
||||||
|
spigotmc: {
|
||||||
|
url: 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar',
|
||||||
|
prepareArgs: ['--compile', 'None']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* GitHub Actions inputs */
|
/* GitHub Actions inputs */
|
||||||
const versions: string[] = fixArgArr((core.getInput('versions') || 'latest').split(','));
|
const buildToolProvider: string = (core.getInput('buildToolProvider') || 'SpraxDev').toLowerCase();
|
||||||
const target: string[] = fixArgArr((core.getInput('target') || 'Spigot').toUpperCase().split(','));
|
let versions: string[] = fixArgArr((core.getInput('versions') || 'latest').toLowerCase().split(','));
|
||||||
const generateSrc: boolean = core.getInput('generateSrc') == 'true';
|
const generateSrc: boolean = core.getInput('generateSrc') == 'true';
|
||||||
const generateDoc: boolean = core.getInput('generateDoc') == 'true';
|
const generateDoc: boolean = core.getInput('generateDoc') == 'true';
|
||||||
const disableJavaCheck: boolean = core.getInput('disableJavaCheck') == 'true';
|
const disableJavaCheck: boolean = core.getInput('disableJavaCheck') == 'true';
|
||||||
|
|
||||||
const forceRun: boolean = core.getInput('forceRun') == 'true'; // TODO
|
const forceRun: boolean = core.getInput('forceRun') == 'true';
|
||||||
const threadCount: number = isNumeric(core.getInput('threads')) ? parseInt(core.getInput('threads')) : cpuCount;
|
const threadCount: number = isNumeric(core.getInput('threads')) ? parseInt(core.getInput('threads')) : cpuCount;
|
||||||
|
|
||||||
const workingDir = resetWorkingDir();
|
const workingDir = resetWorkingDir();
|
||||||
|
const appLogFile = joinPath(workingDir.logs, 'SpraxDev_Actions-SpigotMC.log');
|
||||||
|
const appLogStream = createWriteStream(appLogFile, {encoding: 'utf-8', flags: 'a' /* append */});
|
||||||
|
|
||||||
async function run(): Promise<{ code: number, msg?: string }> {
|
async function run(): Promise<{ code: number, msg?: string }> {
|
||||||
return new Promise<{ code: number, msg?: string }>(async (resolve, reject): Promise<void> => {
|
return new Promise(async (resolve, reject): Promise<void> => {
|
||||||
if (versions.length == 0) return resolve({code: 0, msg: 'No version(s) provided to build'});
|
try {
|
||||||
if (target.length == 0) return resolve({code: 0, msg: 'No target(s) provided to build'});
|
if (versions.length == 0) return resolve({code: 0, msg: 'No version(s) provided to build'});
|
||||||
|
|
||||||
const appLogFile = joinPath(workingDir.logs, 'SpraxDev_Actions-SpigotMC.log');
|
if (!Object.keys(supportedBuildTools).includes(buildToolProvider)) {
|
||||||
|
return reject(new Error(`'${buildToolProvider}' is not a valid BuildTool-Provider (${Object.keys(supportedBuildTools).join(', ')})`));
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Installed Java-Version:');
|
if (!forceRun) {
|
||||||
await runCmd('java', ['-version'], workingDir.base, appLogFile);
|
versions = await removeExistingVersions(versions, (ver, jarPath) => {
|
||||||
|
logInfo(`Skipping version '${ver}' because it has been found in the local maven repository: ${jarPath}`);
|
||||||
|
});
|
||||||
|
|
||||||
console.log(`Downloading BuildTools.jar from 'hub.spigotmc.org'...`);
|
if (versions.length == 0) return resolve({code: 0, msg: 'No new versions to build'});
|
||||||
await downloadFile('https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar', joinPath(workingDir.cache, 'BuildTools.jar'));
|
}
|
||||||
|
|
||||||
const gotTemplateDirectory = versions.length != 1;
|
const buildTool = supportedBuildTools[buildToolProvider];
|
||||||
|
|
||||||
// Prepare template directory if more than one version is provided
|
logInfo('Installed Java-Version:');
|
||||||
if (gotTemplateDirectory) {
|
await runCmd('java', ['-version'], workingDir.base, appLogStream);
|
||||||
console.log('Prepare for future tasks by running BuildTools...');
|
|
||||||
|
logInfo(`\nDownloading '${buildTool.url}'...`);
|
||||||
|
await downloadFile(buildTool.url, joinPath(workingDir.cache, 'BuildTools.jar'));
|
||||||
|
|
||||||
|
const gotTemplateDirectory = versions.length != 1;
|
||||||
|
|
||||||
|
// Prepare template directory if more than one version is provided
|
||||||
|
if (gotTemplateDirectory) {
|
||||||
|
logInfo('Prepare for future tasks by running BuildTools...');
|
||||||
|
|
||||||
|
await core.group('Prepare BuildTools', async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
return runCmd('java', ['-jar', 'BuildTools.jar', (disableJavaCheck ? '--disable-java-check' : ''), ...buildTool.prepareArgs],
|
||||||
|
workingDir.cache, appLogStream);
|
||||||
|
} catch (err) {
|
||||||
|
logError(err);
|
||||||
|
|
||||||
|
logError(`\nPrinting last 30 lines from '${resolvePath(appLogFile)}':`);
|
||||||
|
for (const line of readLastLines(appLogFile, 30)) {
|
||||||
|
logError(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildToolsArgs = ['-jar', 'BuildTools.jar', '--compile', 'Spigot'];
|
||||||
|
|
||||||
|
if (generateSrc) {
|
||||||
|
buildToolsArgs.push('--generate-source');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generateDoc) {
|
||||||
|
buildToolsArgs.push('--generate-docs');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disableJavaCheck) {
|
||||||
|
buildToolsArgs.push('--disable-java-check');
|
||||||
|
}
|
||||||
|
|
||||||
|
const tasks = [];
|
||||||
|
for (const ver of versions) {
|
||||||
|
tasks.push(async (): Promise<void> => {
|
||||||
|
return new Promise(async (resolveTask, rejectTask): Promise<void> => {
|
||||||
|
const start = Date.now();
|
||||||
|
|
||||||
|
const logFile = joinPath(workingDir.logs, `${ver}.log`);
|
||||||
|
|
||||||
|
logInfo(`Building version '${ver}'...`);
|
||||||
|
|
||||||
|
// If there is only one version to build, the cache directory is used instead of copying it first
|
||||||
|
const versionDir = gotTemplateDirectory ? joinPath(workingDir.base, `${ver}`) : workingDir.cache;
|
||||||
|
|
||||||
|
if (gotTemplateDirectory) {
|
||||||
|
await copy(workingDir.cache, versionDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// set to silent because multiple builds can run at once
|
||||||
|
await runCmd('java', [...buildToolsArgs, '--rev', ver], versionDir, logFile, true);
|
||||||
|
|
||||||
|
if (gotTemplateDirectory) {
|
||||||
|
rmdirSync(versionDir, {recursive: true}); // delete our task dir
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = Date.now();
|
||||||
|
|
||||||
|
logInfo(`Finished '${ver}' in ${((end - start) / 60_000).toFixed(2)} minutes`);
|
||||||
|
resolveTask();
|
||||||
|
} catch (err) {
|
||||||
|
logInfo(`An error occurred while building '${ver}'`);
|
||||||
|
logError(err);
|
||||||
|
|
||||||
|
logError(`\nPrinting last 30 lines from '${resolvePath(logFile)}':`);
|
||||||
|
|
||||||
|
for (const line of readLastLines(logFile, 30)) {
|
||||||
|
logError(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
rejectTask(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
parallelLimit(tasks, threadCount, (err) => {
|
||||||
|
if (err) return reject(err);
|
||||||
|
|
||||||
|
resolve({code: 0});
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeExistingVersions(versionArr: string[], onExist: (ver: string, jarPath: string) => void): Promise<string[]> {
|
||||||
|
return new Promise(async (resolve, _reject): Promise<void> => {
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
for (const ver of versionArr) {
|
||||||
|
let skipVersion = false;
|
||||||
|
let versionToCheck: string | null = ver != 'latest' ? ver : null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await core.group('Prepare BuildTools', async (): Promise<void> => {
|
const verJsonBuff = await downloadFile(`https://hub.spigotmc.org/versions/${ver}.json`, null);
|
||||||
return runCmd('java', ['-jar', 'BuildTools.jar', '--compile', 'NONE', (disableJavaCheck ? '--disable-java-check' : '')],
|
const verJson = verJsonBuff instanceof Buffer ? JSON.parse(verJsonBuff.toString('utf-8')) : null;
|
||||||
workingDir.cache, appLogFile);
|
const bukkitRef: undefined | string = verJson?.refs?.Bukkit;
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
|
|
||||||
console.error(`\nPrinting last 25 lines from '${resolvePath(appLogFile)}':`);
|
if (bukkitRef) {
|
||||||
for (const line of (await rll.read(appLogFile, 25))) {
|
const verPomBuff = await downloadFile(`https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/raw/pom.xml?at=${bukkitRef}`, null);
|
||||||
console.error(line);
|
|
||||||
|
if (verPomBuff instanceof Buffer) {
|
||||||
|
const result = xml2js(verPomBuff.toString('utf-8'), {
|
||||||
|
compact: true,
|
||||||
|
ignoreComment: true,
|
||||||
|
ignoreAttributes: true
|
||||||
|
}) as any;
|
||||||
|
|
||||||
|
versionToCheck = result.project?.version?._text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logError(err);
|
||||||
|
}
|
||||||
|
|
||||||
return exit(1);
|
const jarPath = resolvePath(joinPath(userHomeDir, `/.m2/repository/org/spigotmc/spigot/${versionToCheck}/spigot-${versionToCheck}.jar`));
|
||||||
|
if (versionToCheck) {
|
||||||
|
skipVersion = existsSync(jarPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipVersion) {
|
||||||
|
onExist(ver, jarPath);
|
||||||
|
} else {
|
||||||
|
result.push(ver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildToolsArgs = ['-jar', 'BuildTools.jar', '--compile', target.join(',')];
|
resolve(result);
|
||||||
|
|
||||||
if (generateSrc) {
|
|
||||||
buildToolsArgs.push('--generate-source');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (generateDoc) {
|
|
||||||
buildToolsArgs.push('--generate-docs');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disableJavaCheck) {
|
|
||||||
buildToolsArgs.push('--disable-java-check');
|
|
||||||
}
|
|
||||||
|
|
||||||
const tasks = [];
|
|
||||||
for (const ver of versions) {
|
|
||||||
tasks.push((callback: (err?: Error, result?: unknown) => void) => {
|
|
||||||
try {
|
|
||||||
const start = Date.now();
|
|
||||||
|
|
||||||
const logFile = joinPath(workingDir.logs, `${ver}.log`);
|
|
||||||
|
|
||||||
console.log(`Building version '${ver}'...`);
|
|
||||||
|
|
||||||
// If there is only one version to build, the cache directory is used instead of copying it first
|
|
||||||
const versionDir = gotTemplateDirectory ? joinPath(workingDir.base, `${ver}`) : workingDir.cache;
|
|
||||||
|
|
||||||
if (gotTemplateDirectory) {
|
|
||||||
copy(workingDir.cache, versionDir)
|
|
||||||
.then(() => {
|
|
||||||
runCmd('java', [...buildToolsArgs, '--rev', ver],
|
|
||||||
versionDir, logFile, true) // set to silent because multiple builds can run at once
|
|
||||||
.then(() => {
|
|
||||||
rmdirSync(versionDir, {recursive: true}); // delete our task dir
|
|
||||||
|
|
||||||
const end = Date.now();
|
|
||||||
|
|
||||||
console.log(`Finished building '${ver}' in ${((end - start) / 60_000)} minutes`);
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(`An error occurred while building '${ver}'`);
|
|
||||||
console.error(err);
|
|
||||||
|
|
||||||
console.error(`\nPrinting last 25 lines from '${resolvePath(logFile)}':`);
|
|
||||||
rll.read(logFile, 25)
|
|
||||||
.then((lines: string[]) => {
|
|
||||||
for (const line of lines) {
|
|
||||||
console.error(line);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(console.error)
|
|
||||||
.finally(() => callback(err));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
(parallelLimit(tasks, threadCount) as unknown as Promise<unknown[]>) // Valid according to docs - types outdated?
|
|
||||||
.then(() => resolve({code: 0}))
|
|
||||||
.catch(reject);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function logInfo(msg?: string): void {
|
||||||
|
console.log(msg);
|
||||||
|
appLogStream.write(msg + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logError(msg?: string | object): void {
|
||||||
|
if (typeof msg != 'string') {
|
||||||
|
msg = JSON.stringify(msg, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(msg);
|
||||||
|
appLogStream.write(msg + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
run()
|
run()
|
||||||
.then((result) => exit(result.code, result.msg))
|
.then((result) => exit(result.code, result.msg))
|
||||||
.catch((err) => exit(1, err));
|
.catch((err) => exit(1, err));
|
112
src/utils.ts
112
src/utils.ts
|
@ -1,14 +1,17 @@
|
||||||
import { spawn as spawnProcess } from 'child_process';
|
import { spawn as spawnProcess } from 'child_process';
|
||||||
import { join as joinPath } from 'path';
|
import { createWriteStream, mkdirSync, readFileSync, rmdirSync, WriteStream } from 'fs';
|
||||||
import { get as httpGet } from 'http';
|
import { get as httpGet } from 'http';
|
||||||
import { get as httpsGet } from 'https';
|
import { get as httpsGet } from 'https';
|
||||||
import { cpus, tmpdir } from 'os';
|
import readLines from 'n-readlines';
|
||||||
import { createWriteStream, mkdirSync, readFileSync, rmdirSync, WriteStream } from 'fs';
|
import { cpus, homedir, tmpdir } from 'os';
|
||||||
|
import { join as joinPath } from 'path';
|
||||||
|
import { logError, logInfo } from './index';
|
||||||
|
|
||||||
const packageJson = JSON.parse(readFileSync(joinPath(__dirname, '..', 'package.json'), 'utf-8'));
|
const packageJson = JSON.parse(readFileSync(joinPath(__dirname, '..', 'package.json'), 'utf-8'));
|
||||||
const userAgent = `${packageJson.name || 'Action-SpigotMC'}/${packageJson.version || 'UNKNOWN_VERSION'} (+${packageJson.homepage || 'https://github.com/SpraxDev/'})`;
|
const userAgent = `${packageJson.name || 'Action-SpigotMC'}/${packageJson.version || 'UNKNOWN_VERSION'} (+${packageJson.homepage || 'https://github.com/SpraxDev/Action-SpigotMC'})`;
|
||||||
|
|
||||||
export const cpuCount = cpus().length;
|
export const cpuCount = cpus().length;
|
||||||
|
export const userHomeDir = homedir();
|
||||||
|
|
||||||
export function fixArgArr(arr: string[]): string[] {
|
export function fixArgArr(arr: string[]): string[] {
|
||||||
const result: string[] = [];
|
const result: string[] = [];
|
||||||
|
@ -28,9 +31,12 @@ export function isNumeric(str: string): boolean {
|
||||||
return /^[0-9]+$/.test(str);
|
return /^[0-9]+$/.test(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runCmd(cmd: string, args: string[], workingDir: string, logFile: string, silent: boolean = false): Promise<void> {
|
export async function runCmd(cmd: string, args: string[], workingDir: string, logStreamOrFile: string | WriteStream, silent: boolean = false): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const logStream = createWriteStream(logFile, {encoding: 'utf-8', flags: 'a'}); // Use UTF-8 and append when file exists
|
const closeLogStream = typeof logStreamOrFile == 'string';
|
||||||
|
const logStream = typeof logStreamOrFile != 'string' ? logStreamOrFile :
|
||||||
|
createWriteStream(logStreamOrFile, {encoding: 'utf-8', flags: 'a' /* append */});
|
||||||
|
|
||||||
const runningProcess = spawnProcess(cmd, args, {shell: true, cwd: workingDir, env: process.env});
|
const runningProcess = spawnProcess(cmd, args, {shell: true, cwd: workingDir, env: process.env});
|
||||||
|
|
||||||
runningProcess.stdout.on('data', (data) => {
|
runningProcess.stdout.on('data', (data) => {
|
||||||
|
@ -49,7 +55,9 @@ export async function runCmd(cmd: string, args: string[], workingDir: string, lo
|
||||||
});
|
});
|
||||||
|
|
||||||
runningProcess.on('close', (code) => {
|
runningProcess.on('close', (code) => {
|
||||||
logStream.close();
|
if (closeLogStream) {
|
||||||
|
logStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
return reject({err: new Error(`process exited with code ${code}`), cmd, workingDir});
|
return reject({err: new Error(`process exited with code ${code}`), cmd, workingDir});
|
||||||
|
@ -60,48 +68,81 @@ export async function runCmd(cmd: string, args: string[], workingDir: string, lo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadFile(url: string, dest: string): Promise<void> {
|
/**
|
||||||
const getURL = url.toLowerCase().startsWith('http://') ? httpGet : httpsGet;
|
* @param url The URL to fetch the data from
|
||||||
|
* @param dest Set to `null` to get an Buffer instead of writing it to the file system
|
||||||
|
* @param currRedirectDepth Internally used to track how often the function has been redirected
|
||||||
|
*/
|
||||||
|
export async function downloadFile(url: string, dest: string | null, currRedirectDepth: number = 0): Promise<Buffer | void> {
|
||||||
|
const doGetRequest = url.toLowerCase().startsWith('http://') ? httpGet : httpsGet;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let writeStream: WriteStream | null = null;
|
let writeStream: WriteStream | null = null;
|
||||||
|
|
||||||
const done = function (err: boolean) {
|
const done = function (errored: boolean) {
|
||||||
if (writeStream) {
|
if (writeStream) {
|
||||||
writeStream.close();
|
writeStream.close();
|
||||||
writeStream = null;
|
writeStream = null;
|
||||||
|
|
||||||
if (err) {
|
if (errored && dest != null) {
|
||||||
rmdirSync(dest, {recursive: true});
|
rmdirSync(dest, {recursive: true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO
|
doGetRequest(url, {
|
||||||
getURL(url, {
|
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': userAgent
|
'User-Agent': userAgent
|
||||||
}
|
}
|
||||||
}, (httpRes) => {
|
}, (httpRes) => {
|
||||||
if (httpRes.statusCode != 200) {
|
if (httpRes.statusCode != 200) {
|
||||||
done(true);
|
const locHeader = httpRes.headers.location;
|
||||||
|
|
||||||
return reject(new Error(`Server responded with ${httpRes.statusCode}`));
|
// Follow redirect
|
||||||
|
if (currRedirectDepth < 12 && locHeader &&
|
||||||
|
(httpRes.statusCode == 301 || httpRes.statusCode == 302 || httpRes.statusCode == 303 ||
|
||||||
|
httpRes.statusCode == 307 || httpRes.statusCode == 308)) {
|
||||||
|
done(false);
|
||||||
|
|
||||||
|
if (!/https?:\/\//g.test(locHeader)) {
|
||||||
|
return reject(new Error(`Server responded with ${httpRes.statusCode} and a relative Location-Header value (${locHeader})`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return downloadFile(locHeader, dest, ++currRedirectDepth)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
} else {
|
||||||
|
done(true);
|
||||||
|
|
||||||
|
return reject(new Error(`Server responded with ${httpRes.statusCode}`));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeStream = createWriteStream(dest, {encoding: 'binary'})
|
if (dest != null) {
|
||||||
.on('finish', () => {
|
writeStream = createWriteStream(dest, {encoding: 'binary'})
|
||||||
done(false);
|
.on('finish', () => {
|
||||||
|
done(false);
|
||||||
|
|
||||||
return resolve();
|
return resolve();
|
||||||
})
|
})
|
||||||
.on('error', (err) => {
|
.on('error', (err) => {
|
||||||
done(true);
|
done(true);
|
||||||
|
|
||||||
return reject(err);
|
return reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
httpRes.pipe(writeStream);
|
httpRes.pipe(writeStream);
|
||||||
|
} else {
|
||||||
|
const chunks: Buffer[] = [];
|
||||||
|
|
||||||
|
httpRes.on('data', (chunk) => {
|
||||||
|
chunks.push(Buffer.from(chunk, 'binary'));
|
||||||
|
});
|
||||||
|
|
||||||
|
httpRes.on('end', () => {
|
||||||
|
resolve(Buffer.concat(chunks));
|
||||||
|
});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.on('error', (err) => {
|
.on('error', (err) => {
|
||||||
done(true);
|
done(true);
|
||||||
|
@ -111,6 +152,23 @@ export async function downloadFile(url: string, dest: string): Promise<void> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function readLastLines(file: string, lineCount: number, encoding: string = 'utf-8'): string[] {
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
const reader = new readLines(file);
|
||||||
|
|
||||||
|
let line;
|
||||||
|
while (line = reader.next()) {
|
||||||
|
result.push(line.toString(encoding));
|
||||||
|
|
||||||
|
if (result.length > lineCount) {
|
||||||
|
result.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
export function resetWorkingDir(): { base: string, cache: string, logs: string } {
|
export function resetWorkingDir(): { base: string, cache: string, logs: string } {
|
||||||
const baseDir = joinPath(tmpdir(), 'SpraxDev-Action-SpigotMC');
|
const baseDir = joinPath(tmpdir(), 'SpraxDev-Action-SpigotMC');
|
||||||
const cacheDir = joinPath(baseDir, 'cache');
|
const cacheDir = joinPath(baseDir, 'cache');
|
||||||
|
@ -128,9 +186,9 @@ export function resetWorkingDir(): { base: string, cache: string, logs: string }
|
||||||
export function exit(code: number, msg?: string | Error): never {
|
export function exit(code: number, msg?: string | Error): never {
|
||||||
if (msg) {
|
if (msg) {
|
||||||
if (typeof msg == 'string') {
|
if (typeof msg == 'string') {
|
||||||
console.log(msg);
|
logInfo(msg);
|
||||||
} else {
|
} else {
|
||||||
console.error(msg);
|
logError(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue