Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Changelog

## v3

This version adds **experimental** support for [pnpm](https://pnpm.io/) and
[yarn](https://yarnpkg.com/).

Depending on the package manager and version, the invocation of the `tsx`
command that drives `@github/local-action` is invoked differently.

| Package Manager | Version | Command |
| --------------- | ------- | ----------- |
| `npm` | Any | `npm exec` |
| `pnpm` | Any | `pnpm dlx` |
| `yarn` | `<= 3` | `yarn exec` |
| `yarn` | `>= 4` | `yarn dlx` |

Alongside this, yarn PnP support is implemented via
[unplugging](https://yarnpkg.com/cli/unplug) any modules stubbed by
`@github/local-action` and "re-plugging" after completion of the action run.

This support is still a work in progress. Any feedback or issues are welcome!

## v2

As of version `2.0.0`, the `local-action` tool has been updated to require
**Node.js v20.6.0** or higher. This is necessary to support ESM loaders to
override dependencies in the GitHub Actions Toolkit.

## v1

With the release of `v1.0.0`, there was a need to switch from
[`ts-node`](https://www.npmjs.com/package/ts-node) to
[`tsx`](https://www.npmjs.com/package/tsx). However, the bundled version of
`tsx` is being used, so you should no longer need to install either :grinning:
13 changes: 2 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,9 @@ currently implemented by this tool.
| `@actions/artifact` | `2.2.0` |
| `@actions/core` | `1.11.1` |

## v2 Changes
## Changelog

As of version `2.0.0`, the `local-action` tool has been updated to require
**Node.js v20.6.0** or higher. This is necessary to support ESM loaders to
override dependencies in the GitHub Actions Toolkit.

## v1 Changes

With the release of `v1.0.0`, there was a need to switch from
[`ts-node`](https://www.npmjs.com/package/ts-node) to
[`tsx`](https://www.npmjs.com/package/tsx). However, the bundled version of
`tsx` is being used, so you should no longer need to install either :grinning:
See the [CHANGELOG](./CHANGELOG.md) for a complete list of changes.

## Prerequisites

Expand Down
4 changes: 4 additions & 0 deletions __fixtures__/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import { jest } from '@jest/globals'
export const accessSync = jest.fn()
export const createWriteStream = jest.fn()
export const createReadStream = jest.fn()
export const existsSync = jest.fn()
export const mkdirSync = jest.fn()
export const readFileSync = jest.fn()
export const rmSync = jest.fn()

export default {
accessSync,
createWriteStream,
createReadStream,
existsSync,
mkdirSync,
readFileSync,
rmSync
}
144 changes: 0 additions & 144 deletions __tests__/commands/run.test.ts

This file was deleted.

33 changes: 33 additions & 0 deletions __tests__/utils/package.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { jest } from '@jest/globals'
import * as fs from '../../__fixtures__/fs.js'
import { ResetCoreMetadata } from '../../src/stubs/core/core.js'
import { ResetEnvMetadata } from '../../src/stubs/env.js'

jest.unstable_mockModule('fs', () => fs)

const { isESM } = await import('../../src/utils/package.js')

describe('Package', () => {
beforeEach(() => {
// Reset metadata
ResetEnvMetadata()
ResetCoreMetadata()
})

afterEach(() => {
jest.resetAllMocks()
})

describe('isESM', () => {
it('Returns true for ESM packages', () => {
fs.existsSync.mockReturnValue(true)
fs.readFileSync.mockReturnValue(
JSON.stringify({
type: 'module'
})
)

expect(isESM()).toBe(true)
})
})
})
55 changes: 53 additions & 2 deletions bin/local-action.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ function entrypoint() {
// Disable experimental warnings.
process.env.NODE_NO_WARNINGS = 1

// Start building the command to run local-action.
let command = `npx tsx "${path.join(packagePath, 'src', 'index.ts')}"`
// Start building the command to run local-action. The package manager will
// be prepended to this later.
let command = `tsx "${path.join(packagePath, 'src', 'index.ts')}"`

// If there are no input arguments, or the only argument is the help flag,
// display the help message.
Expand Down Expand Up @@ -74,6 +75,56 @@ function entrypoint() {
command += ` ${arg}`
}

// Starting in the TARGET_ACTION_PATH, locate the package.json file and
// determine the package manager.
const actionPackageDirs = path
.resolve(process.env.TARGET_ACTION_PATH)
.split(path.sep)

while (actionPackageDirs.length > 0) {
const actionPackage = actionPackageDirs.join(path.sep)

// Check if the package.json file exists.
if (fs.existsSync(path.join(actionPackage, 'package.json'))) {
// Read the package.json file.
const json = JSON.parse(
fs.readFileSync(path.join(actionPackage, 'package.json')),
'utf8'
)

// If the package.json file has a packageManager field, set the
// command to use that package manager.
if (json.packageManager?.startsWith('pnpm')) {
process.env.NODE_PACKAGE_MANAGER = 'pnpm'
command = 'pnpm dlx ' + command
} else if (json.packageManager?.startsWith('yarn')) {
process.env.NODE_PACKAGE_MANAGER = 'yarn'

// The older version of yarn does not support `yarn dlx`, so we fall
// back to `yarn exec`.
if (json.packageManager.startsWith('yarn@1'))
command = 'yarn exec ' + command
else command = 'yarn dlx ' + command
} else {
// Otherwise, fall back to npm.
process.env.NODE_PACKAGE_MANAGER = 'npm'
command = 'npm exec ' + command
}

break
}

// Remove the last directory from the path.
actionPackageDirs.pop()
}

if (actionPackage.length === 0) {
console.error(
'No package.json file found in the action directory or any parent directories.'
)
process.exit(1)
}

// Run the command.
execSync(command, { stdio: 'inherit' })
} catch (error) {
Expand Down
4 changes: 3 additions & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ const config: JestConfigWithTsJest = {
coveragePathIgnorePatterns: [
'node_modules',
'src/bootstrap.mts',
'src/types/quibble.d.ts'
'src/types/quibble.d.ts',
'src/commands/run.ts',
'src/stubs/artifact/artifact.ts'
],
coverageReporters: ['json-summary', 'lcov', 'text'],
coverageThreshold: {
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@github/local-action",
"description": "Local Debugging for GitHub Actions",
"version": "2.6.4",
"version": "3.0.0",
"type": "module",
"author": "Nick Alteen <ncalteen@github.com>",
"private": false,
Expand Down
Loading