Skip to content

Commit

Permalink
feat(package): allow installation of github-releases
Browse files Browse the repository at this point in the history
New
`xst package install github-release <abbrev>`

Moved command
`xst package install <packages..>`
Replace with
`xst package install local <packages..>`
  • Loading branch information
line-o committed Feb 14, 2024
1 parent c2b8bfa commit b7510af
Show file tree
Hide file tree
Showing 10 changed files with 484 additions and 133 deletions.
2 changes: 1 addition & 1 deletion commands/package/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as install from './install.js'
import * as install from './install/index.js'
import * as list from './list.js'
import * as uninstall from './uninstall.js'

Expand Down
131 changes: 0 additions & 131 deletions commands/package/install.js

This file was deleted.

163 changes: 163 additions & 0 deletions commands/package/install/github.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { connect } from '@existdb/node-exist'
import { got } from 'got'
import { valid, gt } from 'semver'
// import { basename } from 'node:path'

import { isDBAdmin, getServerUrl } from '../../../utility/connection.js'
import { uploadMethod, removeTemporaryCollection, getInstalledVersion } from '../../../utility/package.js'

async function getRelease (api, owner, repo, release, assetFilter) {
const path = `repos/${owner}/${repo}/releases/${release}`
const { assets, name } = await got.get(path, { prefixUrl: api }).json()
const f = assets.filter(assetFilter)
if (!f.length) {
throw Error('no matching asset found')
}
if (f.length > 1) {
throw Error('more than one matching asset found')
}
return {
xarName: f[0].name,
packageContents: f[0].browser_download_url,
releaseName: name
}
}

async function install (db, upload, xarName, contents, registry) {
// const xarName = basename(localFilePath)
// const contents = readFileSync(localFilePath)

const uploadResult = await upload(contents, xarName)
if (!uploadResult.success) {
throw new Error(uploadResult.error)
}

console.log('✔︎ uploaded')

const installResult = await db.app.install(xarName, registry)

if (!installResult.success) {
throw new Error(installResult.error)
}

const installationMessage = installResult.result.update ? 'updated' : 'installed'
console.log(`✔︎ ${installationMessage}`)

return 0
}

export const command = ['github-release <abbrev>', 'gh']
export const describe = 'Install a XAR package from a github release'
const options = {
rest: {
describe: 'force upload over REST API',
type: 'boolean'
},
xmlrpc: {
alias: 'rpc',
describe: 'force upload over XML-RPC API',
type: 'boolean'
},
f: {
alias: 'force',
describe: 'Force installation, skip version check'
},
release: {
describe: 'Install a specific release',
default: 'latest',
type: 'string'
},
owner: {
describe: 'The owner of the repository',
default: 'eXist-db',
type: 'string'
},
repo: {
describe: 'The name of the repository, if it differs from abbrev',
type: 'string'
},
registry: {
describe: 'Where to resolve dependencies from, if they are not already installed',
default: 'https://exist-db.org/exist/apps/public-repo/',
type: 'string'
},
api: {
describe: 'Connect to a different github server',
default: 'https://api.github.com',
type: 'string'
},
A: {
alias: 'asset',
describe: 'Pattern to match the package file.',
default: '<abbrev>-<version>.xar'
},
T: {
alias: 'tag-prefix',
describe: 'How to read the version from the associated git-tag',
default: 'v',
type: 'string'
},
debug: {
type: 'boolean',
default: false
}
}

export const builder = yargs => {
return yargs.options(options)
.conflicts('xmlrpc', 'rest')
}

export async function handler (argv) {
if (argv.help) {
return 0
}

// main
const {
abbrev, api, force, T, owner, release, registry,
connectionOptions, rest, xmlrpc
} = argv

const repo = argv.repo && argv.repo !== '' ? argv.repo : abbrev
// check permissions (and therefore implicitly the connection)
const db = connect(connectionOptions)
isDBAdmin(db)

const upload = await uploadMethod(db, connectionOptions, xmlrpc, rest)
const tagMatcher = new RegExp(`^${T}(?<version>.+)$`)

// const r = false ? new RegExp(`${asset}`) : new RegExp(`^${abbrev}.*\\.xar$`)
const r = new RegExp(`^${abbrev}.*\\.xar$`)
const assetFilter = a => { return r.test(a.name) }

try {
const installedVersion = await getInstalledVersion(db, abbrev)
const { xarName, packageContents, releaseName } = await getRelease(api, owner, repo, release, assetFilter)
const foundVersion = tagMatcher.exec(releaseName).groups.version
console.log(`Install ${abbrev} on ${getServerUrl(db)}`)
// if (debug) {
// console.debug('released:', valid(foundVersion))
// console.debug('installed:', valid(installedVersion))
// }

if (valid(foundVersion) === null) {
throw Error('Package does not have a valid semver "' + foundVersion + '"')
}

const doUpdate = (installedVersion === null || force || gt(foundVersion, installedVersion))

if (!doUpdate) {
console.log(`Version ${installedVersion} is already installed, nothing to do.`)
return 0
}

const assetDownload = await got.get(packageContents)

await install(db, upload, xarName, assetDownload.rawBody, registry)
} finally {
await removeTemporaryCollection(db)
}

return 0
}
31 changes: 31 additions & 0 deletions commands/package/install/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as local from './local.js'
import * as github from './github.js'
// import * as registry from './registry.js'

const commands = [
local,
github
// registry
]

export const command = ['install <command>', 'i']
export const describe = 'Install XAR packages'
export async function handler (argv) {
if (argv.help) {
return 0
}
}

const options = {
registry: {
describe: 'Where to resolve dependencies from, if they are not already installed',
default: 'https://exist-db.org/exist/apps/public-repo/'
}
}

export const builder = function (yargs) {
return yargs
.options(options)
.command(commands)
.recommendCommands()
}
Loading

0 comments on commit b7510af

Please sign in to comment.