Skip to content

Commit 979f92b

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 <dankeboy36@gmail.com>
1 parent 072d71c commit 979f92b

File tree

4 files changed

+163
-41
lines changed

4 files changed

+163
-41
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
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

Lines changed: 112 additions & 15 deletions
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

Lines changed: 48 additions & 23 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy