Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hex): Add protobuf definitions for registry v2 support #32222

Merged
merged 4 commits into from
Oct 30, 2024
Merged
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
92 changes: 92 additions & 0 deletions lib/modules/datasource/hex/v2/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import protobuf from 'protobufjs';
import upath from 'upath';
import { Package } from './package';
import { Signed } from './signed';

function protobufLoad(file: string): Promise<protobuf.Root> {
const resolvedFile = upath.join(__dirname, file);
return new Promise((resolve, reject) => {
protobuf.load(resolvedFile, (err, root) => {
if (err) {
reject(err);
return;
}

if (!root) {
reject(new Error('Root is empty'));
return;
}

resolve(root);
});
});
}

describe('modules/datasource/hex/v2/index', () => {
describe('Signed', () => {
async function encodeSigned(input: unknown): Promise<Buffer> {
const message = Signed.fromJSON(input);
const root = await protobufLoad('signed.proto');
const x = root.lookupType('Signed').encode(message).finish();
return Buffer.from(x);
}

it('roundtrip', async () => {
const input = {
payload: Buffer.from('foo'),
signature: Buffer.from('bar'),
};
const encodedBuf = await encodeSigned(input);

const output = Signed.decode(encodedBuf);

expect(output).toEqual(input);
});
});

describe('Package', () => {
async function encodePackage(input: unknown): Promise<Buffer> {
const message = Package.fromJSON(input);
const root = await protobufLoad('package.proto');
const x = root.lookupType('Package').encode(message).finish();
return Buffer.from(x);
}

it('roundtrip', async () => {
const input: Package = {
name: 'foo',
repository: 'hexpm',
releases: [
{
version: '1.0.0',
innerChecksum: new Uint8Array(),
dependencies: [],
},
{
version: '2.0.0',
innerChecksum: new Uint8Array(),
dependencies: [],
},
{
version: '3.0.0',
innerChecksum: new Uint8Array(),
dependencies: [],
},
],
};
const encodedBuf = await encodePackage(input);

const output = Package.decode(encodedBuf);

expect(output).toMatchObject({
name: 'foo',
repository: 'hexpm',
releases: [
{ version: '1.0.0' },
{ version: '2.0.0' },
{ version: '3.0.0' },
],
});
});
});
});
55 changes: 55 additions & 0 deletions lib/modules/datasource/hex/v2/package.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// https://github.com/hexpm/specifications/blob/9c411dbe96c87ccee438d40838d02b5fa6abb60b/registry/package.proto

syntax = "proto2";

message Package {
// All releases of the package
repeated Release releases = 1;
// Name of package
required string name = 2;
// Name of repository
required string repository = 3;
}

message Release {
// Release version
required string version = 1;
// sha256 checksum of "inner" package tarball
// deprecated in favor of outer_checksum
required bytes inner_checksum = 2;
// All dependencies of the release
repeated Dependency dependencies = 3;
// If set the release is retired, a retired release should only be
// resolved if it has already been locked in a project
optional RetirementStatus retired = 4;
// sha256 checksum of outer package tarball
// required when encoding but optional when decoding
optional bytes outer_checksum = 5;
}

message RetirementStatus {
required RetirementReason reason = 1;
optional string message = 2;
}

enum RetirementReason {
RETIRED_OTHER = 0;
RETIRED_INVALID = 1;
RETIRED_SECURITY = 2;
RETIRED_DEPRECATED = 3;
RETIRED_RENAMED = 4;
}

message Dependency {
// Package name of dependency
required string package = 1;
// Version requirement of dependency
required string requirement = 2;
// If set and true the package is optional (see dependency resolution)
optional bool optional = 3;
// If set is the OTP application name of the dependency, if not set the
// application name is the same as the package name
optional string app = 4;
// If set, the repository where the dependency is located
optional string repository = 5;
}
Loading
Loading