-
Notifications
You must be signed in to change notification settings - Fork 1
New: support git URL/ref plugin install and source persistence #96
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,15 @@ | |
| "description": "Whether the plugin has been installed locally (as opposed to with the CLI)", | ||
| "type": "boolean" | ||
| }, | ||
| "gitUrl": { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add "gitUrl": {
"description": "The HTTPS git URL this plugin was installed from, if applicable",
"type": "string",
"format": "uri"
} |
||
| "description": "The HTTPS git URL this plugin was installed from, if applicable", | ||
| "type": "string", | ||
| "format": "uri" | ||
| }, | ||
| "gitRef": { | ||
| "description": "The git branch, tag, or commit this plugin was installed from, if applicable", | ||
| "type": "string" | ||
| }, | ||
| "isEnabled": { | ||
| "description": "", | ||
| "type": "boolean", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| import { describe, it, mock } from 'node:test' | ||
| import assert from 'node:assert/strict' | ||
| import ContentPluginModule from '../lib/ContentPluginModule.js' | ||
|
|
||
| describe('ContentPluginModule.installPlugin()', () => { | ||
| it('should install git URLs directly and persist gitUrl/gitRef', async () => { | ||
| const runCliCommand = mock.fn(async () => [{ | ||
| isInstallSuccessful: true, | ||
| getInfo: async () => ({ name: 'adapt-hotgrid', version: '2.0.0', targetAttribute: '_component' }), | ||
| getType: async () => 'component' | ||
| }]) | ||
| const insertOrUpdate = mock.fn(async (data) => data) | ||
| const processPluginFiles = mock.fn(async () => { | ||
| throw new Error('processPluginFiles should not be called for git installs') | ||
| }) | ||
| const context = { | ||
| framework: { runCliCommand }, | ||
| processPluginFiles, | ||
| insertOrUpdate, | ||
| findOne: mock.fn(async () => ({ name: 'adapt-hotgrid', version: '999.0.0' })), | ||
| processPluginSchemas: mock.fn(async () => {}), | ||
| app: { | ||
| errors: { | ||
| CONTENTPLUGIN_ALREADY_EXISTS: { setData: (data) => Object.assign(new Error('already exists'), { data }) }, | ||
| CONTENTPLUGIN_CLI_INSTALL_FAILED: { setData: (data) => Object.assign(new Error('cli failed'), { data }) }, | ||
| CONTENTPLUGIN_ATTR_MISSING: { setData: (data) => Object.assign(new Error('attr missing'), { data }) } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const result = await ContentPluginModule.prototype.installPlugin.call( | ||
| context, | ||
| '', | ||
| 'https://github.com/org/adapt-hotgrid.git#v2.0.0', | ||
| { force: false } | ||
| ) | ||
|
|
||
| assert.equal(runCliCommand.mock.calls[0].arguments[0], 'installPlugins') | ||
| assert.deepEqual(runCliCommand.mock.calls[0].arguments[1], { | ||
| plugins: ['https://github.com/org/adapt-hotgrid.git#v2.0.0'] | ||
| }) | ||
| assert.equal(context.findOne.mock.callCount(), 0) | ||
| assert.equal(processPluginFiles.mock.callCount(), 0) | ||
| assert.equal(insertOrUpdate.mock.calls[0].arguments[0].gitUrl, 'https://github.com/org/adapt-hotgrid.git') | ||
| assert.equal(insertOrUpdate.mock.calls[0].arguments[0].gitRef, 'v2.0.0') | ||
| assert.equal(result.name, 'adapt-hotgrid') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Error paths are not covered — this test only exercises the happy path ( Consider adding two cases:
|
||
| }) | ||
|
|
||
| it('should throw install failure with CLI plugin name and not persist failed install', async () => { | ||
| const runCliCommand = mock.fn(async () => [{ | ||
| name: 'adapt-hotgrid', | ||
| isInstallSuccessful: false | ||
| }]) | ||
| const insertOrUpdate = mock.fn(async (data) => data) | ||
| const context = { | ||
| framework: { runCliCommand }, | ||
| insertOrUpdate, | ||
| processPluginSchemas: mock.fn(async () => {}), | ||
| app: { | ||
| errors: { | ||
| CONTENTPLUGIN_CLI_INSTALL_FAILED: { setData: (data) => Object.assign(new Error('cli failed'), { data }) }, | ||
| CONTENTPLUGIN_ATTR_MISSING: { setData: (data) => Object.assign(new Error('attr missing'), { data }) } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| await assert.rejects( | ||
| ContentPluginModule.prototype.installPlugin.call(context, '', 'https://github.com/org/adapt-hotgrid.git#v2.0.0'), | ||
| e => { | ||
| assert.equal(e.message, 'cli failed') | ||
| assert.equal(e.data.name, 'adapt-hotgrid') | ||
| return true | ||
| } | ||
| ) | ||
| assert.equal(insertOrUpdate.mock.callCount(), 0) | ||
| }) | ||
|
|
||
| it('should throw missing attr with resolved plugin name', async () => { | ||
| const runCliCommand = mock.fn(async () => [{ | ||
| name: 'adapt-hotgrid', | ||
| isInstallSuccessful: true, | ||
| getInfo: async () => ({ name: 'adapt-hotgrid', version: '2.0.0' }), | ||
| getType: async () => 'component' | ||
| }]) | ||
| const insertOrUpdate = mock.fn(async (data) => data) | ||
| const context = { | ||
| framework: { runCliCommand }, | ||
| insertOrUpdate, | ||
| processPluginSchemas: mock.fn(async () => {}), | ||
| app: { | ||
| errors: { | ||
| CONTENTPLUGIN_CLI_INSTALL_FAILED: { setData: (data) => Object.assign(new Error('cli failed'), { data }) }, | ||
| CONTENTPLUGIN_ATTR_MISSING: { setData: (data) => Object.assign(new Error('attr missing'), { data }) } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| await assert.rejects( | ||
| ContentPluginModule.prototype.installPlugin.call(context, '', 'https://github.com/org/adapt-hotgrid.git#v2.0.0'), | ||
| e => { | ||
| assert.equal(e.message, 'attr missing') | ||
| assert.equal(e.data.name, 'adapt-hotgrid') | ||
| return true | ||
| } | ||
| ) | ||
| }) | ||
| }) | ||
|
|
||
| describe('ContentPluginModule.getMissingPlugins()', () => { | ||
| it('should return gitUrl and gitRef for missing git-installed plugins', async () => { | ||
| const context = { | ||
| find: async () => ([ | ||
| { | ||
| name: 'adapt-hotgrid', | ||
| version: '2.0.0', | ||
| isLocalInstall: false, | ||
| gitUrl: 'https://github.com/org/adapt-hotgrid.git', | ||
| gitRef: 'v2.0.0' | ||
| }, | ||
| { name: 'adapt-text', version: '1.0.0', isLocalInstall: false } | ||
| ]), | ||
| framework: { | ||
| getManifestPlugins: async () => [], | ||
| getInstalledPlugins: async () => [] | ||
| } | ||
| } | ||
| const result = await ContentPluginModule.prototype.getMissingPlugins.call(context) | ||
| assert.deepEqual(result, [ | ||
| 'https://github.com/org/adapt-hotgrid.git#v2.0.0', | ||
| 'adapt-text@1.0.0' | ||
| ]) | ||
| }) | ||
| }) | ||
|
|
||
| describe('ContentPluginModule.syncPluginData()', () => { | ||
| it('should persist gitUrl and gitRef for git sources', async () => { | ||
| const insertOrUpdate = mock.fn(async () => {}) | ||
| const context = { | ||
| log: mock.fn(), | ||
| find: async () => [], | ||
| insertOrUpdate, | ||
| framework: { | ||
| runCliCommand: async () => ([ | ||
| { | ||
| name: 'adapt-hotgrid', | ||
| matchedVersion: '2.0.0', | ||
| isLocalSource: false, | ||
| isGitSource: true, | ||
| gitUrl: 'https://github.com/org/adapt-hotgrid.git', | ||
| gitRef: 'v2.0.0', | ||
| getInfo: async () => ({ name: 'adapt-hotgrid', version: '2.0.0' }), | ||
| getType: async () => 'component' | ||
| } | ||
| ]) | ||
| } | ||
| } | ||
|
|
||
| await ContentPluginModule.prototype.syncPluginData.call(context) | ||
|
|
||
| assert.equal(insertOrUpdate.mock.calls[0].arguments[0].gitUrl, 'https://github.com/org/adapt-hotgrid.git') | ||
| assert.equal(insertOrUpdate.mock.calls[0].arguments[0].gitRef, 'v2.0.0') | ||
| }) | ||
| }) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gitRefis stripped and never stored —versionOrPath.split('#')[0]discards the branch/tag before saving. WhengetMissingPluginsreturnsp.gitUrlon a restart, the CLI installs from the default branch HEAD rather than the originally-pinned ref.The schema needs a
gitReffield alongsidegitUrl, and it should be stored here:Then in
dbData:if (isGitUrl) { dbData.gitUrl = gitUrl; dbData.gitRef = gitRef }And
getMissingPluginsshould reconstruct the full URL:This also fixes the NO_CHANGE detection issue in adaptframework-extras PR #10 once it compares
existing?.gitRef === (ref ?? null)as well.