Skip to content

Commit 8e6f3ec

Browse files
committed
feat: support v prefix in CLI GH release name
From Arduino CLI `>=0.35.0-rc.1`, the `v` prefix is expected in the GitHub release name. The asset filenames do not contain the prefix. Ref: arduino/arduino-cli#2374 Signed-off-by: dankeboy36 <[email protected]>
1 parent 072d71c commit 8e6f3ec

File tree

4 files changed

+163
-41
lines changed

4 files changed

+163
-41
lines changed

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ardunno-cli-gen",
3-
"version": "0.1.5",
3+
"version": "0.1.7",
44
"description": "Generates nice-grpc API for the Arduino CLI",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",

src/__tests__/generate.spec.ts

+112-15
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import * as assert from 'assert';
1+
import * as assert from 'assert/strict';
22
import { describe } from 'mocha';
33
import { join } from 'node:path';
44
import { dir as tempDir } from 'tmp-promise';
5-
import generate, { __test, parseGitHub, parseSemver } from '../generate';
5+
import generate, { __test } from '../generate';
6+
import { SemVer } from 'semver';
67

7-
const { execa } = __test;
8+
const { parseSemver, parseGitHub, protoLocation, execa } = __test;
89

910
describe('generate', () => {
1011
it("should fail when 'src' is an accessible file", async function () {
@@ -141,9 +142,9 @@ describe('generate', () => {
141142
'protobuf',
142143
'empty'
143144
));
144-
assert.notEqual(Empty, undefined);
145-
assert.equal(typeof Empty.fromJSON, 'function');
146-
assert.deepEqual(Empty.fromJSON(), {});
145+
assert.notStrictEqual(Empty, undefined);
146+
assert.strictEqual(typeof Empty.fromJSON, 'function');
147+
assert.deepStrictEqual(Empty.fromJSON(), {});
147148
} finally {
148149
await execa('npm', ['unlink', 'protobufjs'], {
149150
cwd: path,
@@ -154,13 +155,13 @@ describe('generate', () => {
154155

155156
describe('parseGitHub', () => {
156157
it('should parse valid', () => {
157-
assert.deepEqual(parseGitHub('arduino/arduino-cli'), {
158+
assert.deepStrictEqual(parseGitHub('arduino/arduino-cli'), {
158159
owner: 'arduino',
159160
repo: 'arduino-cli',
160161
});
161162
});
162163
it('should parse valid with commit', () => {
163-
assert.deepEqual(parseGitHub('arduino/arduino-cli#5a4ffe0'), {
164+
assert.deepStrictEqual(parseGitHub('arduino/arduino-cli#5a4ffe0'), {
164165
owner: 'arduino',
165166
repo: 'arduino-cli',
166167
commit: '5a4ffe0',
@@ -176,29 +177,125 @@ describe('generate', () => {
176177
'owner/repo#one two',
177178
].forEach((src) =>
178179
it(`should not parse '${src}'`, () =>
179-
assert.equal(parseGitHub(src), undefined))
180+
assert.strictEqual(parseGitHub(src), undefined))
180181
);
181182
});
182183
describe('parseSemver', () => {
183184
it('should parse valid', () =>
184-
assert.equal(parseSemver('0.30.0'), '0.30.0'));
185+
assert.strictEqual(
186+
(<SemVer>parseSemver('0.30.0')).version,
187+
'0.30.0'
188+
));
185189
it('should parse valid with rc', () =>
186-
assert.equal(parseSemver('0.30.0-rc1'), '0.30.0-rc1'));
190+
assert.strictEqual(
191+
(<SemVer>parseSemver('0.30.0-rc1')).version,
192+
'0.30.0-rc1'
193+
));
187194
it("should parse valid with 'v' prefix", () =>
188-
assert.equal(parseSemver('v0.29.1'), '0.29.1'));
195+
assert.strictEqual(
196+
(<SemVer>parseSemver('v0.29.1')).version,
197+
'0.29.1'
198+
));
189199
it("should parse valid semver '>=0.29.0' as a semver [arduino/arduino-cli#1931]", () =>
190-
assert.equal(parseSemver('0.29.0'), '0.29.0'));
200+
assert.strictEqual(
201+
(<SemVer>parseSemver('0.29.0')).version,
202+
'0.29.0'
203+
));
191204
it("should parse to GitHub ref when version is not greater than '0.28.0'", () =>
192-
assert.deepEqual(parseSemver('0.28.0'), {
205+
assert.deepStrictEqual(parseSemver('0.28.0'), {
193206
owner: 'arduino',
194207
repo: 'arduino-cli',
195208
commit: '0.28.0',
196209
}));
197210
['a', '0', '0.30', '0.30.', '0.30.0.'].forEach((src) =>
198211
it(`should not parse '${src}'`, () =>
199-
assert.equal(parseSemver(src), undefined))
212+
assert.strictEqual(parseSemver(src), undefined))
200213
);
201214
});
215+
describe('protoLocation', () => {
216+
(
217+
[
218+
['0.28.0', false],
219+
['0.29.0-rc.1', false],
220+
[
221+
'0.29.0',
222+
{
223+
endpoint:
224+
'https://github.com/arduino/arduino-cli/releases/download/0.29.0/arduino-cli_0.29.0_proto.zip',
225+
filename: 'arduino-cli_0.29.0_proto.zip',
226+
},
227+
],
228+
[
229+
'v0.29.0',
230+
{
231+
endpoint:
232+
'https://github.com/arduino/arduino-cli/releases/download/0.29.0/arduino-cli_0.29.0_proto.zip',
233+
filename: 'arduino-cli_0.29.0_proto.zip',
234+
},
235+
],
236+
[
237+
'v0.34.2',
238+
{
239+
endpoint:
240+
'https://github.com/arduino/arduino-cli/releases/download/0.34.2/arduino-cli_0.34.2_proto.zip',
241+
filename: 'arduino-cli_0.34.2_proto.zip',
242+
},
243+
],
244+
[
245+
'v0.35.0-rc.0',
246+
{
247+
endpoint:
248+
'https://github.com/arduino/arduino-cli/releases/download/0.35.0-rc.0/arduino-cli_0.35.0-rc.0_proto.zip',
249+
filename: 'arduino-cli_0.35.0-rc.0_proto.zip',
250+
},
251+
],
252+
[
253+
'v0.35.0-rc.1',
254+
{
255+
endpoint:
256+
'https://github.com/arduino/arduino-cli/releases/download/v0.35.0-rc.1/arduino-cli_0.35.0-rc.1_proto.zip',
257+
filename: 'arduino-cli_0.35.0-rc.1_proto.zip',
258+
},
259+
],
260+
[
261+
'v0.35.0',
262+
{
263+
endpoint:
264+
'https://github.com/arduino/arduino-cli/releases/download/v0.35.0/arduino-cli_0.35.0_proto.zip',
265+
filename: 'arduino-cli_0.35.0_proto.zip',
266+
},
267+
],
268+
[
269+
'v0.35.1',
270+
{
271+
endpoint:
272+
'https://github.com/arduino/arduino-cli/releases/download/v0.35.1/arduino-cli_0.35.1_proto.zip',
273+
filename: 'arduino-cli_0.35.1_proto.zip',
274+
},
275+
],
276+
] as const
277+
)
278+
.map(
279+
([raw, expected]) =>
280+
[new SemVer(raw, { loose: true }), expected] as [
281+
SemVer,
282+
{ endpoint: string; filename: string } | false
283+
]
284+
)
285+
.forEach(([semver, expected]) =>
286+
it(`should${
287+
!expected ? ' not' : ''
288+
} get the GitHub release asset location for the protos (${
289+
semver.raw
290+
})`, () => {
291+
if (!expected) {
292+
assert.throws(() => protoLocation(semver));
293+
} else {
294+
assert.deepStrictEqual(protoLocation(semver), expected);
295+
}
296+
})
297+
);
298+
});
202299
});
203300

204301
async function dir<T>(test: (path: string) => Promise<T>): Promise<T> {

src/generate.ts

+48-23
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export default async function (options: Options): Promise<void> {
4141
if (!semverOrGitHub) {
4242
throw new Error(`Invalid <src>: ${src}`);
4343
}
44-
const { protoPath, dispose } = await (typeof semverOrGitHub === 'string'
44+
const { protoPath, dispose } = await (semverOrGitHub instanceof SemVer
4545
? download(semverOrGitHub)
4646
: clone(semverOrGitHub));
4747
try {
@@ -59,7 +59,7 @@ interface Plugin {
5959
readonly options: Record<string, string | string[] | boolean | boolean[]>;
6060
readonly path: string;
6161
}
62-
export type PluginName = 'ts_proto';
62+
type PluginName = 'ts_proto';
6363
const plugins: Record<PluginName, Plugin> = {
6464
// eslint-disable-next-line @typescript-eslint/naming-convention
6565
ts_proto: {
@@ -161,10 +161,7 @@ interface GitHub {
161161
readonly commit?: string | undefined;
162162
}
163163

164-
/**
165-
* (non-API)
166-
*/
167-
export function parseGitHub(src: string): GitHub | undefined {
164+
function parseGitHub(src: string): GitHub | undefined {
168165
const match: RegExpGroups<['owner', 'repo', 'commit']> =
169166
src.match(ghPattern);
170167
if (match && match.groups) {
@@ -217,9 +214,10 @@ async function clone(
217214
};
218215
}
219216

220-
async function download(
221-
semver: string
222-
): Promise<{ protoPath: string; dispose: () => Promise<void> }> {
217+
const { owner, repo } = arduinoGitHub;
218+
const releases = `https://github.com/${owner}/${repo}/releases`;
219+
220+
function protoLocation(semver: SemVer): { endpoint: string; filename: string } {
223221
if (!valid(semver)) {
224222
log('attempted to download with invalid semver %s', semver);
225223
throw new Error(`invalid semver ${semver}`);
@@ -228,11 +226,26 @@ async function download(
228226
log('attempted to download the asset file with semver %s', semver);
229227
throw new Error(`semver must be '>=0.29.0' it was ${semver}`);
230228
}
229+
const filenameVersion = semver.version;
230+
const ghReleaseVersion = hasSemverPrefix(semver)
231+
? semver.raw
232+
: semver.version;
233+
const filename = `arduino-cli_${filenameVersion}_proto.zip`;
234+
const endpoint = `${releases}/download/${ghReleaseVersion}/${filename}`;
235+
log(
236+
'semver: %s (raw: %s), filename: %s, endpoint: %s',
237+
semver.version,
238+
semver.raw,
239+
filename,
240+
endpoint
241+
);
242+
return { endpoint, filename };
243+
}
231244

232-
const { owner, repo } = arduinoGitHub;
233-
const filename = `arduino-cli_${semver}_proto.zip`;
234-
const releases = `https://github.com/${owner}/${repo}/releases`;
235-
const endpoint = `${releases}/download/${semver}/${filename}`;
245+
async function download(
246+
semver: SemVer
247+
): Promise<{ protoPath: string; dispose: () => Promise<void> }> {
248+
const { endpoint, filename } = protoLocation(semver);
236249
log('accessing protos from public endpoint %s', endpoint);
237250
// asset GET will result in a HTTP 302 (Redirect)
238251
const getLocationResp = await get(endpoint);
@@ -304,41 +317,50 @@ async function get(endpoint: string): Promise<IncomingMessage> {
304317
}
305318

306319
/**
307-
* (non-API)
308-
*
309320
* If the `src` argument is `<0.29.0` semver, the function returns with a `GitHub` instance.
310321
*/
311-
export function parseSemver(src: string): string | GitHub | undefined {
322+
function parseSemver(src: string): SemVer | GitHub | undefined {
312323
log('parse semver %s', src);
313324
if (!valid(src)) {
314325
log('invalid semver %s', src);
315326
return undefined;
316327
}
317-
const semver = new SemVer(src, true);
318-
const version = semver.version;
328+
const semver = new SemVer(src, { loose: true });
319329
if (canDownloadProtos(semver)) {
320-
log('parsed semver %s is >=0.29.0', version);
321-
return version;
330+
log(
331+
'parsed semver %s is >=0.29.0 (raw: %s)',
332+
semver.version,
333+
semver.raw
334+
);
335+
return semver;
322336
}
323337
const github = {
324338
...arduinoGitHub,
325339
commit: semver.version,
326340
};
327341
log(
328-
'parsed semver %s is <0.29.0. falling back to GitHub ref %j',
329-
version,
342+
'parsed semver %s is <0.29.0 (raw: %s). falling back to GitHub ref %j',
343+
semver.version,
344+
semver.raw,
330345
github
331346
);
332347
return github;
333348
}
334349

335350
/**
336-
* The `.proto` files were not part of the Arduino CLI release before version 0.29.0 ([`arduino/arduino-cli#1931`](https://github.com/arduino/arduino-cli/pull/1931)).
351+
* The `.proto` files were not part of the Arduino CLI release before version `0.29.0` ([`arduino/arduino-cli#1931`](https://github.com/arduino/arduino-cli/pull/1931)).
337352
*/
338353
function canDownloadProtos(semver: SemVer | string): boolean {
339354
return gte(semver, new SemVer('0.29.0'));
340355
}
341356

357+
/**
358+
* The Arduino CLI GitHub release has the `'v'` prefix from version `>=v0.35.0-rc.1` ([`arduino/arduino-cli#2374`](https://github.com/arduino/arduino-cli/pull/2374)).
359+
*/
360+
function hasSemverPrefix(semver: SemVer | string): boolean {
361+
return gte(semver, new SemVer('0.35.0-rc.1'));
362+
}
363+
342364
// Taken from https://github.com/microsoft/TypeScript/issues/32098#issuecomment-1212501932
343365
type RegExpGroups<T extends string[]> =
344366
| (RegExpMatchArray & {
@@ -351,5 +373,8 @@ type RegExpGroups<T extends string[]> =
351373
*/
352374
// eslint-disable-next-line @typescript-eslint/naming-convention
353375
export const __test = {
376+
parseGitHub,
377+
protoLocation,
378+
parseSemver,
354379
execa,
355380
} as const;

0 commit comments

Comments
 (0)