foreman_remote_execution 18.0.1 → 18.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/foreman_remote_execution/locale/fr/foreman_remote_execution.js +28 -28
- data/app/assets/javascripts/foreman_remote_execution/locale/ja/foreman_remote_execution.js +48 -48
- data/app/assets/javascripts/foreman_remote_execution/locale/ko/foreman_remote_execution.js +29 -29
- data/app/assets/javascripts/foreman_remote_execution/locale/zh_CN/foreman_remote_execution.js +22 -22
- data/app/assets/javascripts/foreman_remote_execution/template_invocation.js +0 -170
- data/app/assets/stylesheets/foreman_remote_execution/job_invocations.scss +0 -6
- data/app/controllers/job_invocations_controller.rb +1 -98
- data/app/helpers/job_invocations_helper.rb +0 -49
- data/app/helpers/remote_execution_helper.rb +23 -123
- data/config/routes.rb +0 -6
- data/lib/foreman_remote_execution/plugin.rb +2 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/foreman_remote_execution.pot +2 -2
- data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/fr/foreman_remote_execution.po +28 -28
- data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ja/foreman_remote_execution.po +48 -48
- data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ko/foreman_remote_execution.po +29 -29
- data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_CN/foreman_remote_execution.po +22 -22
- data/package.json +1 -14
- data/test/functional/job_invocations_controller_test.rb +0 -77
- data/webpack/JobInvocationDetail/JobInvocationConstants.js +5 -0
- data/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js +0 -10
- data/webpack/JobInvocationDetail/TemplateInvocation.js +12 -69
- data/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputCodeBlock.js +94 -72
- data/webpack/JobInvocationDetail/TemplateInvocationHelpers.js +33 -0
- data/webpack/JobInvocationDetail/__tests__/JobInvocationDetailEmptyState.test.js +1 -1
- data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +0 -6
- data/webpack/JobInvocationDetail/__tests__/OutputCodeBlock.test.js +1 -1
- data/webpack/JobInvocationDetail/__tests__/TableToolbarActions.test.js +1 -1
- data/webpack/JobInvocationDetail/__tests__/TemplateInvocation.test.js +5 -1
- data/webpack/JobInvocationDetail/__tests__/TemplateInvocationHelpers.test.js +94 -0
- data/webpack/JobInvocationDetail/__tests__/TemplateInvocationPolling.test.js +338 -139
- data/webpack/JobInvocationDetail/useTemplateInvocationOutputPolling.js +185 -0
- data/webpack/JobWizard/JobWizardPageRerun.js +0 -10
- data/webpack/JobWizard/__tests__/autofill.test.js +23 -0
- data/webpack/JobWizard/__tests__/integration.test.js +1 -1
- data/webpack/JobWizard/autofill.js +18 -4
- data/webpack/JobWizard/index.js +1 -18
- data/webpack/JobWizard/steps/HostsAndInputs/__tests__/HostsAndInputs.test.js +49 -1
- data/webpack/global_index.js +0 -2
- data/webpack/index.js +0 -15
- data/webpack/react_app/components/RegistrationExtension/__tests__/RexInterface.test.js +1 -1
- metadata +6 -53
- data/app/assets/stylesheets/foreman_remote_execution/modal_window.scss +0 -4
- data/app/helpers/job_invocations_chart_helper.rb +0 -80
- data/app/views/job_invocations/_card_results.html.erb +0 -12
- data/app/views/job_invocations/_card_schedule.html.erb +0 -33
- data/app/views/job_invocations/_card_target_hosts.html.erb +0 -57
- data/app/views/job_invocations/_card_user_input.html.erb +0 -16
- data/app/views/job_invocations/_description_fields.html.erb +0 -4
- data/app/views/job_invocations/_form.html.erb +0 -144
- data/app/views/job_invocations/_preview_hosts_modal.html.erb +0 -15
- data/app/views/job_invocations/_rerun_taxonomies.html.erb +0 -22
- data/app/views/job_invocations/_tab_hosts.html.erb +0 -11
- data/app/views/job_invocations/_tab_overview.html.erb +0 -41
- data/app/views/job_invocations/_tab_preview_templates.html.erb +0 -20
- data/app/views/job_invocations/_user_input.html.erb +0 -21
- data/app/views/job_invocations/new.html.erb +0 -9
- data/app/views/job_invocations/refresh.js.erb +0 -4
- data/app/views/job_invocations/show.html.erb +0 -59
- data/app/views/job_invocations/show.js.erb +0 -12
- data/app/views/job_invocations/show.json.erb +0 -5
- data/test/support/remote_execution_helper.rb +0 -5
- data/webpack/react_app/components/TargetingHosts/TargetingHosts.js +0 -62
- data/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js +0 -2
- data/webpack/react_app/components/TargetingHosts/TargetingHostsHelpers.js +0 -10
- data/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.js +0 -45
- data/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.scss +0 -30
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.js +0 -78
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.scss +0 -3
- data/webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js +0 -25
- data/webpack/react_app/components/TargetingHosts/__tests__/HostItem.test.js +0 -76
- data/webpack/react_app/components/TargetingHosts/__tests__/HostStatus.test.js +0 -6
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHosts.test.js +0 -6
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsPage.test.js +0 -9
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsSelectors.test.js +0 -31
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +0 -12
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap +0 -96
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +0 -75
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +0 -16
- data/webpack/react_app/components/TargetingHosts/__tests__/fixtures.js +0 -56
- data/webpack/react_app/components/TargetingHosts/components/HostItem.js +0 -39
- data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +0 -54
- data/webpack/react_app/components/TargetingHosts/index.js +0 -150
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.js +0 -60
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +0 -76
- data/webpack/react_app/components/jobInvocations/index.js +0 -94
- data/webpack/react_app/extend/reducers.js +0 -5
- data/webpack/react_app/redux/actions/jobInvocations/index.js +0 -87
- data/webpack/react_app/redux/consts.js +0 -5
- data/webpack/react_app/redux/reducers/index.js +0 -6
- data/webpack/react_app/redux/reducers/jobInvocations/index.fixtures.js +0 -46
- data/webpack/react_app/redux/reducers/jobInvocations/index.js +0 -34
- data/webpack/react_app/redux/reducers/jobInvocations/index.test.js +0 -43
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const getLastOutputTimestamp = output =>
|
|
2
|
+
output.length ? output[output.length - 1].timestamp : null;
|
|
3
|
+
|
|
4
|
+
export const normalizeOutput = output =>
|
|
5
|
+
output.reduce((normalized, lineSet) => {
|
|
6
|
+
const previousLineSet = normalized[normalized.length - 1];
|
|
7
|
+
|
|
8
|
+
if (
|
|
9
|
+
previousLineSet &&
|
|
10
|
+
previousLineSet.output_type === lineSet.output_type &&
|
|
11
|
+
!previousLineSet.output.endsWith('\n')
|
|
12
|
+
) {
|
|
13
|
+
const firstCompleteLine = lineSet.output.match(/^[^\n]*\n/);
|
|
14
|
+
if (firstCompleteLine) {
|
|
15
|
+
normalized[normalized.length - 1] = {
|
|
16
|
+
...previousLineSet,
|
|
17
|
+
output: previousLineSet.output + firstCompleteLine[0],
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const remainder = lineSet.output.slice(firstCompleteLine[0].length);
|
|
21
|
+
if (remainder) normalized.push({ ...lineSet, output: remainder });
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
normalized.push(lineSet);
|
|
27
|
+
return normalized;
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
export const mergeOutput = (currentOutput, newOutput) => {
|
|
31
|
+
if (!newOutput.length) return currentOutput;
|
|
32
|
+
return normalizeOutput([...currentOutput, ...newOutput]);
|
|
33
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
import { createMemoryHistory } from 'history';
|
|
5
5
|
import { Router } from 'react-router-dom';
|
|
6
6
|
import JobInvocationEmptyState from '../JobInvocationEmptyState';
|
|
@@ -245,12 +245,6 @@ describe('JobInvocationDetailPage', () => {
|
|
|
245
245
|
expect(screen.getByText('Abort')).toBeInTheDocument();
|
|
246
246
|
expect(screen.queryByText('Enable recurring')).not.toBeInTheDocument();
|
|
247
247
|
expect(screen.queryByText('Cancel recurring')).not.toBeInTheDocument();
|
|
248
|
-
expect(
|
|
249
|
-
screen
|
|
250
|
-
.getByText('Legacy UI')
|
|
251
|
-
.closest('a')
|
|
252
|
-
.getAttribute('href')
|
|
253
|
-
).toEqual(`/legacy/job_invocations/${jobId}`);
|
|
254
248
|
});
|
|
255
249
|
|
|
256
250
|
it('keeps toolbar buttons mounted while job invocation data is refreshing', async () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
import { OutputCodeBlock } from '../TemplateInvocationComponents/OutputCodeBlock';
|
|
5
5
|
import { jobInvocationOutput } from './fixtures';
|
|
6
6
|
|
|
@@ -2,13 +2,16 @@ import React from 'react';
|
|
|
2
2
|
import configureMockStore from 'redux-mock-store';
|
|
3
3
|
import { Provider } from 'react-redux';
|
|
4
4
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
5
|
-
import '@testing-library/jest-dom
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
7
|
+
import API from 'foremanReact/API';
|
|
6
8
|
import * as api from 'foremanReact/redux/API';
|
|
7
9
|
import * as selectors from '../JobInvocationSelectors';
|
|
8
10
|
import { TemplateInvocation } from '../TemplateInvocation';
|
|
9
11
|
import { mockTemplateInvocationResponse } from './fixtures';
|
|
10
12
|
|
|
11
13
|
jest.spyOn(api, 'get');
|
|
14
|
+
jest.mock('foremanReact/API');
|
|
12
15
|
jest.mock('../JobInvocationSelectors');
|
|
13
16
|
|
|
14
17
|
jest.mock('foremanReact/components/ToastsList', () => ({
|
|
@@ -47,6 +50,7 @@ const mockProps = {
|
|
|
47
50
|
|
|
48
51
|
describe('TemplateInvocation', () => {
|
|
49
52
|
beforeEach(() => {
|
|
53
|
+
API.get.mockImplementation(() => new Promise(() => {}));
|
|
50
54
|
selectors.selectTemplateInvocationStatus.mockImplementation(() => () =>
|
|
51
55
|
'RESOLVED'
|
|
52
56
|
);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getLastOutputTimestamp,
|
|
3
|
+
mergeOutput,
|
|
4
|
+
normalizeOutput,
|
|
5
|
+
} from '../TemplateInvocationHelpers';
|
|
6
|
+
|
|
7
|
+
describe('TemplateInvocationHelpers', () => {
|
|
8
|
+
describe('getLastOutputTimestamp', () => {
|
|
9
|
+
it('returns null for empty output', () => {
|
|
10
|
+
expect(getLastOutputTimestamp([])).toBeNull();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('returns the timestamp of the last output chunk', () => {
|
|
14
|
+
expect(
|
|
15
|
+
getLastOutputTimestamp([
|
|
16
|
+
{ timestamp: 1, output: 'first\n' },
|
|
17
|
+
{ timestamp: 2, output: 'second\n' },
|
|
18
|
+
])
|
|
19
|
+
).toBe(2);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('normalizeOutput', () => {
|
|
24
|
+
it('joins lines split between chunks in one response', () => {
|
|
25
|
+
const result = normalizeOutput([
|
|
26
|
+
{ timestamp: 1, output_type: 'stdout', output: 'hel' },
|
|
27
|
+
{
|
|
28
|
+
timestamp: 2,
|
|
29
|
+
output_type: 'stdout',
|
|
30
|
+
output: 'lo\r\nworld\r\n',
|
|
31
|
+
},
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
expect(result).toEqual([
|
|
35
|
+
{ timestamp: 1, output_type: 'stdout', output: 'hello\r\n' },
|
|
36
|
+
{ timestamp: 2, output_type: 'stdout', output: 'world\r\n' },
|
|
37
|
+
]);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('mergeOutput', () => {
|
|
42
|
+
it('appends new chunks without changing existing objects', () => {
|
|
43
|
+
const existingChunk = { timestamp: 1, output: 'first\n' };
|
|
44
|
+
const newChunk = { timestamp: 2, output: 'second\n' };
|
|
45
|
+
|
|
46
|
+
const result = mergeOutput([existingChunk], [newChunk]);
|
|
47
|
+
|
|
48
|
+
expect(result).toEqual([existingChunk, newChunk]);
|
|
49
|
+
expect(result[0]).toBe(existingChunk);
|
|
50
|
+
expect(result[1]).toBe(newChunk);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('joins a line split across two polling responses', () => {
|
|
54
|
+
const result = mergeOutput(
|
|
55
|
+
[{ timestamp: 1, output: 'partial ' }],
|
|
56
|
+
[{ timestamp: 2, output: 'line\nnext line\n' }]
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(result).toEqual([
|
|
60
|
+
{ timestamp: 1, output: 'partial line\n' },
|
|
61
|
+
{ timestamp: 2, output: 'next line\n' },
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('does not join chunks of different output types', () => {
|
|
66
|
+
const result = mergeOutput(
|
|
67
|
+
[{ timestamp: 1, output_type: 'stdout', output: 'partial ' }],
|
|
68
|
+
[{ timestamp: 2, output_type: 'stderr', output: 'error\n' }]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(result).toEqual([
|
|
72
|
+
{ timestamp: 1, output_type: 'stdout', output: 'partial ' },
|
|
73
|
+
{ timestamp: 2, output_type: 'stderr', output: 'error\n' },
|
|
74
|
+
]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('does not append an empty chunk after completing a split line', () => {
|
|
78
|
+
const result = mergeOutput(
|
|
79
|
+
[{ timestamp: 1, output_type: 'stdout', output: 'partial ' }],
|
|
80
|
+
[{ timestamp: 2, output_type: 'stdout', output: 'line\n' }]
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect(result).toEqual([
|
|
84
|
+
{ timestamp: 1, output_type: 'stdout', output: 'partial line\n' },
|
|
85
|
+
]);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('returns the current output when there is nothing to append', () => {
|
|
89
|
+
const currentOutput = [{ timestamp: 1, output: 'first\n' }];
|
|
90
|
+
|
|
91
|
+
expect(mergeOutput(currentOutput, [])).toBe(currentOutput);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|