Skip to content
Draft
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
3 changes: 2 additions & 1 deletion .github/workflows/validate-action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ jobs:
with:
json-file-path: "__tests__/test.json"
example-app: "sample-app-1"
path-to-example-app: "path/to/sample-app-1"
slcp-path: "path/to/sample-app-1.slcp"
slcw-path: "path/to/sample-app-1.slcw"
build-script: "__tests__/build_script.sh"
output-directory: "out/"
build-type: "standard"
54 changes: 40 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,28 @@ To use this action, include it in your workflow YAML file.
| Name | Description |
| --------------------- | ---------------------------------------------------------------------------------------- |
| `example-app` | Example app to build |
| `path-to-example-app` | Path example directory to be built |
| `slcp-path` | Path to the .slcp file (application-only project) |
| `slcw-path` | Path to the .slcw file (solution with bootloader) |
| `json-file-path` | JSON content to be used as GN args |
| `build-script` | Build script to be executed for the provided example app |
| `output-directory` | Output directory for the build artifacts |
| `build-type` | Defines which build type to use from the json file (standard, full, custom-sqa, release) |
| `build-type` | Defines which build type to use from the json file (standard, full, custom-sqa) |

## Outputs

This action does not produce any outputs.

## Project File Types

This action supports two types of Silicon Labs project files:

- **`.slcp` files**: Application-only projects that contain just the application code
- **`.slcw` files**: Solution projects that include both the application and bootloader components

The action automatically selects the appropriate file based on the `projectFileType` specified in your JSON configuration:
- When `projectFileType: "slcp"` is specified, the action uses the path from `slcp-path`
- When `projectFileType: "slcw"` is specified or omitted, the action uses the path from `slcw-path` (default behavior)

## Example Workflow

```yaml
Expand All @@ -49,7 +61,8 @@ jobs:
uses: ./ # Uses an action in the root directory
with:
example-app: "lighting-app"
path-to-example-app: "./path/to/lighting-app"
slcp-path: "./path/to/lighting-app.slcp"
slcw-path: "./path/to/lighting-app.slcw"
json-file-path: "./path/to/json.json"
build-script: "./path/to/build_script.sh"
output-directory: "./path/to/output"
Expand Down Expand Up @@ -105,7 +118,7 @@ act --container-architecture linux/amd64 -W .github/workflows/eslint-check.yml

The JSON file used by this action supports a flexible structure to define build configurations.
It allows you to specify default builds that apply to all example apps, as well as builds specific to individual example apps.
Additionally, the JSON structure supports multiple build types (e.g., `standard`, `custom-sqa`, `release` and `full`).
Additionally, the JSON structure supports multiple build types (e.g., `standard`, `custom-sqa`, and `full`).

The JSON file should follow this structure:

Expand All @@ -115,13 +128,15 @@ The JSON file should follow this structure:
"default": [
{
"boards": ["defaultBoard1", "defaultBoard2"],
"arguments": ["defaultArg1", "defaultArg2"]
"arguments": ["defaultArg1", "defaultArg2"],
"projectFileType": "slcw"
}
],
"exampleApp1": [
{
"boards": ["board1", "board2"],
"arguments": ["arg1", "arg2"]
"arguments": ["arg1", "arg2"],
"projectFileType": "slcp"
}
]
},
Expand All @@ -135,7 +150,8 @@ The JSON file should follow this structure:
"exampleApp2": [
{
"boards": ["board3"],
"arguments": ["arg3"]
"arguments": ["arg3"],
"projectFileType": "slcw"
}
]
}
Expand All @@ -144,15 +160,23 @@ The JSON file should follow this structure:

### Explanation

- **`buildType1`, `buildType2`, etc.**: Represents different build types (e.g., `standard`, `custom-sqa`, `release` or `full`). Each build type contains its own set of configurations.
- **`buildType1`, `buildType2`, etc.**: Represents different build types (e.g., `standard`, `custom-sqa`, or `full`). Each build type contains its own set of configurations.
- **`default`**: Contains build configurations that apply to all example apps for the given build type. Each object in the array specifies:

- `boards`: A list of board names for which the build should be executed.
- `arguments`: A list of arguments to pass to the build script.
- `projectFileType` (optional): Specifies which project file path to use:
- `"slcp"`: Uses the path from the `slcp-path` input (application-only project)
- `"slcw"`: Uses the path from the `slcw-path` input (solution with bootloader)
- If omitted, defaults to `"slcw"`

- **`exampleApp1`, `exampleApp2`, etc.**: Keys representing specific example apps. Each key contains an array of build configurations specific to that app. Each object in the array specifies:
- `boards`: A list of board names for which the build should be executed.
- `arguments`: A list of arguments to pass to the build script.
- `projectFileType` (optional): Specifies which project file path to use:
- `"slcp"`: Uses the path from the `slcp-path` input (application-only project)
- `"slcw"`: Uses the path from the `slcw-path` input (solution with bootloader)
- If omitted, defaults to `"slcw"`

### Example

Expand All @@ -170,7 +194,8 @@ For the following JSON structure:
"sample-app-1": [
{
"boards": ["board1", "board2"],
"arguments": ["arg1", "arg2"]
"arguments": ["arg1", "arg2"],
"projectFileType": "slcp"
}
]
},
Expand All @@ -184,7 +209,8 @@ For the following JSON structure:
"sample-app-2": [
{
"boards": ["board4"],
"arguments": ["arg4"]
"arguments": ["arg4", "--lto"],
"projectFileType": "slcp"
}
]
}
Expand All @@ -193,11 +219,11 @@ For the following JSON structure:

- The `standard` build type will:

- Run the `default` configuration for `board1` with `arg1` and `arg2`.
- Run the `sample-app-1` configuration for `board1` and `board2` with `arg1` and `arg2`.
- Run the `default` configuration for `board1` with `arg1` and `arg2` using the path from `slcw-path` (default behavior).
- Run the `sample-app-1` configuration for `board1` and `board2` with `arg1` and `arg2` using the path from `slcp-path`.

- The `custom-sqa` build type will:
- Run the `default` configuration for `board3` with `arg3`.
- Run the `sample-app-2` configuration for `board4` with `arg4`.
- Run the `default` configuration for `board3` with `arg3` using the path from `slcw-path` (default behavior).
- Run the `sample-app-2` configuration for `board4` with `arg4` and `--lto` using the path from `slcp-path`.

This structure provides flexibility to define builds for multiple build types and example apps while maintaining default configurations.
179 changes: 166 additions & 13 deletions __tests__/jsonParser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,24 @@ describe('JsonParser', () =>
};

const buildScript = 'build.sh';
const pathToExampleApp = '/path/to/example';
const outputDirectory = '/output';
const slcpPath = '/path/to/example.slcp';
const slcwPath = '/path/to/example.slcw';

it('should generate commands for default build type', () =>
{
const parser = new JsonParser(mockJsonData, 'standard', 'exampleApp1', buildScript, pathToExampleApp, outputDirectory);
const parser = new JsonParser(mockJsonData, 'standard', 'exampleApp1', buildScript, outputDirectory, slcpPath, slcwPath);
const commands = parser.generateCommands();
expect(commands).toEqual([
'build.sh /path/to/example /output board1 arg1 arg2',
'build.sh /path/to/example /output board2 arg1 arg2',
'build.sh /path/to/example /output board3 arg3'
'build.sh /path/to/example.slcw /output board1 arg1 arg2',
'build.sh /path/to/example.slcw /output board2 arg1 arg2',
'build.sh /path/to/example.slcw /output board3 arg3'
]);
});

it('should throw an error if build type is missing', () =>
{
const parser = new JsonParser(mockJsonData, 'nonexistent', 'exampleApp1', buildScript, pathToExampleApp, outputDirectory);
const parser = new JsonParser(mockJsonData, 'nonexistent', 'exampleApp1', buildScript, outputDirectory, slcpPath, slcwPath);
expect(() => parser.generateCommands()).toThrow('No build type found for nonexistent');
});

Expand All @@ -53,7 +54,7 @@ describe('JsonParser', () =>
}
};

const parser = new JsonParser(mockJsonDataNoDefault, 'standard', 'nonexistentApp', buildScript, pathToExampleApp, outputDirectory);
const parser = new JsonParser(mockJsonDataNoDefault, 'standard', 'nonexistentApp', buildScript, outputDirectory, slcpPath, slcwPath);
expect(() => parser.generateCommands()).toThrow('No build information found for nonexistentApp');
});

Expand All @@ -69,17 +70,17 @@ describe('JsonParser', () =>
]
}
};
const parser = new JsonParser(modifiedJsonData, 'standard', 'nonexistentApp', buildScript, pathToExampleApp, outputDirectory);
const parser = new JsonParser(modifiedJsonData, 'standard', 'nonexistentApp', buildScript, outputDirectory, slcpPath, slcwPath);
const commands = parser.generateCommands();
expect(commands).toEqual(['build.sh /path/to/example /output board1 arg1']);
expect(commands).toEqual(['build.sh /path/to/example.slcw /output board1 arg1']);
});

it('should throw an error if neither default nor specific build info exists', () =>
{
const emptyJsonData = {
standard: {}
};
const parser = new JsonParser(emptyJsonData, 'standard', 'exampleApp1', buildScript, pathToExampleApp, outputDirectory);
const parser = new JsonParser(emptyJsonData, 'standard', 'exampleApp1', buildScript, outputDirectory, slcpPath, slcwPath);
expect(() => parser.generateCommands()).toThrow('No build information found for exampleApp1');
});

Expand Down Expand Up @@ -116,11 +117,163 @@ describe('JsonParser', () =>
}
};

const parser = new JsonParser(multiBuildTypeJsonData, 'standard', 'exampleApp1', buildScript, pathToExampleApp, outputDirectory);
const parser = new JsonParser(multiBuildTypeJsonData, 'standard', 'exampleApp1', buildScript, outputDirectory, slcpPath, slcwPath);
const commands = parser.generateCommands();
expect(commands).toEqual([
'build.sh /path/to/example /output board1 arg1',
'build.sh /path/to/example /output board2 arg2'
'build.sh /path/to/example.slcw /output board1 arg1',
'build.sh /path/to/example.slcw /output board2 arg2'
]);
});

it('should resolve template with projectFileType', () =>
{
const mockJsonDataWithTemplate = {
standard: {
exampleApp1: [
{
boards: ['board1'],
arguments: ['arg1'],
"projectFileType": "slcp"
}
]
}
};

const parser = new JsonParser(mockJsonDataWithTemplate, 'standard', 'exampleApp1', buildScript, outputDirectory, slcpPath, slcwPath);
const commands = parser.generateCommands();
expect(commands).toEqual([
'build.sh /path/to/example.slcp /output board1 arg1'
]);
});

it('should handle mixed projectFileType configurations in default and specific builds', () =>
{
const mockJsonDataMixed = {
standard: {
default: [
{
boards: ['board1'],
arguments: ['arg1'],
"projectFileType": "slcp"
}
],
exampleApp1: [
{
boards: ['board2'],
arguments: ['arg2']
// No projectFileType specified (should use default .slcw)
},
{
boards: ['board3'],
arguments: ['arg3'],
"projectFileType": "slcp"
}
]
}
};

const parser = new JsonParser(mockJsonDataMixed, 'standard', 'exampleApp1', buildScript, outputDirectory, slcpPath, slcwPath);
const commands = parser.generateCommands();
expect(commands).toEqual([
'build.sh /path/to/example.slcp /output board1 arg1',
'build.sh /path/to/example.slcw /output board2 arg2',
'build.sh /path/to/example.slcp /output board3 arg3'
]);
});

it('should handle template with mixed projectFileTypes', () =>
{
const mockJsonDataMixed = {
standard: {
exampleApp1: [
{
boards: ['board1'],
arguments: ['arg1'],
"projectFileType": "slcp"
},
{
boards: ['board2'],
arguments: ['arg2'],
"projectFileType": "slcw"
},
{
boards: ['board3'],
arguments: ['arg3']
// No projectFileType specified (should default to slcw)
}
]
}
};

const parser = new JsonParser(mockJsonDataMixed, 'standard', 'exampleApp1', buildScript, outputDirectory, slcpPath, slcwPath);
const commands = parser.generateCommands();
expect(commands).toEqual([
'build.sh /path/to/example.slcp /output board1 arg1',
'build.sh /path/to/example.slcw /output board2 arg2',
'build.sh /path/to/example.slcw /output board3 arg3'
]);
});

it('should handle separate slcp/slcw paths for Thread platforms', () =>
{
const jsonData = {
"standard": {
"default": [
{
"boards": ["brd4187c"],
"arguments": [""]
},
{
"boards": ["brd4187c"],
"arguments": [""],
"projectFileType": "slcp"
}
]
}
};

const slcpPath = 'slc/apps/air-quality-sensor-app/thread/air-quality-sensor-app.slcp';
const slcwPath = 'slc/apps/air-quality-sensor-app/thread/air-quality-sensor-app-series-2-internal.slcw';

const parser = new JsonParser(jsonData, 'standard', 'air-quality-sensor-app', buildScript, outputDirectory, slcpPath, slcwPath);
const commands = parser.generateCommands();

expect(commands).toHaveLength(2);
// First config has no projectFileType, defaults to .slcw, uses slcwPath
expect(commands[0]).toBe('build.sh slc/apps/air-quality-sensor-app/thread/air-quality-sensor-app-series-2-internal.slcw /output brd4187c ');
// Second config specifies .slcp, uses slcpPath
expect(commands[1]).toBe('build.sh slc/apps/air-quality-sensor-app/thread/air-quality-sensor-app.slcp /output brd4187c ');
});

it('should handle separate slcp/slcw paths for WiFi platforms', () =>
{
const jsonData = {
"standard": {
"default": [
{
"boards": ["brd4187c"],
"arguments": [""],
"projectFileType": "slcp"
},
{
"boards": ["brd4187c"],
"arguments": [""]
}
]
}
};

const slcpPath = 'slc/apps/thermostat/wifi/thermostat-917-ncp.slcp';
const slcwPath = 'slc/apps/thermostat/wifi/thermostat-917-ncp.slcw';

const parser = new JsonParser(jsonData, 'standard', 'thermostat', buildScript, outputDirectory, slcpPath, slcwPath);
const commands = parser.generateCommands();

expect(commands).toHaveLength(2);
// For WiFi, both configs keep the same filename with different extensions
expect(commands[0]).toBe('build.sh slc/apps/thermostat/wifi/thermostat-917-ncp.slcp /output brd4187c ');
expect(commands[1]).toBe('build.sh slc/apps/thermostat/wifi/thermostat-917-ncp.slcw /output brd4187c ');
});


});
Loading