8 Commits
v0 ... v1

Author SHA1 Message Date
ccb85e16fa new tier output
All checks were successful
Unit tests / Unit tests (lts/*) (push) Successful in -1m59s
Unit tests / Unit tests (lts/hydrogen) (push) Successful in -1m59s
NPM Audit Check / Check NPM audit (push) Successful in -2m1s
Distribution check / Generated files check (push) Successful in -1m57s
Unit tests / Unit tests (latest) (push) Successful in -1m59s
2025-11-12 14:52:04 -05:00
8170ed0565 Add logging
All checks were successful
Distribution check / Generated files check (push) Successful in -1m58s
NPM Audit Check / Check NPM audit (push) Successful in -2m9s
Unit tests / Unit tests (latest) (push) Successful in -1m59s
Unit tests / Unit tests (lts/*) (push) Successful in -1m59s
Unit tests / Unit tests (lts/hydrogen) (push) Successful in -1m58s
2025-11-12 12:25:30 -05:00
112afbe142 update dist
All checks were successful
Unit tests / Unit tests (latest) (push) Successful in -1m49s
Unit tests / Unit tests (lts/*) (push) Successful in -1m59s
Unit tests / Unit tests (lts/hydrogen) (push) Successful in -1m59s
Distribution check / Generated files check (push) Successful in -1m48s
NPM Audit Check / Check NPM audit (push) Successful in -2m9s
2025-11-12 11:55:13 -05:00
fc87114c36 use repo name
Some checks failed
NPM Audit Check / Check NPM audit (push) Successful in -2m9s
Unit tests / Unit tests (latest) (push) Successful in -1m59s
Unit tests / Unit tests (lts/*) (push) Successful in -2m0s
Unit tests / Unit tests (lts/hydrogen) (push) Successful in -1m59s
Distribution check / Generated files check (push) Failing after -1m57s
2025-11-11 01:10:56 -05:00
8f96ff74ec link package to repo
All checks were successful
Distribution check / Generated files check (push) Successful in -1m58s
NPM Audit Check / Check NPM audit (push) Successful in -2m10s
Unit tests / Unit tests (latest) (push) Successful in -2m0s
Unit tests / Unit tests (lts/*) (push) Successful in -2m0s
Unit tests / Unit tests (lts/hydrogen) (push) Successful in -1m59s
2025-11-11 01:04:50 -05:00
8574ca8ecb Export with dep repos
All checks were successful
Unit tests / Unit tests (latest) (push) Successful in -1m59s
Unit tests / Unit tests (lts/hydrogen) (push) Successful in -2m0s
Distribution check / Generated files check (push) Successful in -1m58s
NPM Audit Check / Check NPM audit (push) Successful in -2m10s
Unit tests / Unit tests (lts/*) (push) Successful in -2m0s
2025-11-09 23:57:42 -05:00
dd6940a77f Add license
All checks were successful
Distribution check / Generated files check (push) Successful in -1m58s
NPM Audit Check / Check NPM audit (push) Successful in -2m9s
Unit tests / Unit tests (latest) (push) Successful in -1m59s
Unit tests / Unit tests (lts/*) (push) Successful in -1m59s
Unit tests / Unit tests (lts/hydrogen) (push) Successful in -1m59s
2025-11-09 19:20:19 -05:00
8ce406f86a delete old package
All checks were successful
Distribution check / Generated files check (push) Successful in -1m56s
NPM Audit Check / Check NPM audit (push) Successful in -2m10s
Unit tests / Unit tests (lts/hydrogen) (push) Successful in -1m56s
Unit tests / Unit tests (latest) (push) Successful in -1m57s
Unit tests / Unit tests (lts/*) (push) Successful in -1m56s
2025-11-09 17:42:31 -05:00
9 changed files with 168 additions and 21 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Cory Sanin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -31,6 +31,10 @@ outputs:
description: whether a deletion is required or not description: whether a deletion is required or not
destination: destination:
description: destination repo description: destination repo
deps:
description: which repos to enable while building (stable, testing, staging)
tier:
description: which tier of repos to enable (0 for system/core, etc.)
runs: runs:
using: 'node16' using: 'node16'

45
dist/index.js vendored
View File

@@ -41396,6 +41396,8 @@ async function parse(previous, current) {
build: false, build: false,
move: [], move: [],
delete: [], delete: [],
deps: getDepRepo(actions.addRepo),
tier: getTier(actions.addRepo || actions.removeRepo),
actions, actions,
}; };
// can't delete if there's nothing to delete/no previous success // can't delete if there's nothing to delete/no previous success
@@ -41404,11 +41406,11 @@ async function parse(previous, current) {
result.delete.push(...parseRepoContents(repo, actions.removeRepo)); result.delete.push(...parseRepoContents(repo, actions.removeRepo));
} }
else if (isMove(actions)) { else if (isMove(actions)) {
const moving = result.move = parseRepoContents(curr.repos[actions.addRepo], actions.removeRepo); result.move = parseRepoContents(curr.repos[actions.addRepo], actions.removeRepo);
prev && result.delete.push(...getDropped(parseRepoContents(prev.repos[actions.addRepo], actions.addRepo), moving)); prev && result.delete.push(...parseRepoContents(prev.repos[actions.addRepo], actions.addRepo));
} }
else if ((result.build = isAdd(actions)) && prev) { else if ((result.build = isAdd(actions)) && prev) {
result.delete.push(...getDropped(parseRepoContents(prev.repos[actions.addRepo], actions.addRepo), parseRepoContents(curr.repos[actions.addRepo], actions.addRepo))); result.delete.push(...parseRepoContents(prev.repos[actions.addRepo], actions.addRepo));
} }
return result; return result;
} }
@@ -41422,9 +41424,6 @@ function parseRepoContents(repoContents, repository) {
}; };
}); });
} }
function getDropped(oldPackages, newPackages) {
return oldPackages.filter(p => newPackages.filter(np => np.package === p.package).length === 0);
}
function isDelete(actions) { function isDelete(actions) {
return !!(actions.removeRepo && actions.addRepo === null); return !!(actions.removeRepo && actions.addRepo === null);
} }
@@ -41434,6 +41433,34 @@ function isAdd(actions) {
function isMove(actions) { function isMove(actions) {
return !!(actions.removeRepo && actions.addRepo); return !!(actions.removeRepo && actions.addRepo);
} }
function getDepRepo(destination) {
const split = (destination || '').split('-');
switch (split[split.length - 1]) {
case 'testing':
case 'gremlins':
return 'testing';
case 'staging':
case 'goblins':
return 'staging';
default:
return 'stable';
}
}
function getTier(destination) {
const split = (destination || '').split('-');
switch (split[0]) {
case 'extra':
case 'world':
return '1';
case 'galaxy':
return '2';
case 'multilib':
case 'lib32':
return '3';
default:
return '0';
}
}
async function tryRead(location) { async function tryRead(location) {
try { try {
const contents = isUrl(location) ? await (await distribution.get(location)).text() : await promises_namespaceObject.readFile(location, { encoding: 'utf-8' }); const contents = isUrl(location) ? await (await distribution.get(location)).text() : await promises_namespaceObject.readFile(location, { encoding: 'utf-8' });
@@ -41475,6 +41502,7 @@ async function main() {
if (mode === 'move') { if (mode === 'move') {
for (const pkg of parsedData.move) { for (const pkg of parsedData.move) {
const filename = getFilename(pkg); const filename = getFilename(pkg);
console.log(`moving ${filename} from ${parsedData.actions.removeRepo} to ${parsedData.actions.addRepo} ...`);
const files = await distribution.get(`${github.context.serverUrl}/api/v1/packages/${github.context.repo.owner}/arch/${pkg.package}/${pkg.version}/files`, { headers }).json(); const files = await distribution.get(`${github.context.serverUrl}/api/v1/packages/${github.context.repo.owner}/arch/${pkg.package}/${pkg.version}/files`, { headers }).json();
const match = files.filter(f => f.name === filename); const match = files.filter(f => f.name === filename);
if (match.length !== 1) { if (match.length !== 1) {
@@ -41486,11 +41514,13 @@ async function main() {
body, body,
headers headers
}); });
await distribution.post(`${github.context.serverUrl}/api/v1/packages/${github.context.repo.owner}/arch/${pkg.package}/-/link/${github.context.repo.repo}`, { headers });
} }
await deletePackages(parsedData.move, headers); await deletePackages(parsedData.move, headers);
return; return;
} }
else if (mode === 'delete') { else if (mode === 'delete') {
console.log(`deleting ${parsedData.delete.join(', ') || 'no packages'} ...`);
await deletePackages(parsedData.delete, headers); await deletePackages(parsedData.delete, headers);
return; return;
} }
@@ -41513,11 +41543,14 @@ async function doParse() {
const previous = core.getInput('previous', { required: true }); const previous = core.getInput('previous', { required: true });
const current = getCurrent(); const current = getCurrent();
const diff = await parse(previous, current); const diff = await parse(previous, current);
console.log(diff);
core.setOutput('parsed-data', JSON.stringify(diff)); core.setOutput('parsed-data', JSON.stringify(diff));
core.setOutput('build', diff.build); core.setOutput('build', diff.build);
core.setOutput('move', diff.move.length > 0); core.setOutput('move', diff.move.length > 0);
core.setOutput('delete', diff.delete.length > 0); core.setOutput('delete', diff.delete.length > 0);
core.setOutput('destination', diff.actions.addRepo); core.setOutput('destination', diff.actions.addRepo);
core.setOutput('deps', diff.deps);
core.setOutput('tier', diff.tier);
} }
//# sourceMappingURL=router.js.map //# sourceMappingURL=router.js.map
;// CONCATENATED MODULE: ./lib/src/index.js ;// CONCATENATED MODULE: ./lib/src/index.js

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "pkgbase-yaml-parser", "name": "pkgbase-yaml-parser",
"version": "0.0.1", "version": "1.0.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pkgbase-yaml-parser", "name": "pkgbase-yaml-parser",
"version": "0.0.1", "version": "1.0.3",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.11.1",

View File

@@ -1,6 +1,6 @@
{ {
"name": "pkgbase-yaml-parser", "name": "pkgbase-yaml-parser",
"version": "0.0.1", "version": "1.0.3",
"description": "compare Artix `pkgbase.yaml` files", "description": "compare Artix `pkgbase.yaml` files",
"keywords": [ "keywords": [
"artix", "artix",

View File

@@ -1,9 +1,10 @@
import { type PathLike } from 'fs';
import fsp from 'fs/promises'; import fsp from 'fs/promises';
import { URL } from 'url'; import { URL } from 'url';
import ky from 'ky'; import ky from 'ky';
import * as YAML from 'yaml'; import * as YAML from 'yaml';
export type DependencyRepo = 'stable' | 'testing' | 'staging';
export interface PackageInfo { export interface PackageInfo {
package: string; package: string;
repository: string; repository: string;
@@ -25,6 +26,8 @@ export interface Result {
build: boolean; build: boolean;
move: PackageInfo[]; move: PackageInfo[];
delete: PackageInfo[]; delete: PackageInfo[];
deps: DependencyRepo;
tier: string;
actions: Actions; actions: Actions;
} }
@@ -61,6 +64,8 @@ export async function parse(previous: string, current: string): Promise<Result>
build: false, build: false,
move: [], move: [],
delete: [], delete: [],
deps: getDepRepo(actions.addRepo),
tier: getTier(actions.addRepo || actions.removeRepo),
actions, actions,
}; };
@@ -70,11 +75,11 @@ export async function parse(previous: string, current: string): Promise<Result>
result.delete.push(...parseRepoContents(repo, actions.removeRepo)); result.delete.push(...parseRepoContents(repo, actions.removeRepo));
} }
else if (isMove(actions)) { else if (isMove(actions)) {
const moving = result.move = parseRepoContents(curr.repos[actions.addRepo], actions.removeRepo); result.move = parseRepoContents(curr.repos[actions.addRepo], actions.removeRepo);
prev && result.delete.push(...getDropped(parseRepoContents(prev.repos[actions.addRepo], actions.addRepo), moving)); prev && result.delete.push(...parseRepoContents(prev.repos[actions.addRepo], actions.addRepo));
} }
else if ((result.build = isAdd(actions)) && prev) { else if ((result.build = isAdd(actions)) && prev) {
result.delete.push(...getDropped(parseRepoContents(prev.repos[actions.addRepo], actions.addRepo), parseRepoContents(curr.repos[actions.addRepo], actions.addRepo))); result.delete.push(...parseRepoContents(prev.repos[actions.addRepo], actions.addRepo));
} }
return result; return result;
@@ -91,10 +96,6 @@ function parseRepoContents(repoContents: RepoContents, repository: string): Pack
}); });
} }
function getDropped(oldPackages: PackageInfo[], newPackages: PackageInfo[]): PackageInfo[] {
return oldPackages.filter(p => newPackages.filter(np => np.package === p.package).length === 0);
}
function isDelete(actions: Actions): boolean { function isDelete(actions: Actions): boolean {
return !!(actions.removeRepo && actions.addRepo === null); return !!(actions.removeRepo && actions.addRepo === null);
} }
@@ -107,6 +108,36 @@ function isMove(actions: Actions): boolean {
return !!(actions.removeRepo && actions.addRepo); return !!(actions.removeRepo && actions.addRepo);
} }
export function getDepRepo(destination: string): DependencyRepo {
const split = (destination || '').split('-');
switch(split[split.length - 1]) {
case 'testing':
case 'gremlins':
return 'testing';
case 'staging':
case 'goblins':
return 'staging';
default:
return 'stable';
}
}
export function getTier(destination: string): string {
const split = (destination || '').split('-');
switch(split[0]) {
case 'extra':
case 'world':
return '1';
case 'galaxy':
return '2';
case 'multilib':
case 'lib32':
return '3';
default:
return '0';
}
}
export async function tryRead(location: string): Promise<PkgBase | null> { export async function tryRead(location: string): Promise<PkgBase | null> {
try { try {
const contents = isUrl(location) ? await (await ky.get(location)).text() : await fsp.readFile(location, { encoding: 'utf-8' }); const contents = isUrl(location) ? await (await ky.get(location)).text() : await fsp.readFile(location, { encoding: 'utf-8' });

View File

@@ -31,6 +31,7 @@ export async function main() {
if (mode === 'move') { if (mode === 'move') {
for (const pkg of parsedData.move) { for (const pkg of parsedData.move) {
const filename = getFilename(pkg); const filename = getFilename(pkg);
console.log(`moving ${filename} from ${parsedData.actions.removeRepo} to ${parsedData.actions.addRepo} ...`);
const files = await ky.get(`${context.serverUrl}/api/v1/packages/${context.repo.owner}/arch/${pkg.package}/${pkg.version}/files`, { headers }).json<PackageFile[]>(); const files = await ky.get(`${context.serverUrl}/api/v1/packages/${context.repo.owner}/arch/${pkg.package}/${pkg.version}/files`, { headers }).json<PackageFile[]>();
const match = files.filter(f => f.name === filename); const match = files.filter(f => f.name === filename);
if (match.length !== 1) { if (match.length !== 1) {
@@ -42,11 +43,13 @@ export async function main() {
body, body,
headers headers
}); });
await ky.post(`${context.serverUrl}/api/v1/packages/${context.repo.owner}/arch/${pkg.package}/-/link/${context.repo.repo}`, { headers });
} }
await deletePackages(parsedData.move, headers); await deletePackages(parsedData.move, headers);
return; return;
} }
else if (mode === 'delete') { else if (mode === 'delete') {
console.log(`deleting ${parsedData.delete.join(', ') || 'no packages'} ...`);
await deletePackages(parsedData.delete, headers); await deletePackages(parsedData.delete, headers);
return; return;
} }
@@ -73,9 +76,12 @@ async function doParse() {
const previous = core.getInput('previous', { required: true }); const previous = core.getInput('previous', { required: true });
const current = getCurrent(); const current = getCurrent();
const diff = await parse(previous, current); const diff = await parse(previous, current);
console.log(diff);
core.setOutput('parsed-data', JSON.stringify(diff)); core.setOutput('parsed-data', JSON.stringify(diff));
core.setOutput('build', diff.build); core.setOutput('build', diff.build);
core.setOutput('move', diff.move.length > 0); core.setOutput('move', diff.move.length > 0);
core.setOutput('delete', diff.delete.length > 0); core.setOutput('delete', diff.delete.length > 0);
core.setOutput('destination', diff.actions.addRepo); core.setOutput('destination', diff.actions.addRepo);
core.setOutput('deps', diff.deps);
core.setOutput('tier', diff.tier);
} }

View File

@@ -1,6 +1,6 @@
import path from 'path'; import path from 'path';
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
import { parse, type Result } from '../src/pkgbase.js'; import { parse, getDepRepo, getTier, type Result } from '../src/pkgbase.js';
describe('pkgbase parser', () => { describe('pkgbase parser', () => {
it('can detect an add operation', async () => { it('can detect an add operation', async () => {
@@ -8,6 +8,8 @@ describe('pkgbase parser', () => {
build: true, build: true,
move: [], move: [],
delete: [], delete: [],
deps: 'staging',
tier: '0',
actions: { actions: {
addRepo: 'system-goblins', addRepo: 'system-goblins',
removeRepo: null, removeRepo: null,
@@ -27,6 +29,8 @@ describe('pkgbase parser', () => {
build: true, build: true,
move: [], move: [],
delete: [], delete: [],
deps: 'stable',
tier: '1',
actions: { actions: {
addRepo: 'world', addRepo: 'world',
removeRepo: null, removeRepo: null,
@@ -51,8 +55,22 @@ describe('pkgbase parser', () => {
package: "pidgin", package: "pidgin",
repository: "world", repository: "world",
version: "2.14.14-3", version: "2.14.14-3",
},
{
"architecture": "x86_64",
"package": "libpurple",
"repository": "world",
"version": "2.14.14-3",
},
{
"architecture": "x86_64",
"package": "finch",
"repository": "world",
"version": "2.14.14-3",
} }
], ],
deps: 'stable',
tier: '1',
actions: { actions: {
addRepo: 'world', addRepo: 'world',
removeRepo: null, removeRepo: null,
@@ -78,7 +96,14 @@ describe('pkgbase parser', () => {
version: "1:7.9.2-1", version: "1:7.9.2-1",
} }
], ],
delete: [], delete: [{
"architecture": "x86_64",
"package": "opencascade",
"repository": "world",
"version": "1:7.9.1-1",
}],
deps: 'stable',
tier: '1',
actions: { actions: {
addRepo: 'world', addRepo: 'world',
removeRepo: 'world-gremlins', removeRepo: 'world-gremlins',
@@ -116,8 +141,22 @@ describe('pkgbase parser', () => {
package: "pidgin", package: "pidgin",
repository: "world", repository: "world",
version: "2.14.14-3", version: "2.14.14-3",
},
{
"architecture": "x86_64",
"package": "libpurple",
"repository": "world",
"version": "2.14.14-3",
},
{
"architecture": "x86_64",
"package": "finch",
"repository": "world",
"version": "2.14.14-3",
} }
], ],
deps: 'stable',
tier: '1',
actions: { actions: {
addRepo: 'world', addRepo: 'world',
removeRepo: 'world-gremlins', removeRepo: 'world-gremlins',
@@ -129,7 +168,7 @@ describe('pkgbase parser', () => {
} }
}; };
const rDir = 'move-with-dropped'; const rDir = 'move-with-dropped';
await expect(parse(`https://git.sanin.dev/packages_test/pkgbase-yaml-parser/raw/branch/master/test/resources/${rDir}/pkgbase.old.yaml`, path.join('test', 'resources', rDir, 'pkgbase.new.yaml'))).resolves.toEqual(expected); await expect(parse(`https://git.sanin.dev/packages_infra/pkgbase-yaml-parser/raw/branch/master/test/resources/${rDir}/pkgbase.old.yaml`, path.join('test', 'resources', rDir, 'pkgbase.new.yaml'))).resolves.toEqual(expected);
}); });
it('can detect a delete operation', async () => { it('can detect a delete operation', async () => {
@@ -156,6 +195,8 @@ describe('pkgbase parser', () => {
version: "3.13.0-2", version: "3.13.0-2",
} }
], ],
deps: 'stable',
tier: '1',
actions: { actions: {
addRepo: null, addRepo: null,
removeRepo: 'world', removeRepo: 'world',
@@ -169,4 +210,15 @@ describe('pkgbase parser', () => {
const rDir = 'remove'; const rDir = 'remove';
await expect(parse(path.join('test', 'resources', rDir, 'pkgbase.old.yaml'), path.join('test', 'resources', rDir, 'pkgbase.new.yaml'))).resolves.toEqual(expected); await expect(parse(path.join('test', 'resources', rDir, 'pkgbase.old.yaml'), path.join('test', 'resources', rDir, 'pkgbase.new.yaml'))).resolves.toEqual(expected);
}); });
it('can handle Arch repos', async () => {
expect(getDepRepo('core')).to.be.equal('stable');
expect(getDepRepo('core-testing')).to.be.equal('testing');
expect(getDepRepo('extra-staging')).to.be.equal('staging');
expect(getTier('core-testing')).to.be.equal('0');
expect(getTier('extra')).to.be.equal('1');
expect(getTier('galaxy-goblins')).to.be.equal('2');
expect(getTier('multilib')).to.be.equal('3');
expect(getTier('lib32')).to.be.equal('3');
});
}); });