Skip to content

Commit

Permalink
feat: improved error handling (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
samypr100 authored May 20, 2024
1 parent c77c001 commit a804b2b
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 15 deletions.
42 changes: 35 additions & 7 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: Setup Dev Drive
uses: ./

test-inputs:
test-declare-inputs:
runs-on: windows-2022
steps:
- name: Check out source code
Expand All @@ -64,18 +64,25 @@ jobs:
mount-if-exists: false
workspace-copy: true

test-large-fixed:
test-formats:
strategy:
fail-fast: false
matrix:
drive-format: [ FAT, FAT32, exFAT, NTFS, ReFS ]
runs-on: windows-2022
steps:
- name: Check out source code
uses: actions/checkout@v4
- name: Setup Dev Drive
uses: ./
with:
drive-size: 10GB
drive-type: Fixed
drive-format: ${{ matrix.drive-format }}

test-large-dynamic:
test-large-size:
strategy:
fail-fast: false
matrix:
drive-type: [ Fixed, Dynamic ]
runs-on: windows-2022
steps:
- name: Check out source code
Expand All @@ -84,9 +91,9 @@ jobs:
uses: ./
with:
drive-size: 10GB
drive-type: Dynamic
drive-type: ${{ matrix.drive-type }}

test-path-with-spaces:
test-drive-path-with-spaces:
runs-on: windows-2022
steps:
- name: Check out source code
Expand Down Expand Up @@ -125,6 +132,27 @@ jobs:
if: ${{ !matrix.workspace-copy && steps.setup-drive.outcome != 'success' }}
run: exit 1

test-unsupported-os:
runs-on: ubuntu-latest
steps:
- name: Check out source code
uses: actions/checkout@v4
- name: Setup Dev Drive
uses: ./

test-legacy-runners:
runs-on: windows-2019
steps:
- name: Check out source code
uses: actions/checkout@v4
- name: Setup Dev Drive
id: setup-drive
continue-on-error: true
uses: ./
- name: Fail when failure is not the outcome
if: steps.setup-drive.outcome != 'failure'
run: exit 1

test-cache-storage:
runs-on: windows-2022
steps:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 2.2.0

* Improved error handling feedback.
* Additional CI tests.
* More Badges.

# 2.1.2

* Documentation improvements.
Expand Down
2 changes: 1 addition & 1 deletion dist/cleanup/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/setup/index.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/cleanup-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { dismount } from './vhd-commands'

export async function cleanup(): Promise<void> {
if (process.platform !== WIN_PLATFORM) {
throw new Error('This action can only run on windows.')
core.info('This action can only run on Windows.')
return
}

core.info('Attempting to remove Dev Drive...')
Expand Down
3 changes: 2 additions & 1 deletion src/setup-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ export async function setup(
copyWorkspace: boolean,
): Promise<void> {
if (process.platform !== WIN_PLATFORM) {
throw new Error('This action can only run on windows.')
core.info('This action can only run on Windows.')
return
}
// Normalize User Path Input
let normalizedDrivePath = toPlatformPath(drivePath)
Expand Down
47 changes: 43 additions & 4 deletions src/vhd-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,25 @@ import { compare } from 'compare-versions'
import * as core from '@actions/core'
import fs from 'fs-extra'

const VHDCommandNotFound = (name: string) =>
new Error(
`Failed to detect ${name} command. Hyper-V may not be enabled or you're running an unsupported Windows version.`,
)

export async function dismount(drivePath: string) {
const pathArg = quote([drivePath])
const pwshCommand = `Dismount-VHD -Path ${pathArg}`
const pwshCommandArgs = ['-NoProfile', '-Command', `. {${pwshCommand}}`]

// When running inside `-Command`, `-ErrorAction Stop` will retain the proper exit code
const pwshCommand = `Dismount-VHD -Path ${pathArg} -ErrorAction Stop`
const pwshCommandArgs = ['-NoProfile', '-Command', `. { ${pwshCommand} }`]

const commandExists = await checkCommandExist('Dismount-VHD')
if (commandExists != 0) {
throw VHDCommandNotFound('Dismount-VHD')
}

const options: ExecOptions = {}
options.silent = true
options.failOnStdErr = false
options.ignoreReturnCode = true

Expand All @@ -37,6 +50,11 @@ export async function create(
formatCmd = `Format-Volume -DevDrive -Confirm:$false -Force ;`
}

const commandExists = await checkCommandExist('New-VHD')
if (commandExists != 0) {
throw VHDCommandNotFound('New-VHD')
}

const pwshCommand = [
`$DevDrive = New-VHD -Path ${pathArg} -SizeBytes ${sizeArg} -${driveType} |`,
'Mount-VHD -Passthru |',
Expand All @@ -48,14 +66,19 @@ export async function create(

core.debug(`Generated the following command:\n${pwshCommand}`)

const pwshCommandArgs = ['-NoProfile', '-Command', `. {${pwshCommand}}`]
const pwshCommandArgs = ['-NoProfile', '-Command', `. { ${pwshCommand} }`]

return await execMountOrCreate(pwshCommandArgs)
}

export async function mount(drivePath: string): Promise<string> {
const pathArg = quote([drivePath])

const commandExists = await checkCommandExist('Mount-VHD')
if (commandExists != 0) {
throw VHDCommandNotFound('Mount-VHD')
}

const pwshCommand = [
`$DevDrive = Mount-VHD -Path ${pathArg} -PassThru |`,
'Get-Disk |',
Expand All @@ -66,7 +89,7 @@ export async function mount(drivePath: string): Promise<string> {

core.debug(`Generated the following command:\n${pwshCommand}`)

const pwshCommandArgs = ['-NoProfile', '-Command', `. {${pwshCommand}}`]
const pwshCommandArgs = ['-NoProfile', '-Command', `. { ${pwshCommand} }`]

return await execMountOrCreate(pwshCommandArgs)
}
Expand All @@ -75,6 +98,9 @@ async function execMountOrCreate(pwshCommandArgs: string[]): Promise<string> {
const options: ExecOptions = {}
let outStr = ''
let errStr = ''
options.silent = true
options.failOnStdErr = false
options.ignoreReturnCode = true
options.listeners = {
stdout: (data: Buffer) => {
outStr += data.toString()
Expand Down Expand Up @@ -109,3 +135,16 @@ async function execMountOrCreate(pwshCommandArgs: string[]): Promise<string> {

return driveLetter
}

async function checkCommandExist(name: string): Promise<number> {
// When running inside `-Command`, `-ErrorAction Stop` will retain the proper exit code
const pwshCommand = `Get-Command -Name ${name} -CommandType Cmdlet -ErrorAction Stop`
const pwshCommandArgs = ['-NoProfile', '-Command', `. { ${pwshCommand} }`]

const options: ExecOptions = {}
options.silent = true
options.failOnStdErr = false
options.ignoreReturnCode = true

return await exec(POWERSHELL_BIN, pwshCommandArgs, options)
}

0 comments on commit a804b2b

Please sign in to comment.