Skip to content

Commit

Permalink
feat(node): support node 20 in tasks
Browse files Browse the repository at this point in the history
Use Node 20 using microsoft guidance: https://learn.microsoft.com/en-us/azure/devops/extend/develop/add-build-task?view=azure-devops#q-how-can-i-upgrade-my-custom-task-to-the-latest-node

Keep Node 10 as a fallback.

Adding support requires a hacky patch to fix shell.js, which doesn't support bundlers.
Mitigates the issue described in aws#539

Addresses aws#566

Credit to ivanduplenskikh:  ivanduplenskikh#1

Co-authored-by: Ivan Duplenskikh <[email protected]>
  • Loading branch information
hayemaxi and ivanduplenskikh committed Nov 25, 2024
1 parent f4b9ae1 commit f05199a
Show file tree
Hide file tree
Showing 26 changed files with 295 additions and 308 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Feature",
"description": "Tasks now support Node 20"
}
11 changes: 2 additions & 9 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
{
"files.exclude": {
"build": true,
"package": true,
"package-lock.json": true,
".vscode": true
},
"files.exclude": {},
"search.exclude": {
"build": true,
"package": true,
".vscode": true
"package": true
},
"json.schemas": [
{
Expand Down
87 changes: 65 additions & 22 deletions build-scripts/packageExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,57 @@ interface CommandLineOptions {
publisher?: string
}

const shelljsRootPath = path.resolve(process.cwd(), './node_modules/shelljs/')
const shelljsEntryPath = path.join(shelljsRootPath, 'shell.js')
/**
* Patch shelljs, because it is not compatible with esbuild
* More info: https://github.com/aws/aws-toolkit-azure-devops/pull/539
*/
class ShelljsPatch {
private originalContent: string | undefined
private isPatched = false

patch() {
const shelljsRootPath = path.resolve(process.cwd(), './node_modules/shelljs/')
const sourceRequireString =
"require('./commands').forEach(function (command) {\n require('./src/' + command);\n});"
const originalContent = fs.readFileSync(shelljsEntryPath, 'utf-8')

// eslint-disable-next-line @typescript-eslint/no-var-requires
const fixedRequireString = require(path.join(shelljsRootPath, 'commands.js'))
.map((command: string) => `require('./src/${command}.js');`)
.join('\n')

const patchedContent = originalContent.replace(sourceRequireString, fixedRequireString)
if (originalContent === patchedContent) {
throw new Error('Could not patch shelljs, was this npm package updated?')
}

fs.writeFileSync(shelljsEntryPath, patchedContent)

this.isPatched = true
this.originalContent = originalContent
}

unpatch() {
if (this.isPatched && this.originalContent) {
fs.writeFileSync(shelljsEntryPath, this.originalContent)
this.isPatched = false
this.originalContent = undefined
}
}
}
const shelljsPatch = new ShelljsPatch()

function findMatchingFiles(directory: string) {
return fs.readdirSync(directory)
}

function installNodePackages(directory: string) {
fs.mkdirpSync(directory)
const npmCmd = `npm install --prefix ${directory} azure-pipelines-task-lib --only=production`
try {
const output = ncp.execSync(npmCmd)
console.log(output.toString('utf8'))
} catch (err) {
console.error(err.output ? err.output.toString() : err?.message)
process.exit(1)
}
const output = ncp.execSync(npmCmd)
console.log(output.toString('utf8'))
}

function generateGitHashFile() {
Expand Down Expand Up @@ -69,6 +106,8 @@ function packagePlugin(options: CommandLineOptions) {
// get required npm packages that will be copied
installNodePackages(npmFolder)

shelljsPatch.patch()

// clean, dedupe and pack each task as needed
findMatchingFiles(folders.sourceTasks).forEach(function(taskName) {
console.log('Processing task ' + taskName)
Expand Down Expand Up @@ -111,22 +150,19 @@ function packagePlugin(options: CommandLineOptions) {
const inputFilename = path.join(taskBuildFolder, taskName + '.runner.js')

console.log('packing node-based task')
try {
const result = esbuild.buildSync({
entryPoints: [inputFilename],
bundle: true,
platform: 'node',
target: ['node10'],
minify: true,
outfile: `${taskPackageFolder}/${taskName}.js`
})
result.warnings.forEach(warning => console.log(warning))
} catch (err) {
console.error(err.output ? err.output.toString() : err.message)
process.exit(1)
}
const result = esbuild.buildSync({
entryPoints: [inputFilename],
bundle: true,
platform: 'node',
target: ['node10', 'node20'],
minify: true,
outfile: `${taskPackageFolder}/${taskName}.js`
})
result.warnings.forEach(warning => console.log(warning))
})

shelljsPatch.unpatch()

console.log('Creating deployment vsix')

const binName = os.platform() === 'win32' ? `tfx.cmd` : 'tfx'
Expand Down Expand Up @@ -156,5 +192,12 @@ const parsedOptions: CommandLineOptions = {}
if (commandLineInput.length > 0 && commandLineInput[0].split('=')[0] === 'publisher') {
parsedOptions.publisher = commandLineInput[0].split('=')[1]
}
packagePlugin(parsedOptions)

try {
packagePlugin(parsedOptions)
} catch (e) {
shelljsPatch.unpatch()
throw e
}

console.timeEnd(timeMessage)
Loading

0 comments on commit f05199a

Please sign in to comment.