Skip to content

Commit

Permalink
feat(OS): Add Windows support
Browse files Browse the repository at this point in the history
  • Loading branch information
mwarres committed Mar 13, 2023
1 parent b3af288 commit 0984dcb
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .checkov.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
quiet: true
skip-check:
# Our containers are for testing purposes only
- CKV_DOCKER_2 # "Ensure that HEALTHCHECK instructions have been added to container images"
- CKV_DOCKER_3 # "Ensure that a user for the container has been created"
2 changes: 2 additions & 0 deletions .dictionary.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Laven
ltsc
nanoserver
npmpackagejsonlintignore
trivyignore
29 changes: 24 additions & 5 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,38 @@ jobs:
comment_mode: off
save-cache:
name: Save Cache
runs-on: ubuntu-22.04
strategy:
matrix:
os:
- ubuntu-22.04
- windows-2022
runs-on: ${{ matrix.os }}
steps:
- name: Check out repository.
uses: actions/[email protected]
- name: Save Docker images.
uses: ./
with:
key: docker-cache-test-${{ github.run_id }}-${{ github.run_attempt }}
key: docker-cache-test-${{ matrix.os }}-${{ github.run_id }}-${{ github.run_attempt }}
- name: Build an empty test Docker image.
run: docker build --tag empty .
run: |
if [[ "${{ matrix.os }}" =~ 'windows' ]]; then
DOCKERFILE='Dockerfile.windows'
else
DOCKERFILE='Dockerfile'
fi
docker build --tag empty . --file "$DOCKERFILE"
shell: bash
restore-cache:
name: Restore Cache
needs:
- save-cache
runs-on: ubuntu-22.04
strategy:
matrix:
os:
- ubuntu-22.04
- windows-2022
runs-on: ${{ matrix.os }}
permissions:
actions: write # for cache deletion
steps:
Expand All @@ -97,11 +114,12 @@ jobs:
- name: Load Docker images.
uses: ./
with:
key: docker-cache-test-${{ github.run_id }}-${{ github.run_attempt }}
key: docker-cache-test-${{ matrix.os }}-${{github.run_id }}-${{ github.run_attempt }}
- name: Verify Docker loaded empty image from cache.
run: |
description="$(docker inspect --format '{{ index .Config.Labels "description" }}' empty)"
[[ $description == 'empty image' ]]
shell: bash
- name: Delete test cache if permitted (i.e., workflow not triggered from fork).
if: always()
run: >
Expand All @@ -118,6 +136,7 @@ jobs:
github.run_attempt
}}&ref=$GITHUB_REF" ||
(( $? == 22 ))
shell: bash
notify:
name: Notify
if: always()
Expand Down
1 change: 1 addition & 0 deletions .mega-linter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ JSON_PRETTIER_FILE_EXTENSIONS:
- .json
- .md
MARKDOWN_MARKDOWNLINT_CONFIG_FILE: .markdownlint.yaml
REPOSITORY_CHECKOV_CONFIG_FILE: LINTER_DEFAULT
SPELL_CSPELL_CONFIG_FILE: LINTER_DEFAULT
TYPESCRIPT_DEFAULT_STYLE: prettier
# Work around https://github.com/oxsecurity/megalinter/issues/1572.
Expand Down
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# for testing purposes
# checkov:skip=CKV_DOCKER_3:Suppress error "Ensure that a user for the container has been created" since this Dockerfile is only used for testing.

FROM scratch
LABEL description="empty image"
Expand Down
4 changes: 4 additions & 0 deletions Dockerfile.windows
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# for testing purposes

FROM mcr.microsoft.com/windows/nanoserver:ltsc2022
LABEL description="empty image"
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ failed) and false on cache miss. See also

## Supported Runners

Please refer to
[`README.md` of ScribeMD/rootless-docker](https://github.com/ScribeMD/rootless-docker#supported-runners).
- Tested on `ubuntu-22.04` and `windows-2022`
- Probably works on `ubuntu-18.04` and `ubuntu-20.04`
- May work on future versions of Linux and Windows

## Permissions

Expand Down
1 change: 1 addition & 0 deletions cspell.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dictionaryDefinitions:
path: .dictionary.txt
dictionaries:
- custom
- docker
- fullstack
- npm
- python
Expand Down
2 changes: 1 addition & 1 deletion dist/main/index.js

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

48 changes: 41 additions & 7 deletions src/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { testProp } from "@fast-check/jest";
import { jest } from "@jest/globals";
import { string } from "fast-check";
import { Arbitrary, constantFrom, string } from "fast-check";

jest.unstable_mockModule("node:child_process", () => ({
exec: jest.fn<typeof import("node:child_process").exec>(),
Expand All @@ -23,6 +23,7 @@ describe("Util", (): void => {
const mockedExec = async (
command: string,
error: Error | null,
platform: NodeJS.Platform,
stdout = "",
stderr = ""
): Promise<string> => {
Expand All @@ -33,51 +34,84 @@ describe("Util", (): void => {
): any => {
callback(error, { stdout, stderr });
}));
const output = await util.execBashCommand(command);
const output = await util.execBashCommand(command, platform);

expect(core.info).nthCalledWith<[string]>(1, command);
const shell =
platform === "win32"
? "C:\\Program Files\\Git\\bin\\bash.exe"
: "/usr/bin/bash";
expect(child_process.exec).lastCalledWith(
command,
{ shell: "/usr/bin/bash" },
{ shell },
expect.anything()
);
return output;
};

const platform = (): Arbitrary<NodeJS.Platform> =>
constantFrom<NodeJS.Platform>("linux", "win32");

testProp(
"ferries command output to GitHub Actions on success",
[string(), string(), string()],
[string(), platform(), string(), string()],
async (
command: string,
platform: NodeJS.Platform,
stdout: string,
stderr: string
): Promise<void> => {
jest.clearAllMocks();
const output = await mockedExec(command, null, stdout, stderr);
const output = await mockedExec(
command,
null,
platform,
stdout,
stderr
);

expect(output).toBe(stdout);
expect(core.info).lastCalledWith(stdout);
expect(core.error).lastCalledWith(stderr);
},
{
examples: [
["sample Linux command", "linux", "", ""],
["sample Windows command", "win32", "", ""],
],
}
);

testProp(
"ferries failure to GitHub Actions",
[string(), string(), string(), string()],
[string(), string(), platform(), string(), string()],
async (
command: string,
errorMessage: string,
platform: NodeJS.Platform,
stdout: string,
stderr: string
): Promise<void> => {
jest.clearAllMocks();
const error = new Error(errorMessage);
const output = await mockedExec(command, error, stdout, stderr);
const output = await mockedExec(
command,
error,
platform,
stdout,
stderr
);

expect(output).toBe("");
expect(core.info).toHaveBeenCalledTimes(1);
expect(core.error).not.toHaveBeenCalled();
expect(core.setFailed).lastCalledWith(error.toString());
},
{
examples: [
["sample Linux command", "", "linux", "", ""],
["sample Windows command", "", "win32", "", ""],
],
}
);
});
Expand Down
11 changes: 9 additions & 2 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ const execAsPromised = promisify(exec);

import { error, info, setFailed } from "@actions/core";

const execBashCommand = async (command: string): Promise<string> => {
const execBashCommand = async (
command: string,
platform: NodeJS.Platform = process.platform
): Promise<string> => {
info(command);
const shell =
platform === "win32"
? "C:\\Program Files\\Git\\bin\\bash.exe"
: "/usr/bin/bash";
let output = "";
try {
const result = await execAsPromised(command, { shell: "/usr/bin/bash" });
const result = await execAsPromised(command, { shell });
output = result.stdout;
info(output);
error(result.stderr);
Expand Down

0 comments on commit 0984dcb

Please sign in to comment.