foreman_remote_execution 3.2.1 → 3.3.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/.eslintrc +5 -30
- data/.gitignore +1 -0
- data/.hound.yml +0 -5
- data/.travis.yml +2 -3
- data/app/lib/actions/remote_execution/run_host_job.rb +3 -2
- data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +3 -0
- data/app/models/remote_execution_provider.rb +5 -0
- data/app/services/default_proxy_proxy_selector.rb +18 -0
- data/db/seeds.d/70-job_templates.rb +1 -1
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/package.json +16 -33
- data/webpack/index.js +1 -2
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.js +10 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +6 -3
- data/webpack/react_app/components/jobInvocations/index.js +19 -7
- data/webpack/react_app/redux/actions/jobInvocations/index.js +12 -8
- data/webpack/react_app/redux/consts.js +1 -2
- data/webpack/react_app/redux/reducers/jobInvocations/index.fixtures.js +8 -40
- data/webpack/react_app/redux/reducers/jobInvocations/index.test.js +17 -11
- data/webpack/test_setup.js +2 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d00f4722f74258ad947432c2d8104522d3fb53749f7bac4e7c52914862af3ecc
|
4
|
+
data.tar.gz: 187645d51578339523b94fb83fe781cba865477a616c2d8c0980255be1fd0377
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04c6a44e96bb03d75310d7dd48acd249503f04778c62f520d1101bf4719d195c2cd4d11e9a6ae63c97e24d8cbd50884dd090ec56a54aff933ee19f3379bbeec1
|
7
|
+
data.tar.gz: 165ba49b54b18ed4128c7b72a53ef52fea60f6f9a619ee7bd0a22545910cf68997b763e27f3569892b20dd528e70236c44b241c1d1b6c5fcec15a5a21f76af7e
|
data/.eslintrc
CHANGED
@@ -1,32 +1,7 @@
|
|
1
1
|
{
|
2
|
-
"
|
3
|
-
"extends": [
|
4
|
-
|
5
|
-
"
|
6
|
-
]
|
7
|
-
"env": {
|
8
|
-
"browser": true,
|
9
|
-
"es6": true,
|
10
|
-
"node": true,
|
11
|
-
"jasmine": true,
|
12
|
-
"jest": true
|
13
|
-
},
|
14
|
-
"parser": "babel-eslint",
|
15
|
-
"rules": {
|
16
|
-
"react/jsx-uses-vars": "error",
|
17
|
-
"react/jsx-uses-react": "error",
|
18
|
-
"no-unused-vars": [
|
19
|
-
"error",
|
20
|
-
{
|
21
|
-
"vars": "all",
|
22
|
-
"args": "none"
|
23
|
-
}
|
24
|
-
],
|
25
|
-
"no-underscore-dangle": "off",
|
26
|
-
"no-use-before-define": "off",
|
27
|
-
"import/prefer-default-export": "off",
|
28
|
-
// Import rules off for now due to HoundCI issue
|
29
|
-
"import/no-unresolved": "off",
|
30
|
-
"import/extensions": "off"
|
31
|
-
}
|
2
|
+
"plugins": ["@theforeman/foreman"],
|
3
|
+
"extends": [
|
4
|
+
"plugin:@theforeman/foreman/core",
|
5
|
+
"plugin:@theforeman/foreman/plugins"
|
6
|
+
]
|
32
7
|
}
|
data/.gitignore
CHANGED
data/.hound.yml
CHANGED
data/.travis.yml
CHANGED
@@ -29,6 +29,9 @@ module Actions
|
|
29
29
|
|
30
30
|
raise _('Could not use any template used in the job invocation') if template_invocation.blank?
|
31
31
|
|
32
|
+
provider = template_invocation.template.provider
|
33
|
+
proxy_selector = provider.required_proxy_selector_for(template_invocation.template) || proxy_selector
|
34
|
+
|
32
35
|
provider_type = template_invocation.template.provider_type.to_s
|
33
36
|
proxy = determine_proxy!(proxy_selector, provider_type, host)
|
34
37
|
|
@@ -36,8 +39,6 @@ module Actions
|
|
36
39
|
script = renderer.render
|
37
40
|
raise _('Failed rendering template: %s') % renderer.error_message unless script
|
38
41
|
|
39
|
-
provider = template_invocation.template.provider
|
40
|
-
|
41
42
|
additional_options = { :hostname => provider.find_ip_or_hostname(host),
|
42
43
|
:script => script,
|
43
44
|
:execution_timeout_interval => job_invocation.execution_timeout_interval,
|
@@ -13,6 +13,9 @@ module ForemanRemoteExecution
|
|
13
13
|
proxy = ::SmartProxy.find(proxy_id)
|
14
14
|
begin
|
15
15
|
proxy.drop_host_from_known_hosts(target)
|
16
|
+
rescue RestClient::ResourceNotFound => e
|
17
|
+
# ignore 404 when known_hosts entry is missing or the module was not enabled
|
18
|
+
Foreman::Logging.exception "Proxy failed to delete SSH known_hosts for #{name}, #{ip}", e, :level => :error
|
16
19
|
rescue => e
|
17
20
|
Rails.logger.warn e.message
|
18
21
|
return false
|
@@ -98,5 +98,10 @@ class RemoteExecutionProvider
|
|
98
98
|
def proxy_action_class
|
99
99
|
ForemanRemoteExecutionCore::Actions::RunScript
|
100
100
|
end
|
101
|
+
|
102
|
+
# Return a specific proxy selector to use for running a given template
|
103
|
+
# Returns either nil to use the default selector or an instance of a (sub)class of ::ForemanTasks::ProxySelector
|
104
|
+
def required_proxy_selector_for(_template)
|
105
|
+
end
|
101
106
|
end
|
102
107
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class DefaultProxyProxySelector < ::RemoteExecutionProxySelector
|
2
|
+
def initialize
|
3
|
+
# TODO: Remove this once we have a reliable way of determining the internal proxy without katello
|
4
|
+
# Tracked as https://projects.theforeman.org/issues/29840
|
5
|
+
raise _('Internal proxy selector can only be used if Katello is enabled') unless defined?(::Katello)
|
6
|
+
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def available_proxies(host, provider)
|
11
|
+
# TODO: Once we have a internal proxy marker/feature on the proxy, we can
|
12
|
+
# swap the implementation
|
13
|
+
internal_proxy = ::Katello.default_capsule
|
14
|
+
super.reduce({}) do |acc, (key, proxies)|
|
15
|
+
acc.merge(key => proxies.select { |proxy| proxy == internal_proxy })
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,7 +4,7 @@ User.as_anonymous_admin do
|
|
4
4
|
JobTemplate.without_auditing do
|
5
5
|
Dir[File.join("#{ForemanRemoteExecution::Engine.root}/app/views/templates/**/*.erb")].each do |template|
|
6
6
|
sync = !Rails.env.test? && Setting[:remote_execution_sync_templates]
|
7
|
-
template = JobTemplate.import_raw!(File.read(template), :default => true, :
|
7
|
+
template = JobTemplate.import_raw!(File.read(template), :default => true, :lock => true, :update => sync)
|
8
8
|
template.organizations = organizations if template.present?
|
9
9
|
template.locations = locations if template.present?
|
10
10
|
end
|
data/package.json
CHANGED
@@ -3,25 +3,14 @@
|
|
3
3
|
"version": "1.0.0",
|
4
4
|
"license": "GPL-3.0",
|
5
5
|
"scripts": {
|
6
|
-
"lint": "
|
7
|
-
"test": "
|
8
|
-
"test:watch": "
|
9
|
-
"test:current": "
|
10
|
-
|
11
|
-
|
12
|
-
"
|
13
|
-
"
|
14
|
-
"node_modules",
|
15
|
-
"webpack"
|
16
|
-
],
|
17
|
-
"setupFiles": [
|
18
|
-
"raf/polyfill",
|
19
|
-
"./webpack/test_setup.js"
|
20
|
-
],
|
21
|
-
"testPathIgnorePatterns": [
|
22
|
-
"/node_modules/",
|
23
|
-
"<rootDir>/foreman/"
|
24
|
-
]
|
6
|
+
"lint": "tfm-lint --plugin -d /webpack",
|
7
|
+
"test": "tfm-test --plugin",
|
8
|
+
"test:watch": "tfm-test --plugin --watchAll",
|
9
|
+
"test:current": "tfm-test --plugin --watch",
|
10
|
+
"publish-coverage": "tfm-publish-coverage",
|
11
|
+
"stories": "tfm-stories --plugin",
|
12
|
+
"stories:build": "tfm-build-stories --plugin",
|
13
|
+
"stories:deploy": "surge --project .storybook-dist"
|
25
14
|
},
|
26
15
|
"repository": {
|
27
16
|
"type": "git",
|
@@ -32,22 +21,16 @@
|
|
32
21
|
},
|
33
22
|
"devDependencies": {
|
34
23
|
"@babel/core": "^7.7.0",
|
35
|
-
"@theforeman/builder": "^4.
|
36
|
-
"@theforeman/
|
24
|
+
"@theforeman/builder": "^4.2.1",
|
25
|
+
"@theforeman/eslint-plugin-foreman": "^4.2.1",
|
26
|
+
"@theforeman/stories": "^4.2.1",
|
27
|
+
"@theforeman/test": "^4.2.1",
|
28
|
+
"@theforeman/vendor-dev": "^4.2.1",
|
37
29
|
"babel-eslint": "^10.0.0",
|
38
|
-
"
|
39
|
-
"
|
40
|
-
"enzyme-adapter-react-16": "^1.1.0",
|
41
|
-
"enzyme-to-json": "^3.1.2",
|
42
|
-
"eslint": "^4.10.0",
|
43
|
-
"eslint-config-airbnb": "^16.0.0",
|
44
|
-
"eslint-plugin-import": "^2.8.0",
|
45
|
-
"eslint-plugin-jest": "^21.2.0",
|
46
|
-
"eslint-plugin-jsx-a11y": "^6.0.2",
|
47
|
-
"eslint-plugin-react": "^7.4.0",
|
48
|
-
"jest": "^24.9.0"
|
30
|
+
"eslint": "^6.8.0",
|
31
|
+
"prettier": "^1.19.1"
|
49
32
|
},
|
50
33
|
"peerDependencies": {
|
51
|
-
"@theforeman/vendor": ">= 4.
|
34
|
+
"@theforeman/vendor": ">= 4.2.1"
|
52
35
|
}
|
53
36
|
}
|
data/webpack/index.js
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
import URI from 'urijs';
|
2
1
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
3
|
-
import {
|
2
|
+
import { registerReducer } from 'foremanReact/common/MountingService';
|
4
3
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
5
4
|
import componentRegistry from 'foremanReact/components/componentRegistry';
|
6
5
|
import JobInvocationContainer from './react_app/components/jobInvocations';
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
2
3
|
|
3
4
|
const AggregateStatus = ({ statuses }) => (
|
4
5
|
<div id="aggregate_statuses">
|
@@ -31,4 +32,13 @@ const AggregateStatus = ({ statuses }) => (
|
|
31
32
|
</div>
|
32
33
|
);
|
33
34
|
|
35
|
+
AggregateStatus.propTypes = {
|
36
|
+
statuses: PropTypes.shape({
|
37
|
+
cancelled: PropTypes.number,
|
38
|
+
failed: PropTypes.number,
|
39
|
+
pending: PropTypes.number,
|
40
|
+
success: PropTypes.number,
|
41
|
+
}).isRequired,
|
42
|
+
};
|
43
|
+
|
34
44
|
export default AggregateStatus;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { shallow } from '
|
3
|
-
import AggregateStatus from './index
|
2
|
+
import { shallow } from '@theforeman/test';
|
3
|
+
import AggregateStatus from './index';
|
4
4
|
|
5
5
|
jest.unmock('./index.js');
|
6
6
|
|
@@ -20,7 +20,10 @@ describe('AggregateStatus', () => {
|
|
20
20
|
|
21
21
|
it('renders cards with props passed', () => {
|
22
22
|
const statuses = {
|
23
|
-
success: 19,
|
23
|
+
success: 19,
|
24
|
+
failed: 20,
|
25
|
+
cancelled: 31,
|
26
|
+
pending: 3,
|
24
27
|
};
|
25
28
|
const chartNumbers = shallow(<AggregateStatus statuses={statuses} />);
|
26
29
|
const success = chartNumbers.find('#success_count').text();
|
@@ -4,14 +4,18 @@ import Immutable from 'seamless-immutable';
|
|
4
4
|
import PropTypes from 'prop-types';
|
5
5
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
6
6
|
import DonutChart from 'foremanReact/components/common/charts/DonutChart';
|
7
|
-
import AggregateStatus from './AggregateStatus
|
7
|
+
import AggregateStatus from './AggregateStatus';
|
8
8
|
import * as JobInvocationActions from '../../redux/actions/jobInvocations';
|
9
9
|
|
10
|
-
const colIndexOfMaxValue = columns =>
|
10
|
+
const colIndexOfMaxValue = columns =>
|
11
|
+
columns.reduce((iMax, x, i, arr) => (x[1] > arr[iMax][1] ? i : iMax), 0);
|
11
12
|
|
12
13
|
class JobInvocationContainer extends React.Component {
|
13
14
|
componentDidMount() {
|
14
|
-
const {
|
15
|
+
const {
|
16
|
+
startJobInvocationsPolling,
|
17
|
+
data: { url },
|
18
|
+
} = this.props;
|
15
19
|
|
16
20
|
startJobInvocationsPolling(url);
|
17
21
|
}
|
@@ -22,15 +26,20 @@ class JobInvocationContainer extends React.Component {
|
|
22
26
|
|
23
27
|
return (
|
24
28
|
<div id="job_invocations_chart_container">
|
25
|
-
<DonutChart
|
26
|
-
|
29
|
+
<DonutChart
|
30
|
+
data={Immutable.asMutable(jobInvocations)}
|
31
|
+
title={{
|
32
|
+
type: 'percent',
|
33
|
+
secondary: (jobInvocations[iMax] || [])[0],
|
34
|
+
}}
|
35
|
+
/>
|
27
36
|
<AggregateStatus statuses={statuses} />
|
28
37
|
</div>
|
29
38
|
);
|
30
39
|
}
|
31
40
|
}
|
32
41
|
|
33
|
-
const mapStateToProps =
|
42
|
+
const mapStateToProps = state => {
|
34
43
|
const {
|
35
44
|
jobInvocations,
|
36
45
|
statuses,
|
@@ -62,4 +71,7 @@ JobInvocationContainer.defaultProps = {
|
|
62
71
|
jobInvocations: [['property', 3, 'color']],
|
63
72
|
statuses: {},
|
64
73
|
};
|
65
|
-
export default connect(
|
74
|
+
export default connect(
|
75
|
+
mapStateToProps,
|
76
|
+
JobInvocationActions
|
77
|
+
)(JobInvocationContainer);
|
@@ -8,10 +8,10 @@ import {
|
|
8
8
|
} from '../../consts';
|
9
9
|
|
10
10
|
const defaultJobInvocationsPollingInterval = 1000;
|
11
|
-
const jobInvocationsInterval =
|
12
|
-
defaultJobInvocationsPollingInterval;
|
11
|
+
const jobInvocationsInterval =
|
12
|
+
process.env.JOB_INVOCATIONS_POLLING || defaultJobInvocationsPollingInterval;
|
13
13
|
|
14
|
-
const getJobInvocations = url => (dispatch, getState) => {
|
14
|
+
const getJobInvocations = url => async (dispatch, getState) => {
|
15
15
|
function onGetJobInvocationsSuccess({ data }) {
|
16
16
|
// If the job has finished, stop polling
|
17
17
|
if (data.finished) {
|
@@ -41,7 +41,7 @@ const getJobInvocations = url => (dispatch, getState) => {
|
|
41
41
|
if (jobInvocationsInterval) {
|
42
42
|
setTimeout(
|
43
43
|
() => dispatch(getJobInvocations(url)),
|
44
|
-
jobInvocationsInterval
|
44
|
+
jobInvocationsInterval
|
45
45
|
);
|
46
46
|
}
|
47
47
|
}
|
@@ -52,10 +52,14 @@ const getJobInvocations = url => (dispatch, getState) => {
|
|
52
52
|
|
53
53
|
if (getState().foremanRemoteExecutionReducers.jobInvocations.isPolling) {
|
54
54
|
if (isDocumentVisible) {
|
55
|
-
|
56
|
-
.
|
57
|
-
|
58
|
-
|
55
|
+
try {
|
56
|
+
const data = await API.get(url);
|
57
|
+
onGetJobInvocationsSuccess(data);
|
58
|
+
} catch (error) {
|
59
|
+
onGetJobInvocationsFailed(error);
|
60
|
+
} finally {
|
61
|
+
triggerPolling();
|
62
|
+
}
|
59
63
|
} else {
|
60
64
|
// document is not visible, keep polling without api call
|
61
65
|
triggerPolling();
|
@@ -2,5 +2,4 @@ export const JOB_INVOCATIONS_POLLING_STARTED =
|
|
2
2
|
'JOB_INVOCATIONS_POLLING_STARTED';
|
3
3
|
export const JOB_INVOCATIONS_GET_JOB_INVOCATIONS =
|
4
4
|
'JOB_INVOCATIONS_GET_JOB_INVOCATIONS';
|
5
|
-
export const JOB_INVOCATIONS_JOB_FINISHED =
|
6
|
-
'JOB_INVOCATIONS_JOB_FINISHED';
|
5
|
+
export const JOB_INVOCATIONS_JOB_FINISHED = 'JOB_INVOCATIONS_JOB_FINISHED';
|
@@ -15,26 +15,10 @@ export const pollingStarted = Immutable({
|
|
15
15
|
export const jobInvocationsPayload = Immutable({
|
16
16
|
jobInvocations: {
|
17
17
|
job_invocations: [
|
18
|
-
[
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
],
|
23
|
-
[
|
24
|
-
'Failed',
|
25
|
-
20,
|
26
|
-
'#B7312D',
|
27
|
-
],
|
28
|
-
[
|
29
|
-
'Pending',
|
30
|
-
40,
|
31
|
-
'#B7312D',
|
32
|
-
],
|
33
|
-
[
|
34
|
-
'Cancelled',
|
35
|
-
0,
|
36
|
-
'#B7312D',
|
37
|
-
],
|
18
|
+
['Success', 100, '#B7312D'],
|
19
|
+
['Failed', 20, '#B7312D'],
|
20
|
+
['Pending', 40, '#B7312D'],
|
21
|
+
['Cancelled', 0, '#B7312D'],
|
38
22
|
],
|
39
23
|
statuses: {
|
40
24
|
cancelled: 0,
|
@@ -48,26 +32,10 @@ export const jobInvocationsPayload = Immutable({
|
|
48
32
|
export const jobInvocationsReceived = Immutable({
|
49
33
|
isPolling: true,
|
50
34
|
jobInvocations: [
|
51
|
-
[
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
],
|
56
|
-
[
|
57
|
-
'Failed',
|
58
|
-
20,
|
59
|
-
'#B7312D',
|
60
|
-
],
|
61
|
-
[
|
62
|
-
'Pending',
|
63
|
-
40,
|
64
|
-
'#B7312D',
|
65
|
-
],
|
66
|
-
[
|
67
|
-
'Cancelled',
|
68
|
-
0,
|
69
|
-
'#B7312D',
|
70
|
-
],
|
35
|
+
['Success', 100, '#B7312D'],
|
36
|
+
['Failed', 20, '#B7312D'],
|
37
|
+
['Pending', 40, '#B7312D'],
|
38
|
+
['Cancelled', 0, '#B7312D'],
|
71
39
|
],
|
72
40
|
statuses: {
|
73
41
|
cancelled: 0,
|
@@ -18,20 +18,26 @@ describe('job invocations chart reducer', () => {
|
|
18
18
|
expect(reducer(undefined, {})).toEqual(initialState);
|
19
19
|
});
|
20
20
|
it('should start polling given POLLING_STARTED', () => {
|
21
|
-
expect(
|
22
|
-
|
23
|
-
|
21
|
+
expect(
|
22
|
+
reducer(initialState, {
|
23
|
+
type: JOB_INVOCATIONS_POLLING_STARTED,
|
24
|
+
})
|
25
|
+
).toEqual(pollingStarted);
|
24
26
|
});
|
25
27
|
it('should stop polling given JOB_FINISHED', () => {
|
26
|
-
expect(
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
expect(
|
29
|
+
reducer(pollingStarted, {
|
30
|
+
type: JOB_INVOCATIONS_JOB_FINISHED,
|
31
|
+
payload: { jobInvocations: { job_invocations: [], statuses: {} } },
|
32
|
+
})
|
33
|
+
).toEqual(initialState);
|
30
34
|
});
|
31
35
|
it('should receive job invocations given GET_JOB_INVOCATIONS', () => {
|
32
|
-
expect(
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
expect(
|
37
|
+
reducer(pollingStarted, {
|
38
|
+
type: JOB_INVOCATIONS_GET_JOB_INVOCATIONS,
|
39
|
+
payload: jobInvocationsPayload,
|
40
|
+
})
|
41
|
+
).toEqual(jobInvocationsReceived);
|
36
42
|
});
|
37
43
|
});
|
data/webpack/test_setup.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import 'core-js/shim';
|
2
2
|
import 'regenerator-runtime/runtime';
|
3
3
|
|
4
|
-
import { configure } from '
|
4
|
+
import { configure } from '@theforeman/test';
|
5
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
5
6
|
import Adapter from 'enzyme-adapter-react-16';
|
6
7
|
|
7
8
|
configure({ adapter: new Adapter() });
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_remote_execution
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Foreman Remote Execution team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deface
|
@@ -205,6 +205,7 @@ files:
|
|
205
205
|
- app/models/template_invocation_input_value.rb
|
206
206
|
- app/overrides/execution_interface.rb
|
207
207
|
- app/overrides/subnet_proxies.rb
|
208
|
+
- app/services/default_proxy_proxy_selector.rb
|
208
209
|
- app/services/remote_execution_proxy_selector.rb
|
209
210
|
- app/services/ui_notifications/remote_execution_jobs/base_job_finish.rb
|
210
211
|
- app/views/api/v2/foreign_input_sets/base.json.rabl
|
@@ -426,7 +427,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
426
427
|
- !ruby/object:Gem::Version
|
427
428
|
version: '0'
|
428
429
|
requirements: []
|
429
|
-
rubygems_version: 3.0.
|
430
|
+
rubygems_version: 3.0.4
|
430
431
|
signing_key:
|
431
432
|
specification_version: 4
|
432
433
|
summary: A plugin bringing remote execution to the Foreman, completing the config
|