Skip to content

Commit 620d2d4

Browse files
author
OpenShift Bot
authored
Merge pull request #1798 from spadgett/yaml-linting
Merged by openshift-bot
2 parents 296c13c + 49aa652 commit 620d2d4

File tree

16 files changed

+490
-346
lines changed

16 files changed

+490
-346
lines changed

app/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ <h1>JavaScript Required</h1>
366366
<script src="scripts/directives/pauseRolloutsCheckbox.js"></script>
367367
<script src="scripts/directives/keyValueEditor.js"></script>
368368
<script src="scripts/directives/confirmOnExit.js"></script>
369+
<script src="scripts/directives/uiAceYaml.js"></script>
369370
<script src="scripts/filters/date.js"></script>
370371
<script src="scripts/filters/resources.js"></script>
371372
<script src="scripts/filters/canI.js"></script>

app/scripts/controllers/edit/yaml.js

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,11 @@ angular.module('openshiftConsole')
5151
$window.history.back();
5252
};
5353

54-
var onChange = _.throttle(function() {
55-
$scope.$eval(function() {
54+
$scope.$watch('resource', function(current, previous) {
55+
if (current !== previous) {
5656
$scope.modified = true;
57-
});
58-
}, 1000);
59-
60-
$scope.aceLoaded = function(editor) {
61-
var session = editor.getSession();
62-
session.setOption('tabSize', 2);
63-
session.setOption('useSoftTabs', true);
64-
65-
// Wait for the editor to initialize before adding the on change handler
66-
// so it's not immediately marked as modified.
67-
setTimeout(function() {
68-
session.on('change', onChange);
69-
});
70-
};
57+
}
58+
});
7159

7260
var watches = [];
7361
ProjectsService
@@ -86,9 +74,10 @@ angular.module('openshiftConsole')
8674

8775
DataService.get(resourceGroupVersion, $scope.name, context, { errorNotification: false }).then(
8876
function(result) {
77+
var original = result;
78+
8979
// Modify a copy of the resource.
90-
var resource = angular.copy(result);
91-
$scope.resource = resource;
80+
_.set($scope, 'updated.resource', angular.copy(result));
9281

9382
// TODO: Update the BreadcrumbsService to handle types without browse pages.
9483
// $scope.breadcrumbs = BreadcrumbsService.getBreadcrumbs({
@@ -101,47 +90,38 @@ angular.module('openshiftConsole')
10190
return _.get(resource, 'metadata.resourceVersion');
10291
};
10392

104-
_.set($scope, 'editor.model', jsyaml.safeDump(resource, {'sortKeys': true}));
105-
10693
$scope.save = function() {
94+
var updated = $scope.updated.resource;
10795
$scope.modified = false;
108-
var updatedResource;
109-
try {
110-
updatedResource = jsyaml.safeLoad($scope.editor.model);
111-
} catch (e) {
112-
$scope.error = e;
113-
return;
114-
}
115-
116-
if (updatedResource.kind !== resource.kind) {
96+
if (updated.kind !== original.kind) {
11797
$scope.error = {
118-
message: 'Cannot change resource kind (original: ' + resource.kind + ', modified: ' + (updatedResource.kind || '<unspecified>') + ').'
98+
message: 'Cannot change resource kind (original: ' + original.kind + ', modified: ' + (updated.kind || '<unspecified>') + ').'
11999
};
120100
return;
121101
}
122102

123-
var groupVersion = APIService.objectToResourceGroupVersion(resource);
124-
var updatedGroupVersion = APIService.objectToResourceGroupVersion(updatedResource);
103+
var groupVersion = APIService.objectToResourceGroupVersion(original);
104+
var updatedGroupVersion = APIService.objectToResourceGroupVersion(updated);
125105
if (!updatedGroupVersion) {
126-
$scope.error = { message: APIService.invalidObjectKindOrVersion(updatedResource) };
106+
$scope.error = { message: APIService.invalidObjectKindOrVersion(updated) };
127107
return;
128108
}
129109
if (updatedGroupVersion.group !== groupVersion.group) {
130110
$scope.error = { message: 'Cannot change resource group (original: ' + (groupVersion.group || '<none>') + ', modified: ' + (updatedGroupVersion.group || '<none>') + ').' };
131111
return;
132112
}
133113
if (!APIService.apiInfo(updatedGroupVersion)) {
134-
$scope.error = { message: APIService.unsupportedObjectKindOrVersion(updatedResource) };
114+
$scope.error = { message: APIService.unsupportedObjectKindOrVersion(updated) };
135115
return;
136116
}
137117

138118
$scope.updatingNow = true;
139-
DataService.update(updatedGroupVersion, $scope.resource.metadata.name, updatedResource, {
140-
namespace: $scope.resource.metadata.namespace
119+
DataService.update(groupVersion, original.metadata.name, original, {
120+
namespace: original.metadata.namespace
141121
}).then(
142122
// success
143123
function(response) {
144-
var editedResourceVersion = _.get(updatedResource, 'metadata.resourceVersion');
124+
var editedResourceVersion = _.get(updated, 'metadata.resourceVersion');
145125
var newResourceVersion = _.get(response, 'metadata.resourceVersion');
146126
if (newResourceVersion === editedResourceVersion) {
147127
$scope.alerts['no-changes-applied'] = {
@@ -174,7 +154,7 @@ angular.module('openshiftConsole')
174154
// Watch for changes to warn the user. If the watch failes, ignore the error since it's only used for this warning.
175155
// Some resources don't support watch.
176156
watches.push(DataService.watchObject(resourceGroupVersion, $scope.name, context, function(newValue, action) {
177-
$scope.resourceChanged = getVersion(newValue) !== getVersion(resource);
157+
$scope.resourceChanged = getVersion(newValue) !== getVersion(original);
178158
$scope.resourceDeleted = action === "DELETED";
179159
}, {
180160
errorNotification: false

app/scripts/directives/fromFile.js

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,6 @@ angular.module("openshiftConsole")
3434
editor.$blockScrolling = Infinity;
3535
};
3636

37-
var checkErrorAnnotations = function() {
38-
var editorAnnotations = aceEditorSession.getAnnotations();
39-
$scope.editorErrorAnnotation = _.some(editorAnnotations, { type: 'error' });
40-
};
41-
42-
// Determine whats the input format (JSON/YAML) and set appropriate view mode
43-
var updateEditorMode = _.debounce(function(){
44-
try {
45-
JSON.parse($scope.editorContent);
46-
aceEditorSession.setMode("ace/mode/json");
47-
} catch (e) {
48-
try {
49-
jsyaml.safeLoad($scope.editorContent);
50-
aceEditorSession.setMode("ace/mode/yaml");
51-
} catch (e) {}
52-
}
53-
$scope.$apply(checkErrorAnnotations);
54-
}, 300);
55-
56-
// Check if the editor isn't empty to disable the 'Add' button. Also check in what format the input is in (JSON/YAML) and change
57-
// the editor accordingly.
58-
$scope.aceChanged = updateEditorMode;
59-
6037
var launchConfirmationDialog = function(alerts) {
6138
var modalInstance = $uibModal.open({
6239
animation: true,
@@ -113,8 +90,6 @@ angular.module("openshiftConsole")
11390
}
11491
};
11592

116-
var resource;
117-
11893
$scope.create = function() {
11994
delete $scope.error;
12095

@@ -124,33 +99,23 @@ angular.module("openshiftConsole")
12499
// is JSON related the printed reason will be "Reason: Unable to parse", in case of YAML related
125100
// reason the true reason will be printed, since YAML parser throws an error object with needed
126101
// data.
127-
try {
128-
resource = JSON.parse($scope.editorContent);
129-
} catch (e) {
130-
try {
131-
resource = jsyaml.safeLoad($scope.editorContent);
132-
} catch (e) {
133-
$scope.error = e;
134-
return;
135-
}
136-
}
137102

138-
if (!isKindValid(resource)) {
103+
if (!isKindValid($scope.resource)) {
139104
return;
140105
}
141106

142-
$scope.resourceKind = resource.kind;
107+
$scope.resourceKind = $scope.resource.kind;
143108
$scope.resourceKind.endsWith("List") ? $scope.isList = true : $scope.isList = false;
144109

145-
if (!isMetadataValid(resource)) {
110+
if (!isMetadataValid($scope.resource)) {
146111
return;
147112
}
148113
if ($scope.isList) {
149-
$scope.resourceList = resource.items;
114+
$scope.resourceList = $scope.resource.items;
150115
$scope.resourceName = '';
151116
} else {
152-
$scope.resourceList = [resource];
153-
$scope.resourceName = resource.metadata.name;
117+
$scope.resourceList = [$scope.resource];
118+
$scope.resourceName = $scope.resource.metadata.name;
154119
if ($scope.resourceKind === "Template") {
155120
$scope.templateOptions = {
156121
process: true,
@@ -293,12 +258,12 @@ angular.module("openshiftConsole")
293258
if ($scope.isDialog) {
294259
$scope.$emit('fileImportedFromYAMLOrJSON', {
295260
project: $scope.project,
296-
template: resource
261+
template: $scope.resource
297262
});
298263
}
299264
else {
300265
namespace = ($scope.templateOptions.add || $scope.updateResources.length > 0) ? $scope.project.metadata.name : "";
301-
path = Navigate.createFromTemplateURL(resource, $scope.project.metadata.name, {namespace: namespace});
266+
path = Navigate.createFromTemplateURL($scope.resource, $scope.project.metadata.name, {namespace: namespace});
302267
$location.url(path);
303268
}
304269
}

app/scripts/directives/oscFileInput.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ angular.module('openshiftConsole')
99
required: "=",
1010
disabled: "=ngDisabled",
1111
showTextArea: '=',
12+
// Hide the clear value link.
13+
hideClear: '=?',
1214
helpText: "@?",
1315
dropZoneId: "@?"
1416
},

app/scripts/directives/uiAceYaml.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
'use strict';
2+
3+
(function() {
4+
angular.module('openshiftConsole').component('uiAceYaml', {
5+
controller: [
6+
'$scope',
7+
UIAceYAML
8+
],
9+
controllerAs: '$ctrl',
10+
bindings: {
11+
resource: '=',
12+
ngRequired: '<?',
13+
showFileInput: '<?'
14+
},
15+
templateUrl: 'views/directives/ui-ace-yaml.html'
16+
});
17+
18+
function UIAceYAML($scope) {
19+
var ctrl = this;
20+
var aceEditor;
21+
22+
var parseYAML = function(strict) {
23+
// https://github.com/nodeca/js-yaml#safeload-string---options-
24+
return jsyaml.safeLoad(ctrl.model, {
25+
// If `strict` is false, allow duplicate keys in the YAML for
26+
// compability with `oc create` using the js-yaml `json` option. This
27+
// also lets us parse JSON as YAML, where duplicate keys are allowed.
28+
json: !strict
29+
});
30+
};
31+
32+
var clearAnnotations = function() {
33+
aceEditor.getSession().clearAnnotations();
34+
$scope.$evalAsync(function() {
35+
ctrl.annotations = {};
36+
});
37+
};
38+
39+
var setAnnotation = function(e, severity) {
40+
var session = aceEditor.getSession();
41+
var length = session.getLength();
42+
var row = _.get(e, 'mark.line', 0);
43+
var col = _.get(e, 'mark.column', 0);
44+
var message = e.message || 'Could not parse content.';
45+
46+
// If the error line is reported as being after the last line, use the
47+
// last line. This can happen when the error is at the very end of the
48+
// document and the user doesn't have a final newline.
49+
if (row >= length) {
50+
row = length - 1;
51+
}
52+
53+
var annotation = {
54+
row: row,
55+
column: col,
56+
text: message,
57+
type: severity
58+
};
59+
session.setAnnotations([ annotation ]);
60+
61+
$scope.$evalAsync(function() {
62+
ctrl.annotations = {};
63+
ctrl.annotations[severity] = [ annotation ];
64+
});
65+
};
66+
67+
var setValid = function(valid) {
68+
$scope.$evalAsync(function() {
69+
ctrl.form.$setValidity('yamlValid', valid);
70+
});
71+
};
72+
73+
var updated = function() {
74+
// Check for errors, then check for warnings.
75+
try {
76+
ctrl.resource = parseYAML(false);
77+
setValid(true);
78+
// Check for warnings.
79+
try {
80+
parseYAML(true);
81+
clearAnnotations();
82+
} catch (e) {
83+
setAnnotation(e, 'warning');
84+
}
85+
} catch (e) {
86+
setAnnotation(e, 'error');
87+
setValid(false);
88+
}
89+
};
90+
91+
$scope.$watch(function() {
92+
return ctrl.fileUpload;
93+
}, function(content, previous) {
94+
if (content === previous) {
95+
return;
96+
}
97+
98+
ctrl.model = content;
99+
});
100+
101+
ctrl.$onInit = function() {
102+
if (ctrl.resource) {
103+
ctrl.model = jsyaml.safeDump(ctrl.resource, {
104+
sortKeys: true
105+
});
106+
}
107+
};
108+
109+
ctrl.aceChanged = updated;
110+
ctrl.aceLoaded = function(editor) {
111+
// Keep a reference to use later in event callbacks.
112+
aceEditor = editor;
113+
114+
var session = editor.getSession();
115+
session.setOption('tabSize', 2);
116+
session.setOption('useSoftTabs', true);
117+
editor.setDragDelay = 0;
118+
};
119+
120+
ctrl.gotoLine = function(line) {
121+
aceEditor.gotoLine(line);
122+
};
123+
}
124+
})();

0 commit comments

Comments
 (0)