Skip to content

Commit 4b8f191

Browse files
v2-beta bugfix (#52)
* adding tests to catch bugs * updating unit tests and source code * updating workflow to use 2nd release * fixing update level logic * update level deps script workaround * testing no-op on existing install * add output * Update bat.yml * Update bat.yml * Update bat.yml * Update src/matlab.ts Co-authored-by: Mark Cafaro <34887852+mcafaro@users.noreply.github.com> * Update matlab.Release and removed usExisting from destination * updated release info to fix inconsistency * changed output name to matlabroot * fixng pipeline syntax * missing colon in yml * updating naming and fixing missing simulink in bat workflow * changing some variable names for clarity Co-authored-by: Mark Cafaro <34887852+mcafaro@users.noreply.github.com>
1 parent db4be46 commit 4b8f191

File tree

9 files changed

+166
-81
lines changed

9 files changed

+166
-81
lines changed

.github/workflows/bat.yml

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,42 @@ jobs:
3131
matrix:
3232
include:
3333
- os: ubuntu-latest
34-
release: latest
34+
release: latest
35+
products: Simulink Simulink_Test
3536
check-matlab: matlabVer = ver('matlab'); assert(~isempty(matlabVer));
3637
check-simulink: simulinkVer = ver('simulink'); assert(~isempty(simulinkVer));
3738
- os: ubuntu-20.04
38-
release: R2022a
39-
check-matlab: matlabVer = ver('matlab'); assert(strcmp(matlabVer.Release,'(R2022a)'));
40-
check-simulink: simulinkVer = ver('simulink'); assert(strcmp(simulinkVer.Release,'(R2022a)'));
39+
release: R2021bU2
40+
products: |
41+
MATLAB
42+
Simulink
43+
check-matlab: matlabVer = ver('matlab'); assert(strcmp(matlabVer.Release,'(R2021b)'));
44+
check-simulink: simulinkVer = ver('simulink'); assert(strcmp(simulinkVer.Release,'(R2021b)'));
4145
- os: windows-latest
4246
release: latest
47+
products: Simulink
4348
check-matlab: matlabVer = ver('matlab'); assert(~isempty(matlabVer));
4449
check-simulink: simulinkVer = ver('simulink'); assert(~isempty(simulinkVer));
4550
steps:
4651
- uses: actions/download-artifact@v3
4752
with:
4853
name: built-action
49-
- name: Install MATLAB & Simulink (and PCT)
54+
- name: Install selected products
55+
id: setup_matlab
5056
uses: ./
5157
with:
52-
release: ${{ matrix.release}}
53-
products: |
54-
MATLAB
55-
Simulink
58+
release: ${{ matrix.release }}
59+
products: ${{ matrix.products }}
60+
- name: Check matlabroot output is set
61+
run: 'if [[ "${{ steps.setup_matlab.outputs.matlabroot }}" != *"MATLAB"* ]]; then exit 1; fi'
62+
shell: bash
5663
- name: Check MATLAB version
5764
run: matlab-batch "${{ matrix.check-matlab }}"
5865
- name: Check Simulink version
5966
run: matlab-batch "${{ matrix.check-simulink }}"
67+
- name: Check NoOp on 2nd install
68+
uses: ./
69+
with:
70+
release: ${{ matrix.release }}
71+
products: ${{ matrix.products }}
72+

action.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2020 The MathWorks, Inc.
1+
# Copyright 2020-2022 The MathWorks, Inc.
22

33
name: Setup MATLAB
44
description: >-
@@ -16,6 +16,10 @@ inputs:
1616
default: |
1717
MATLAB
1818
Parallel_Computing_Toolbox
19+
outputs:
20+
matlabroot:
21+
description: >-
22+
A full path to the folder where MATLAB is installed.
1923
runs:
2024
using: node16
2125
main: dist/index.js

src/install.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as matlab from "./matlab";
55
import * as mpm from "./mpm";
66
import properties from "./properties.json";
77
import * as script from "./script";
8+
import * as path from "path";
89

910
/**
1011
* Set up an instance of MATLAB on the runner.
@@ -18,20 +19,24 @@ import * as script from "./script";
1819
* @param products A list of products to install (e.g. ["MATLAB", "Simulink"]).
1920
*/
2021
export async function install(platform: string, architecture: string, release: string, products: string[]) {
21-
const version = await matlab.getVersion(release);
22+
const releaseInfo = await matlab.getReleaseInfo(release);
2223

2324
// Install runtime system dependencies for MATLAB on Linux
2425
if (platform === "linux") {
2526
await core.group("Preparing system for MATLAB", () =>
26-
script.downloadAndRunScript(platform, properties.matlabDepsUrl, [version.release])
27+
script.downloadAndRunScript(platform, properties.matlabDepsUrl, [releaseInfo.name])
2728
);
2829
}
2930

3031
await core.group("Setting up MATLAB", async () => {
3132
const mpmPath: string = await mpm.setup(platform, architecture);
32-
const destination: string = await matlab.toolcacheLocation(version);
33+
const [destination, alreadyExists]: [string, boolean] = await matlab.makeToolcacheDir(releaseInfo);
34+
if (!alreadyExists) {
35+
await mpm.install(mpmPath, releaseInfo, products, destination);
36+
}
37+
core.addPath(path.join(destination, "bin"));
38+
core.setOutput('matlabroot', destination);
3339

34-
await mpm.install(mpmPath, version.release, products, destination);
3540
await matlab.setupBatch(platform);
3641
});
3742

src/install.unit.test.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,43 @@ afterEach(() => {
1717

1818
describe("install procedure", () => {
1919
let downloadAndRunScriptMock: jest.Mock<any, any>;
20-
let matlabGetVersionMock: jest.Mock<any, any>;
20+
let matlabGetReleaseInfoMock: jest.Mock<any, any>;
21+
let matlabMakeToolcacheDirMock: jest.Mock<any, any>;
2122
let matlabSetupBatchMock: jest.Mock<any, any>;
2223
let mpmSetupMock: jest.Mock<any, any>;
2324
let mpmInstallMock: jest.Mock<any, any>;
25+
let addPathMock: jest.Mock<any, any>;
26+
let setOutputMock: jest.Mock<any, any>;
2427

2528
const platform = "linux";
2629
const arch = "x64";
2730
const release = "latest";
28-
const version = {
29-
semantic: "9.13.0",
30-
release: "r2022b"
31+
const releaseInfo = {
32+
name: "r2022b",
33+
version: "9.13.0",
34+
updateNumber: "latest"
3135
};
3236
const products = ["MATLAB", "Parallel_Computing_Toolbox"];
3337

3438
const doInstall = () => install.install(platform, arch, release, products);
3539

3640
beforeEach(() => {
3741
downloadAndRunScriptMock = script.downloadAndRunScript as jest.Mock;
38-
matlabGetVersionMock = matlab.getVersion as jest.Mock;
42+
matlabGetReleaseInfoMock = matlab.getReleaseInfo as jest.Mock;
43+
matlabMakeToolcacheDirMock = matlab.makeToolcacheDir as jest.Mock;
3944
matlabSetupBatchMock = matlab.setupBatch as jest.Mock;
4045
mpmSetupMock = mpm.setup as jest.Mock;
4146
mpmInstallMock = mpm.install as jest.Mock;
47+
addPathMock = core.addPath as jest.Mock;
48+
setOutputMock = core.setOutput as jest.Mock;
4249

4350
// Mock core.group to simply return the output of the func it gets from
4451
// the caller
4552
(core.group as jest.Mock).mockImplementation(async (_, func) => {
4653
return func();
4754
});
48-
matlabGetVersionMock.mockResolvedValue(version);
55+
matlabGetReleaseInfoMock.mockResolvedValue(releaseInfo);
56+
matlabMakeToolcacheDirMock.mockResolvedValue(["/opt/hostedtoolcache/MATLAB/9.13.0/x64", false]);
4957
});
5058

5159
it("ideally works", async () => {
@@ -54,6 +62,8 @@ describe("install procedure", () => {
5462
expect(matlabSetupBatchMock).toHaveBeenCalledTimes(1);
5563
expect(mpmSetupMock).toHaveBeenCalledTimes(1);
5664
expect(mpmInstallMock).toHaveBeenCalledTimes(1);
65+
expect(addPathMock).toHaveBeenCalledTimes(1);
66+
expect(setOutputMock).toHaveBeenCalledTimes(1);
5767
});
5868

5969
["darwin", "win32"].forEach((os) => {
@@ -64,11 +74,21 @@ describe("install procedure", () => {
6474
expect(matlabSetupBatchMock).toHaveBeenCalledTimes(1);
6575
expect(mpmSetupMock).toHaveBeenCalledTimes(1);
6676
expect(mpmInstallMock).toHaveBeenCalledTimes(1);
77+
expect(addPathMock).toHaveBeenCalledTimes(1);
78+
expect(setOutputMock).toHaveBeenCalledTimes(1);
6779
});
6880
});
6981

82+
it("NoOp on existing install", async () => {
83+
matlabMakeToolcacheDirMock.mockResolvedValue(["/opt/hostedtoolcache/MATLAB/9.13.0/x64", true]);
84+
await expect(doInstall()).resolves.toBeUndefined();
85+
expect(mpmInstallMock).toHaveBeenCalledTimes(0);
86+
expect(addPathMock).toHaveBeenCalledTimes(1);
87+
expect(setOutputMock).toHaveBeenCalledTimes(1);
88+
});
89+
7090
it("rejects for invalid MATLAB version", async () => {
71-
matlabGetVersionMock.mockRejectedValue(Error("oof"));
91+
matlabGetReleaseInfoMock.mockRejectedValue(Error("oof"));
7292
await expect(doInstall()).rejects.toBeDefined();
7393
});
7494

src/matlab.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,31 @@ import * as fs from "fs";
88
import properties from "./properties.json";
99
import * as script from "./script";
1010

11-
export interface Version {
12-
release: string;
13-
semantic: string;
11+
export interface Release {
12+
name: string;
13+
version: string;
14+
update: string;
1415
}
1516

1617
interface MATLABReleaseInfo {
1718
latest: string;
18-
semantic: {
19+
version: {
1920
[release: string]: string | undefined
2021
}
2122
}
2223

23-
export async function toolcacheLocation(version: Version): Promise<string> {
24-
let toolpath: string = tc.find("MATLAB", version.semantic);
24+
export async function makeToolcacheDir(release: Release): Promise<[string, boolean]> {
25+
let toolpath: string = tc.find("MATLAB", release.version);
26+
let alreadyExists = false;
2527
if (toolpath) {
26-
core.info(`Found MATLAB ${version.release} in cache at ${toolpath}.`);
28+
core.info(`Found MATLAB ${release.name} in cache at ${toolpath}.`);
29+
alreadyExists = true;
2730
} else {
2831
fs.writeFileSync(".keep", "");
29-
toolpath = await tc.cacheFile(".keep", ".keep", "MATLAB", version.semantic);
32+
toolpath = await tc.cacheFile(".keep", ".keep", "MATLAB", release.version);
3033
io.rmRF(".keep");
3134
}
32-
return toolpath
35+
return [toolpath, alreadyExists]
3336
}
3437

3538
export async function setupBatch(platform: string) {
@@ -42,25 +45,31 @@ export async function setupBatch(platform: string) {
4245
return
4346
}
4447

45-
export async function getVersion(release: string): Promise<Version> {
48+
export async function getReleaseInfo(release: string): Promise<Release> {
4649
const client: http.HttpClient = new http.HttpClient();
4750
const releaseInfo = await client.getJson<MATLABReleaseInfo>(properties.matlabReleaseInfoUrl);
4851

4952
if (!releaseInfo.result) {
5053
return Promise.reject(Error(`Unable to retrieve the MATLAB release information. Contact MathWorks at continuous-integration@mathworks.com if the problem persists.`));
5154
}
5255

53-
let parsedRelease: string = release.toLowerCase();
54-
if (parsedRelease === "latest") {
55-
parsedRelease = releaseInfo.result.latest;
56+
let name: string = release.toLowerCase().trim().substring(0,6);
57+
if (name === "latest") {
58+
name = releaseInfo.result.latest;
5659
}
5760

58-
let parsedSemantic = releaseInfo.result.semantic[parsedRelease];
59-
if (!parsedSemantic) {
61+
// Remove update version
62+
let version = releaseInfo.result.version[name];
63+
let update = release.toLowerCase().trim().substring(6,release.length);
64+
if (!update) {
65+
update = "latest"
66+
}
67+
if (!version) {
6068
return Promise.reject(Error(`${release} is invalid or unsupported. Specify the value as R2020a or a later release.`));
6169
}
6270
return {
63-
semantic: parsedSemantic,
64-
release: parsedRelease,
71+
name: name,
72+
version: version,
73+
update: update,
6574
}
6675
}

src/matlab.unit.test.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// Copyright 2022 The MathWorks, Inc.
22

3-
import * as matlab from "./matlab";
4-
import * as script from "./script";
53
import * as core from "@actions/core";
4+
import * as http from "@actions/http-client";
65
import * as tc from "@actions/tool-cache";
7-
import * as http from "@actions/http-client"
6+
import * as matlab from "./matlab";
7+
import * as script from "./script";
88

99
jest.mock("./script")
1010
jest.mock("@actions/core");
@@ -16,9 +16,10 @@ afterEach(() => {
1616
});
1717

1818
describe("matlab tests", () => {
19-
const version = {
20-
semantic: "9.13.0",
21-
release: "r2022b"
19+
const release = {
20+
name: "r2022b",
21+
version: "9.13.0",
22+
update: "latest",
2223
}
2324
describe("toolcacheLocation", () => {
2425
let findMock: jest.Mock<any, any>;
@@ -33,14 +34,14 @@ describe("matlab tests", () => {
3334

3435
it("returns toolpath if in toolcache", async () => {
3536
findMock.mockReturnValue("/opt/hostedtoolcache/matlab/r2022b");
36-
await expect(matlab.toolcacheLocation(version)).resolves.toBe("/opt/hostedtoolcache/matlab/r2022b");
37+
await expect(matlab.makeToolcacheDir(release)).resolves.toMatchObject(["/opt/hostedtoolcache/matlab/r2022b", true]);
3738
expect(infoMock).toHaveBeenCalledTimes(1);
3839
});
3940

4041
it("creates cache and returns new path if not in toolcache", async () => {
4142
findMock.mockReturnValue("");
4243
cacheFileMock.mockReturnValue("/opt/hostedtoolcache/matlab/r2022b");
43-
await expect(matlab.toolcacheLocation(version)).resolves.toBe("/opt/hostedtoolcache/matlab/r2022b");
44+
await expect(matlab.makeToolcacheDir(release)).resolves.toMatchObject(["/opt/hostedtoolcache/matlab/r2022b", false]);
4445
})
4546
});
4647

@@ -74,18 +75,17 @@ describe("matlab tests", () => {
7475
expect(addPathMock).toHaveBeenCalledTimes(0);
7576
expect(tcCacheDirMock).toHaveBeenCalledTimes(0);
7677
});
77-
7878
});
7979

80-
describe("getVersion", () => {
80+
describe("getReleaseInfo", () => {
8181
beforeEach(() => {
82-
// Mock versionInfo response from http client
82+
// Mock MATLABReleaseInfo response from http client
8383
jest.spyOn(http.HttpClient.prototype, 'getJson').mockImplementation(async () => {
8484
return {
8585
statusCode: 200,
8686
result: {
8787
latest: 'r2022b',
88-
semantic: {
88+
version: {
8989
r2022b: '9.13.0',
9090
}
9191
},
@@ -95,15 +95,24 @@ describe("matlab tests", () => {
9595
});
9696

9797
it("latest resolves", () => {
98-
expect(matlab.getVersion("latest")).resolves.toMatchObject(version);
98+
expect(matlab.getReleaseInfo("latest")).resolves.toMatchObject(release);
9999
});
100100

101101
it("case insensitive", () => {
102-
expect(matlab.getVersion("R2022b")).resolves.toMatchObject(version);
102+
expect(matlab.getReleaseInfo("R2022b")).resolves.toMatchObject(release);
103+
});
104+
105+
it("allows specifying update number", () => {
106+
const releaseWithUpdate = {
107+
name: "r2022b",
108+
update: "u2",
109+
version: "9.13.0",
110+
}
111+
expect(matlab.getReleaseInfo("R2022bU2")).resolves.toMatchObject(releaseWithUpdate);
103112
});
104113

105114
it("rejects for unsupported release", () => {
106-
expect(matlab.getVersion("R2022c")).rejects.toBeDefined();
115+
expect(matlab.getReleaseInfo("R2022c")).rejects.toBeDefined();
107116
});
108117

109118
it("rejects if for bad http response", () => {
@@ -114,7 +123,7 @@ describe("matlab tests", () => {
114123
headers: {}
115124
};
116125
})
117-
expect(matlab.getVersion("R2022b")).rejects.toBeDefined();
126+
expect(matlab.getReleaseInfo("R2022b")).rejects.toBeDefined();
118127
});
119128
});
120-
});
129+
});

0 commit comments

Comments
 (0)