-
-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Support volta
, asdf
, and package.json engines
for declaring version
#151
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,14 +1,14 @@ | ||||||||||||||||||||||||||||||
import { addPath, exportVariable } from '@actions/core' | ||||||||||||||||||||||||||||||
import { spawn } from 'child_process' | ||||||||||||||||||||||||||||||
import { rm, writeFile, mkdir } from 'fs/promises' | ||||||||||||||||||||||||||||||
import { readFileSync } from 'fs' | ||||||||||||||||||||||||||||||
import { readFileSync, existsSync } from 'fs' | ||||||||||||||||||||||||||||||
import path from 'path' | ||||||||||||||||||||||||||||||
import { execPath } from 'process' | ||||||||||||||||||||||||||||||
import util from 'util' | ||||||||||||||||||||||||||||||
import { Inputs } from '../inputs' | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export async function runSelfInstaller(inputs: Inputs): Promise<number> { | ||||||||||||||||||||||||||||||
const { version, dest, packageJsonFile, standalone } = inputs | ||||||||||||||||||||||||||||||
const { version, versionFilePath, dest, packageJsonFile, standalone } = inputs | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// prepare self install | ||||||||||||||||||||||||||||||
await rm(dest, { recursive: true, force: true }) | ||||||||||||||||||||||||||||||
|
@@ -19,7 +19,7 @@ export async function runSelfInstaller(inputs: Inputs): Promise<number> { | |||||||||||||||||||||||||||||
await writeFile(pkgJson, JSON.stringify({ private: true })) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// prepare target pnpm | ||||||||||||||||||||||||||||||
const target = await readTarget({ version, packageJsonFile, standalone }) | ||||||||||||||||||||||||||||||
const target = await readTarget({ version, versionFilePath, packageJsonFile, standalone }) | ||||||||||||||||||||||||||||||
const cp = spawn(execPath, [path.join(__dirname, 'pnpm.cjs'), 'install', target, '--no-lockfile'], { | ||||||||||||||||||||||||||||||
cwd: dest, | ||||||||||||||||||||||||||||||
stdio: ['pipe', 'inherit', 'inherit'], | ||||||||||||||||||||||||||||||
|
@@ -37,12 +37,71 @@ export async function runSelfInstaller(inputs: Inputs): Promise<number> { | |||||||||||||||||||||||||||||
return exitCode | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// Nearly identical to the function `actions/setup-node` uses. | ||||||||||||||||||||||||||||||
// See https://github.com/actions/setup-node/blob/39370e3970a6d050c480ffad4ff0ed4d3fdee5af/src/util.ts#L8 | ||||||||||||||||||||||||||||||
function getPnpmVersionFromFile(versionFilePath: string) { | ||||||||||||||||||||||||||||||
if (!existsSync(versionFilePath)) { | ||||||||||||||||||||||||||||||
throw new Error( | ||||||||||||||||||||||||||||||
`The specified pnpm version file at: ${versionFilePath} does not exist` | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const contents = readFileSync(versionFilePath, 'utf8') | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// Try parsing the file as a `package.json` file. | ||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||
const manifest = JSON.parse(contents) | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The behavior would be more predictable if you match the extension of |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// Presume package.json file. | ||||||||||||||||||||||||||||||
if (typeof manifest === 'object' && !!manifest) { | ||||||||||||||||||||||||||||||
// Support Volta. | ||||||||||||||||||||||||||||||
// See https://docs.volta.sh/guide/understanding#managing-your-project | ||||||||||||||||||||||||||||||
if (manifest.volta?.pnpm) { | ||||||||||||||||||||||||||||||
return manifest.volta.pnpm as string | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if (manifest.engines?.pnpm) { | ||||||||||||||||||||||||||||||
return manifest.engines.pnpm as string | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
Comment on lines
+59
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, what if both |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// Support Volta workspaces. | ||||||||||||||||||||||||||||||
// See https://docs.volta.sh/advanced/workspaces | ||||||||||||||||||||||||||||||
if (manifest.volta?.extends) { | ||||||||||||||||||||||||||||||
const extendedFilePath = path.resolve( | ||||||||||||||||||||||||||||||
path.dirname(versionFilePath), | ||||||||||||||||||||||||||||||
manifest.volta.extends | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
console.info('Resolving pnpm version from ' + extendedFilePath) | ||||||||||||||||||||||||||||||
return getPnpmVersionFromFile(extendedFilePath) | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// If contents are an object, we parsed JSON | ||||||||||||||||||||||||||||||
// this can happen if pnpm-version-file is a package.json | ||||||||||||||||||||||||||||||
// yet contains no volta.pnpm or engines.pnpm | ||||||||||||||||||||||||||||||
// | ||||||||||||||||||||||||||||||
// If pnpm-version file is _not_ JSON, control flow | ||||||||||||||||||||||||||||||
// will not have reached these lines. | ||||||||||||||||||||||||||||||
// | ||||||||||||||||||||||||||||||
// And because we've reached here, we know the contents | ||||||||||||||||||||||||||||||
// *are* JSON, so no further string parsing makes sense. | ||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||
console.info('pnpm version file is not JSON file') | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const found = contents.match(/^(?:pnpm\s+)?v?(?<version>[^\s]+)$/m) | ||||||||||||||||||||||||||||||
return found?.groups?.version ?? contents.trim() | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
async function readTarget(opts: { | ||||||||||||||||||||||||||||||
readonly version?: string | undefined | ||||||||||||||||||||||||||||||
readonly versionFilePath?: string | undefined | ||||||||||||||||||||||||||||||
readonly packageJsonFile: string | ||||||||||||||||||||||||||||||
readonly standalone: boolean | ||||||||||||||||||||||||||||||
}) { | ||||||||||||||||||||||||||||||
const { version, packageJsonFile, standalone } = opts | ||||||||||||||||||||||||||||||
const { versionFilePath, packageJsonFile, standalone } = opts | ||||||||||||||||||||||||||||||
let { version } = opts | ||||||||||||||||||||||||||||||
happycollision marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
const { GITHUB_WORKSPACE } = process.env | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let packageManager | ||||||||||||||||||||||||||||||
|
@@ -56,6 +115,14 @@ async function readTarget(opts: { | |||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if (typeof versionFilePath === "string" && typeof version === "string") { | ||||||||||||||||||||||||||||||
throw new Error("Multiple version determination methods specified: 'version' and 'version_file_path'. Please specify only one.") | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if (versionFilePath) { | ||||||||||||||||||||||||||||||
version = getPnpmVersionFromFile(versionFilePath) | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if (version) { | ||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||
typeof packageManager === 'string' && | ||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pnpm 4.11.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"engines":{"pnpm":"4.11.1"}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"volta":{"extends":"./package.volta.json"}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"volta":{"pnpm":"4.11.1"}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is problematic.
.tool-versions
andpackage.json
are completely different formats and should be treated as different features.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, the only reason I did it this way was to match up with how they do it for node versioning in the referenced lib. I figure if js devs are familiar with any GitHub actions at all, it’s likely that one.
I’ll rethink the inputs throwing out that goal and come back with something else.
Or not. Heh. If I have the time I will.