Browse code

Add framework for the v3 web management console

Jessica Forrester authored on 2014/09/20 05:56:43
Showing 42 changed files
... ...
@@ -5,17 +5,35 @@ go:
5 5
   - 1.2
6 6
   - tip
7 7
 
8
+env:
9
+ - TEST_ASSETS=true
10
+ - TEST_ASSETS=false
11
+
12
+matrix:
13
+  exclude:
14
+    - go: 1.3
15
+      env: TEST_ASSETS=false
16
+    - go: 1.2
17
+      env: TEST_ASSETS=true
18
+    - go: tip
19
+      env: TEST_ASSETS=true      
20
+
21
+before_install:
22
+  - ./hack/before-install-assets.sh
23
+
8 24
 install:
9 25
   - ./hack/verify-gofmt.sh
10 26
   - ./hack/install-etcd.sh
11 27
   - ./hack/install-std-race.sh
12 28
   - go get code.google.com/p/go.tools/cmd/cover
13 29
   - ./hack/build-go.sh
30
+  - ./hack/install-assets.sh
14 31
 
15 32
 script:
16 33
   - ./hack/test-go.sh
17 34
   - ./hack/test-cmd.sh
18 35
   - PATH=$HOME/gopath/bin:./third_party/etcd/bin:$PATH ./hack/test-integration.sh
36
+  - ./hack/test-assets.sh
19 37
 
20 38
 notifications:
21 39
   irc: "chat.freenode.net#openshift-dev"
22 40
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+{
1
+  "directory": "bower_components"
2
+}
0 3
new file mode 100644
... ...
@@ -0,0 +1,21 @@
0
+# EditorConfig helps developers define and maintain consistent
1
+# coding styles between different editors and IDEs
2
+# editorconfig.org
3
+
4
+root = true
5
+
6
+
7
+[*]
8
+
9
+# Change these settings to your own preference
10
+indent_style = space
11
+indent_size = 2
12
+
13
+# We recommend you to keep these unchanged
14
+end_of_line = lf
15
+charset = utf-8
16
+trim_trailing_whitespace = true
17
+insert_final_newline = true
18
+
19
+[*.md]
20
+trim_trailing_whitespace = false
0 21
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+* text=auto
0 1
\ No newline at end of file
1 2
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+node_modules
1
+dist
2
+.tmp
3
+.sass-cache
4
+bower_components
0 5
new file mode 100644
... ...
@@ -0,0 +1,23 @@
0
+{
1
+  "node": true,
2
+  "browser": true,
3
+  "esnext": true,
4
+  "bitwise": true,
5
+  "camelcase": true,
6
+  "curly": true,
7
+  "eqeqeq": true,
8
+  "immed": true,
9
+  "indent": 2,
10
+  "latedef": true,
11
+  "newcap": true,
12
+  "noarg": true,
13
+  "regexp": true,
14
+  "undef": true,
15
+  "unused": true,
16
+  "strict": true,
17
+  "trailing": true,
18
+  "smarttabs": true,
19
+  "globals": {
20
+    "angular": false
21
+  }
22
+}
0 23
new file mode 100644
... ...
@@ -0,0 +1,463 @@
0
+// Generated on 2014-09-12 using generator-angular 0.9.8
1
+'use strict';
2
+
3
+// # Globbing
4
+// for performance reasons we're only matching one level down:
5
+// 'test/spec/{,*/}*.js'
6
+// use this if you want to recursively match all subfolders:
7
+// 'test/spec/**/*.js'
8
+
9
+module.exports = function (grunt) {
10
+
11
+  // Load grunt tasks automatically
12
+  require('load-grunt-tasks')(grunt, {
13
+    pattern: ['grunt-*', '!grunt-template-jasmine-istanbul']
14
+  });
15
+
16
+  // Time how long tasks take. Can help when optimizing build times
17
+  require('time-grunt')(grunt);
18
+
19
+  // Configurable paths for the application
20
+  var appConfig = {
21
+    app: require('./bower.json').appPath || 'app',
22
+    dist: 'dist'
23
+  };
24
+
25
+  // Define the configuration for all the tasks
26
+  grunt.initConfig({
27
+
28
+    // Project settings
29
+    yeoman: appConfig,
30
+
31
+    // Watches files for changes and runs tasks based on the changed files
32
+    watch: {
33
+      bower: {
34
+        files: ['bower.json'],
35
+        tasks: ['wiredep']
36
+      },
37
+      js: {
38
+        files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
39
+        tasks: ['newer:jshint:all'],
40
+        options: {
41
+          livereload: '<%= connect.options.livereload %>'
42
+        }
43
+      },
44
+      jsTest: {
45
+        files: ['test/spec/{,*/}*.js'],
46
+        tasks: ['newer:jshint:test', 'karma']
47
+      },
48
+      compass: {
49
+        files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
50
+        tasks: ['compass:server', 'autoprefixer']
51
+      },
52
+      gruntfile: {
53
+        files: ['Gruntfile.js']
54
+      },
55
+      livereload: {
56
+        options: {
57
+          livereload: '<%= connect.options.livereload %>'
58
+        },
59
+        files: [
60
+          '<%= yeoman.app %>/{,*/}*.html',
61
+          '.tmp/styles/{,*/}*.css',
62
+          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
63
+        ]
64
+      }
65
+    },
66
+
67
+    // The actual grunt server settings
68
+    connect: {
69
+      options: {
70
+        port: 9000,
71
+        // Change this to '0.0.0.0' to access the server from outside.
72
+        hostname: 'localhost',
73
+        livereload: 35729
74
+      },
75
+      livereload: {
76
+        options: {
77
+          open: true,
78
+          middleware: function (connect) {
79
+            return [
80
+              connect.static('.tmp'),
81
+              connect().use(
82
+                '/bower_components',
83
+                connect.static('./bower_components')
84
+              ),
85
+              connect.static(appConfig.app)
86
+            ];
87
+          }
88
+        }
89
+      },
90
+      test: {
91
+        options: {
92
+          port: 9001,
93
+          middleware: function (connect) {
94
+            return [
95
+              connect.static('.tmp'),
96
+              connect.static('test'),
97
+              connect().use(
98
+                '/bower_components',
99
+                connect.static('./bower_components')
100
+              ),
101
+              connect.static(appConfig.app)
102
+            ];
103
+          }
104
+        }
105
+      },
106
+      dist: {
107
+        options: {
108
+          open: true,
109
+          base: '<%= yeoman.dist %>'
110
+        }
111
+      }
112
+    },
113
+
114
+    // Make sure code styles are up to par and there are no obvious mistakes
115
+    jshint: {
116
+      options: {
117
+        jshintrc: '.jshintrc',
118
+        reporter: require('jshint-stylish')
119
+      },
120
+      all: {
121
+        src: [
122
+          'Gruntfile.js',
123
+          '<%= yeoman.app %>/scripts/{,*/}*.js'
124
+        ]
125
+      },
126
+      test: {
127
+        options: {
128
+          jshintrc: 'test/.jshintrc'
129
+        },
130
+        src: ['test/spec/{,*/}*.js']
131
+      }
132
+    },
133
+
134
+    // Empties folders to start fresh
135
+    clean: {
136
+      dist: {
137
+        files: [{
138
+          dot: true,
139
+          src: [
140
+            '.tmp',
141
+            '<%= yeoman.dist %>/{,*/}*',
142
+            '!<%= yeoman.dist %>/.git*'
143
+          ]
144
+        }]
145
+      },
146
+      server: '.tmp'
147
+    },
148
+
149
+    // Add vendor prefixed styles
150
+    autoprefixer: {
151
+      options: {
152
+        browsers: ['last 1 version']
153
+      },
154
+      dist: {
155
+        files: [{
156
+          expand: true,
157
+          cwd: '.tmp/styles/',
158
+          src: '{,*/}*.css',
159
+          dest: '.tmp/styles/'
160
+        }]
161
+      }
162
+    },
163
+
164
+    // Automatically inject Bower components into the app
165
+    wiredep: {
166
+      app: {
167
+        src: ['<%= yeoman.app %>/index.html'],
168
+        ignorePath:  /\.\.\//
169
+      },
170
+      sass: {
171
+        src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
172
+        ignorePath: /(\.\.\/){1,2}bower_components\//
173
+      }
174
+    },
175
+
176
+    // Compiles Sass to CSS and generates necessary files if requested
177
+    compass: {
178
+      options: {
179
+        sassDir: '<%= yeoman.app %>/styles',
180
+        cssDir: '.tmp/styles',
181
+        generatedImagesDir: '.tmp/images/generated',
182
+        imagesDir: '<%= yeoman.app %>/images',
183
+        javascriptsDir: '<%= yeoman.app %>/scripts',
184
+        fontsDir: '<%= yeoman.app %>/styles/fonts',
185
+        importPath: './bower_components',
186
+        httpImagesPath: '/images',
187
+        httpGeneratedImagesPath: '/images/generated',
188
+        httpFontsPath: '/styles/fonts',
189
+        relativeAssets: false,
190
+        assetCacheBuster: false,
191
+        raw: 'Sass::Script::Number.precision = 10\n'
192
+      },
193
+      dist: {
194
+        options: {
195
+          generatedImagesDir: '<%= yeoman.dist %>/images/generated'
196
+        }
197
+      },
198
+      server: {
199
+        options: {
200
+          debugInfo: true
201
+        }
202
+      }
203
+    },
204
+
205
+    // Renames files for browser caching purposes
206
+    filerev: {
207
+      dist: {
208
+        src: [
209
+          '<%= yeoman.dist %>/scripts/{,*/}*.js',
210
+          '<%= yeoman.dist %>/styles/{,*/}*.css',
211
+          '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
212
+          '<%= yeoman.dist %>/styles/fonts/*'
213
+        ]
214
+      }
215
+    },
216
+
217
+    // Reads HTML for usemin blocks to enable smart builds that automatically
218
+    // concat, minify and revision files. Creates configurations in memory so
219
+    // additional tasks can operate on them
220
+    useminPrepare: {
221
+      html: '<%= yeoman.app %>/index.html',
222
+      options: {
223
+        dest: '<%= yeoman.dist %>',
224
+        flow: {
225
+          html: {
226
+            steps: {
227
+              js: ['concat', 'uglifyjs'],
228
+              css: ['cssmin']
229
+            },
230
+            post: {}
231
+          }
232
+        }
233
+      }
234
+    },
235
+
236
+    // Performs rewrites based on filerev and the useminPrepare configuration
237
+    usemin: {
238
+      html: ['<%= yeoman.dist %>/{,*/}*.html'],
239
+      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
240
+      options: {
241
+        assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images']
242
+      }
243
+    },
244
+
245
+    // The following *-min tasks will produce minified files in the dist folder
246
+    // By default, your `index.html`'s <!-- Usemin block --> will take care of
247
+    // minification. These next options are pre-configured if you do not wish
248
+    // to use the Usemin blocks.
249
+    // cssmin: {
250
+    //   dist: {
251
+    //     files: {
252
+    //       '<%= yeoman.dist %>/styles/main.css': [
253
+    //         '.tmp/styles/{,*/}*.css'
254
+    //       ]
255
+    //     }
256
+    //   }
257
+    // },
258
+    // uglify: {
259
+    //   dist: {
260
+    //     files: {
261
+    //       '<%= yeoman.dist %>/scripts/scripts.js': [
262
+    //         '<%= yeoman.dist %>/scripts/scripts.js'
263
+    //       ]
264
+    //     }
265
+    //   }
266
+    // },
267
+    // concat: {
268
+    //   dist: {}
269
+    // },
270
+
271
+    imagemin: {
272
+      dist: {
273
+        files: [{
274
+          expand: true,
275
+          cwd: '<%= yeoman.app %>/images',
276
+          src: '{,*/}*.{png,jpg,jpeg,gif}',
277
+          dest: '<%= yeoman.dist %>/images'
278
+        }]
279
+      }
280
+    },
281
+
282
+    svgmin: {
283
+      dist: {
284
+        files: [{
285
+          expand: true,
286
+          cwd: '<%= yeoman.app %>/images',
287
+          src: '{,*/}*.svg',
288
+          dest: '<%= yeoman.dist %>/images'
289
+        }]
290
+      }
291
+    },
292
+
293
+    htmlmin: {
294
+      dist: {
295
+        options: {
296
+          collapseWhitespace: true,
297
+          conservativeCollapse: true,
298
+          collapseBooleanAttributes: true,
299
+          removeCommentsFromCDATA: true,
300
+          removeOptionalTags: true
301
+        },
302
+        files: [{
303
+          expand: true,
304
+          cwd: '<%= yeoman.dist %>',
305
+          src: ['*.html', 'views/{,*/}*.html'],
306
+          dest: '<%= yeoman.dist %>'
307
+        }]
308
+      }
309
+    },
310
+
311
+    // ng-annotate tries to make the code safe for minification automatically
312
+    // by using the Angular long form for dependency injection.
313
+    ngAnnotate: {
314
+      dist: {
315
+        files: [{
316
+          expand: true,
317
+          cwd: '.tmp/concat/scripts',
318
+          src: ['*.js', '!oldieshim.js'],
319
+          dest: '.tmp/concat/scripts'
320
+        }]
321
+      }
322
+    },
323
+
324
+    // Replace Google CDN references
325
+    cdnify: {
326
+      dist: {
327
+        html: ['<%= yeoman.dist %>/*.html']
328
+      }
329
+    },
330
+
331
+    // Copies remaining files to places other tasks can use
332
+    copy: {
333
+      dist: {
334
+        files: [{
335
+          expand: true,
336
+          dot: true,
337
+          cwd: '<%= yeoman.app %>',
338
+          dest: '<%= yeoman.dist %>',
339
+          src: [
340
+            '*.{ico,png,txt}',
341
+            '.htaccess',
342
+            '*.html',
343
+            'views/{,*/}*.html',
344
+            'images/{,*/}*.{webp}',
345
+            'fonts/*'
346
+          ]
347
+        }, {
348
+          expand: true,
349
+          cwd: '.tmp/images',
350
+          dest: '<%= yeoman.dist %>/images',
351
+          src: ['generated/*']
352
+        }, {
353
+          expand: true,
354
+          cwd: '.',
355
+          src: 'bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*',
356
+          dest: '<%= yeoman.dist %>'
357
+        }]
358
+      },
359
+      styles: {
360
+        expand: true,
361
+        cwd: '<%= yeoman.app %>/styles',
362
+        dest: '.tmp/styles/',
363
+        src: '{,*/}*.css'
364
+      }
365
+    },
366
+
367
+    // Run some tasks in parallel to speed up the build process
368
+    concurrent: {
369
+      server: [
370
+        'compass:server'
371
+      ],
372
+      test: [
373
+        'compass'
374
+      ],
375
+      dist: [
376
+        'compass:dist',
377
+        'imagemin',
378
+        'svgmin'
379
+      ]
380
+    },
381
+
382
+    // Test settings
383
+    karma: {
384
+      unit: {
385
+        configFile: 'test/karma.conf.js',
386
+        singleRun: true
387
+      }
388
+    },
389
+
390
+    // Settings for grunt-istanbul-coverage
391
+    // NOTE: coverage task is currently not in use
392
+    coverage: {
393
+      options: {
394
+        thresholds: {
395
+          'statements': 90,
396
+          'branches': 90,
397
+          'lines': 90,
398
+          'functions': 90
399
+        },
400
+        dir: 'coverage',
401
+        root: 'test'
402
+      }
403
+    }    
404
+  });
405
+
406
+
407
+  grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
408
+    if (target === 'dist') {
409
+      return grunt.task.run(['build', 'connect:dist:keepalive']);
410
+    }
411
+
412
+    grunt.task.run([
413
+      'clean:server',
414
+      'wiredep',
415
+      'concurrent:server',
416
+      'autoprefixer',
417
+      'connect:livereload',
418
+      'watch'
419
+    ]);
420
+  });
421
+
422
+  grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
423
+    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
424
+    grunt.task.run(['serve:' + target]);
425
+  });
426
+
427
+  // Loads the coverage task which enforces the minimum coverage thresholds
428
+  grunt.loadNpmTasks('grunt-istanbul-coverage');
429
+
430
+  // karma must run prior to coverage since karma will generate the coverage results
431
+  grunt.registerTask('test', [
432
+    'clean:server',
433
+    'concurrent:test',
434
+    'autoprefixer',
435
+    'connect:test',
436
+    'karma'
437
+    // 'coverage' - add back if we want to enforce coverage percentages
438
+  ]);
439
+
440
+  grunt.registerTask('build', [
441
+    'clean:dist',
442
+    'wiredep',
443
+    'useminPrepare',
444
+    'concurrent:dist',
445
+    'autoprefixer',
446
+    'concat',
447
+    'ngAnnotate',
448
+    'copy:dist',
449
+    'cdnify',
450
+    'cssmin',
451
+    'uglify',
452
+    'filerev',
453
+    'usemin',
454
+    'htmlmin'
455
+  ]);
456
+
457
+  grunt.registerTask('default', [
458
+    'newer:jshint',
459
+    'test',
460
+    'build'
461
+  ]);
462
+};
0 463
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+OpenShift 3 Static Assets
1
+=========================
2
+The static assets for OpenShift v3.  This includes the web management console.
3
+
4
+Contributing
5
+------------
6
+
7
+#### Getting started
8
+1. Install [Nodejs](http://nodejs.org/) and [npm](https://www.npmjs.org/)
9
+2. Install [grunt-cli](http://gruntjs.com/installing-grunt) and [bower](http://bower.io/) by running `npm install -g grunt-cli bower` (may need to be run with sudo)
10
+3. From the `assets` directory, run the following commands:
11
+    
12
+    `npm install` (Install the project's dev dependencies)
13
+    
14
+    `bower install` (Install the project's UI dependencies)
15
+    
16
+    `grunt serve` (Launch the console and start watching for asset changes)
17
+
18
+    Note: If you see an ENOSPC error running `grunt serve`, you may need to increase the number of files your user can watch by running this command:
19
+    
20
+    ```
21
+    echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
22
+    ```
23
+
24
+#### Before opening a pull request
25
+1. Run the test suite with `grunt test`
26
+2. Rebase and squash changes to a single commit
27
+
28
+#### Production builds
29
+1. From the `assets` directory, run `grunt build`
30
+2. From the root of the origin repo, run:
31
+
32
+    ```
33
+    go get github.com/jteeuwen/go-bindata/...
34
+
35
+    go-bindata -prefix "assets/dist" -pkg "assets" -o "pkg/assets/bindata.go" -tags "release" assets/dist/...
36
+
37
+    OS_BUILD_TAGS=release hack/build-go.sh
38
+    ```
39
+
40
+Now when starting the openshift all-in-one server it will also serve the console assets. The default listens at [http://localhost:8091](http://localhost:8091)
0 41
\ No newline at end of file
1 42
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+*.coffee
0 1
\ No newline at end of file
1 2
new file mode 100644
... ...
@@ -0,0 +1,157 @@
0
+<!DOCTYPE html>
1
+<html lang="en">
2
+  <head>
3
+    <meta charset="utf-8">
4
+    <title>Page Not Found :(</title>
5
+    <style>
6
+      ::-moz-selection {
7
+        background: #b3d4fc;
8
+        text-shadow: none;
9
+      }
10
+
11
+      ::selection {
12
+        background: #b3d4fc;
13
+        text-shadow: none;
14
+      }
15
+
16
+      html {
17
+        padding: 30px 10px;
18
+        font-size: 20px;
19
+        line-height: 1.4;
20
+        color: #737373;
21
+        background: #f0f0f0;
22
+        -webkit-text-size-adjust: 100%;
23
+        -ms-text-size-adjust: 100%;
24
+      }
25
+
26
+      html,
27
+      input {
28
+        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
29
+      }
30
+
31
+      body {
32
+        max-width: 500px;
33
+        _width: 500px;
34
+        padding: 30px 20px 50px;
35
+        border: 1px solid #b3b3b3;
36
+        border-radius: 4px;
37
+        margin: 0 auto;
38
+        box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;
39
+        background: #fcfcfc;
40
+      }
41
+
42
+      h1 {
43
+        margin: 0 10px;
44
+        font-size: 50px;
45
+        text-align: center;
46
+      }
47
+
48
+      h1 span {
49
+        color: #bbb;
50
+      }
51
+
52
+      h3 {
53
+        margin: 1.5em 0 0.5em;
54
+      }
55
+
56
+      p {
57
+        margin: 1em 0;
58
+      }
59
+
60
+      ul {
61
+        padding: 0 0 0 40px;
62
+        margin: 1em 0;
63
+      }
64
+
65
+      .container {
66
+        max-width: 380px;
67
+        _width: 380px;
68
+        margin: 0 auto;
69
+      }
70
+
71
+      /* google search */
72
+
73
+      #goog-fixurl ul {
74
+        list-style: none;
75
+        padding: 0;
76
+        margin: 0;
77
+      }
78
+
79
+      #goog-fixurl form {
80
+        margin: 0;
81
+      }
82
+
83
+      #goog-wm-qt,
84
+      #goog-wm-sb {
85
+        border: 1px solid #bbb;
86
+        font-size: 16px;
87
+        line-height: normal;
88
+        vertical-align: top;
89
+        color: #444;
90
+        border-radius: 2px;
91
+      }
92
+
93
+      #goog-wm-qt {
94
+        width: 220px;
95
+        height: 20px;
96
+        padding: 5px;
97
+        margin: 5px 10px 0 0;
98
+        box-shadow: inset 0 1px 1px #ccc;
99
+      }
100
+
101
+      #goog-wm-sb {
102
+        display: inline-block;
103
+        height: 32px;
104
+        padding: 0 10px;
105
+        margin: 5px 0 0;
106
+        white-space: nowrap;
107
+        cursor: pointer;
108
+        background-color: #f5f5f5;
109
+        background-image: -webkit-linear-gradient(rgba(255,255,255,0), #f1f1f1);
110
+        background-image: -moz-linear-gradient(rgba(255,255,255,0), #f1f1f1);
111
+        background-image: -ms-linear-gradient(rgba(255,255,255,0), #f1f1f1);
112
+        background-image: -o-linear-gradient(rgba(255,255,255,0), #f1f1f1);
113
+        -webkit-appearance: none;
114
+        -moz-appearance: none;
115
+        appearance: none;
116
+        *overflow: visible;
117
+        *display: inline;
118
+        *zoom: 1;
119
+      }
120
+
121
+      #goog-wm-sb:hover,
122
+      #goog-wm-sb:focus {
123
+        border-color: #aaa;
124
+        box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
125
+        background-color: #f8f8f8;
126
+      }
127
+
128
+      #goog-wm-qt:hover,
129
+      #goog-wm-qt:focus {
130
+        border-color: #105cb6;
131
+        outline: 0;
132
+        color: #222;
133
+      }
134
+
135
+      input::-moz-focus-inner {
136
+        padding: 0;
137
+        border: 0;
138
+      }
139
+    </style>
140
+  </head>
141
+  <body>
142
+    <div class="container">
143
+      <h1>Not found <span>:(</span></h1>
144
+      <p>Sorry, but the page you were trying to view does not exist.</p>
145
+      <p>It looks like this was the result of either:</p>
146
+      <ul>
147
+        <li>a mistyped address</li>
148
+        <li>an out-of-date link</li>
149
+      </ul>
150
+      <script>
151
+        var GOOG_FIXURL_LANG = (navigator.language || '').slice(0,2),GOOG_FIXURL_SITE = location.host;
152
+      </script>
153
+      <script src="//linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js"></script>
154
+    </div>
155
+  </body>
156
+</html>
0 157
new file mode 100644
1 158
Binary files /dev/null and b/assets/app/favicon.ico differ
2 159
new file mode 100644
3 160
Binary files /dev/null and b/assets/app/images/openshift-logo222.png differ
4 161
new file mode 100644
5 162
Binary files /dev/null and b/assets/app/images/redhat.png differ
6 163
new file mode 100644
... ...
@@ -0,0 +1,77 @@
0
+<!doctype html>
1
+<html class="no-js">
2
+  <head>
3
+    <meta charset="utf-8">
4
+    <title>OpenShift Management Console</title>
5
+    <meta name="description" content="">
6
+    <meta name="viewport" content="width=device-width">
7
+    <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
8
+    <!-- build:css(.) styles/vendor.css -->
9
+    <!-- bower:css -->
10
+    <!-- endbower -->
11
+    <!-- endbuild -->
12
+    <!-- build:css(.tmp) styles/main.css -->
13
+    <link rel="stylesheet" href="styles/main.css">
14
+    <!-- endbuild -->
15
+  </head>
16
+  <body ng-app="openshiftConsole">
17
+    <!-- Add your site or application content here -->
18
+    <div class="container">
19
+      <div class="header">
20
+        <ul class="nav nav-pills pull-right">
21
+          <li class="active"><a ng-href="#">Home</a></li>
22
+          <li><a ng-href="#/about">About</a></li>
23
+        </ul>
24
+        <h3><img src="images/openshift-logo222.png"></h3>
25
+      </div>
26
+
27
+      <div ng-view=""></div>
28
+
29
+      <div class="footer">
30
+        <p><img src="images/redhat.png"></p>
31
+      </div>
32
+    </div>
33
+
34
+    <!-- build:js(.) scripts/oldieshim.js -->
35
+    <!--[if lt IE 9]>
36
+    <script src="bower_components/es5-shim/es5-shim.js"></script>
37
+    <script src="bower_components/json3/lib/json3.js"></script>
38
+    <![endif]-->
39
+    <!-- endbuild -->
40
+
41
+    <!-- build:js(.) scripts/vendor.js -->
42
+    <!-- bower:js -->
43
+    <script src="bower_components/jquery/dist/jquery.js"></script>
44
+    <script src="bower_components/angular/angular.js"></script>
45
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/affix.js"></script>
46
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/alert.js"></script>
47
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/button.js"></script>
48
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/carousel.js"></script>
49
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/collapse.js"></script>
50
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/dropdown.js"></script>
51
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/tab.js"></script>
52
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/transition.js"></script>
53
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/scrollspy.js"></script>
54
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/modal.js"></script>
55
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/tooltip.js"></script>
56
+    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/popover.js"></script>
57
+    <script src="bower_components/angular-resource/angular-resource.js"></script>
58
+    <script src="bower_components/angular-cookies/angular-cookies.js"></script>
59
+    <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
60
+    <script src="bower_components/angular-animate/angular-animate.js"></script>
61
+    <script src="bower_components/angular-touch/angular-touch.js"></script>
62
+    <script src="bower_components/angular-route/angular-route.js"></script>
63
+    <script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
64
+    <!-- endbower -->
65
+    <!-- endbuild -->
66
+
67
+        <!-- build:js({.tmp,app}) scripts/scripts.js -->
68
+        <script src="scripts/app.js"></script>
69
+        <script src="scripts/controllers/main.js"></script>
70
+        <script src="scripts/controllers/about.js"></script>
71
+        <script src="scripts/controllers/pods.js"></script>
72
+        <script src="scripts/controllers/minions.js"></script>
73
+        <script src="scripts/controllers/pod.js"></script>        
74
+        <!-- endbuild -->
75
+</body>
76
+</html>
0 77
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+# robotstxt.org
1
+
2
+User-agent: *
0 3
new file mode 100644
... ...
@@ -0,0 +1,45 @@
0
+'use strict';
1
+
2
+/**
3
+ * @ngdoc overview
4
+ * @name openshiftConsole
5
+ * @description
6
+ * # openshiftConsole
7
+ *
8
+ * Main module of the application.
9
+ */
10
+angular
11
+  .module('openshiftConsole', [
12
+    'ngAnimate',
13
+    'ngCookies',
14
+    'ngResource',
15
+    'ngRoute',
16
+    'ngSanitize',
17
+    'ngTouch'
18
+  ])
19
+  .config(function ($routeProvider) {
20
+    $routeProvider
21
+      .when('/', {
22
+        templateUrl: 'views/main.html',
23
+        controller: 'MainCtrl'
24
+      })
25
+      .when('/about', {
26
+        templateUrl: 'views/about.html',
27
+        controller: 'AboutCtrl'
28
+      })
29
+      .when('/pods', {
30
+        templateUrl: 'views/pods.html',
31
+        controller: 'PodsController'
32
+      })
33
+      .when('/pods/:pod', {
34
+        templateUrl: 'views/pod.html',
35
+        controller: 'PodController'
36
+      })
37
+      .when('/minions', {
38
+        templateUrl: 'views/minions.html',
39
+        controller: 'MinionsController'
40
+      })
41
+      .otherwise({
42
+        redirectTo: '/'
43
+      });
44
+  });
0 45
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+'use strict';
1
+
2
+/**
3
+ * @ngdoc function
4
+ * @name openshiftConsole.controller:AboutCtrl
5
+ * @description
6
+ * # AboutCtrl
7
+ * Controller of the openshiftConsole
8
+ */
9
+angular.module('openshiftConsole')
10
+  .controller('AboutCtrl', function ($scope) {
11
+    $scope.awesomeThings = [
12
+      'HTML5 Boilerplate',
13
+      'AngularJS',
14
+      'Karma'
15
+    ];
16
+  });
0 17
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+'use strict';
1
+
2
+/**
3
+ * @ngdoc function
4
+ * @name openshiftConsole.controller:MainCtrl
5
+ * @description
6
+ * # MainCtrl
7
+ * Controller of the openshiftConsole
8
+ */
9
+angular.module('openshiftConsole')
10
+  .controller('MainCtrl', function ($scope) {
11
+    $scope.awesomeThings = [
12
+      'HTML5 Boilerplate',
13
+      'AngularJS',
14
+      'Karma'
15
+    ];
16
+  });
0 17
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+'use strict';
1
+
2
+/**
3
+ * @ngdoc function
4
+ * @name openshiftConsole.controller:AboutCtrl
5
+ * @description
6
+ * # AboutCtrl
7
+ * Controller of the openshiftConsole
8
+ */
9
+angular.module('openshiftConsole')
10
+  .controller('MinionsController', function ($scope, $http) {
11
+    $scope.minions = [];
12
+    $http.defaults.useXDomain = true;
13
+    $http.get('http://localhost:8080/api/v1beta1/minions').success(function(data) {
14
+      $scope.minions = data.minions;
15
+    });
16
+  });
0 17
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+'use strict';
1
+
2
+/**
3
+ * @ngdoc function
4
+ * @name openshiftConsole.controller:AboutCtrl
5
+ * @description
6
+ * # AboutCtrl
7
+ * Controller of the openshiftConsole
8
+ */
9
+angular.module('openshiftConsole')
10
+  .controller('PodController', function ($scope, $http, $routeParams) {
11
+    $scope.pod = {desiredState: {containers: []}};
12
+    $http.defaults.useXDomain = true;
13
+    $http.get('http://localhost:8080/api/v1beta1/pods/' + $routeParams.pod).success(function(data) {
14
+      $scope.pod = data;
15
+    });
16
+  });
0 17
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+'use strict';
1
+
2
+/**
3
+ * @ngdoc function
4
+ * @name openshiftConsole.controller:AboutCtrl
5
+ * @description
6
+ * # AboutCtrl
7
+ * Controller of the openshiftConsole
8
+ */
9
+angular.module('openshiftConsole')
10
+  .controller('PodsController', function ($scope, $http) {
11
+    $scope.pods = [];
12
+    $http.defaults.useXDomain = true;
13
+    $http.get('http://localhost:8080/api/v1beta1/pods').success(function(data) {
14
+      $scope.pods = data.items;
15
+    });
16
+  });
0 17
new file mode 100644
... ...
@@ -0,0 +1,92 @@
0
+$icon-font-path: "../bower_components/bootstrap-sass-official/assets/fonts/bootstrap/";
1
+// bower:scss
2
+@import "bootstrap-sass-official/assets/stylesheets/_bootstrap.scss";
3
+// endbower
4
+
5
+.browsehappy {
6
+  margin: 0.2em 0;
7
+  background: #ccc;
8
+  color: #000;
9
+  padding: 0.2em 0;
10
+}
11
+
12
+/* Space out content a bit */
13
+body {
14
+  padding-top: 20px;
15
+  padding-bottom: 20px;
16
+}
17
+
18
+/* Everything but the jumbotron gets side spacing for mobile first views */
19
+.header,
20
+.marketing,
21
+.footer {
22
+  padding-left: 15px;
23
+  padding-right: 15px;
24
+}
25
+
26
+/* Custom page header */
27
+.header {
28
+  border-bottom: 1px solid #e5e5e5;
29
+
30
+  /* Make the masthead heading the same height as the navigation */
31
+  h3 {
32
+    margin-top: 0;
33
+    margin-bottom: 0;
34
+    line-height: 40px;
35
+    padding-bottom: 19px;
36
+  }
37
+}
38
+
39
+/* Custom page footer */
40
+.footer {
41
+  padding-top: 19px;
42
+  color: #777;
43
+  border-top: 1px solid #e5e5e5;
44
+}
45
+
46
+.container-narrow > hr {
47
+  margin: 30px 0;
48
+}
49
+
50
+/* Main marketing message and sign up button */
51
+.jumbotron {
52
+  text-align: center;
53
+  border-bottom: 1px solid #e5e5e5;
54
+
55
+  .btn {
56
+    font-size: 21px;
57
+    padding: 14px 24px;
58
+  }
59
+}
60
+
61
+/* Supporting marketing content */
62
+.marketing {
63
+  margin: 40px 0;
64
+
65
+  p + h4 {
66
+    margin-top: 28px;
67
+  }
68
+}
69
+
70
+/* Responsive: Portrait tablets and up */
71
+@media screen and (min-width: 768px) {
72
+  .container {
73
+    max-width: 730px;
74
+  }
75
+
76
+  /* Remove the padding we set earlier */
77
+  .header,
78
+  .marketing,
79
+  .footer {
80
+    padding-left: 0;
81
+    padding-right: 0;
82
+  }
83
+  /* Space out the masthead */
84
+  .header {
85
+    margin-bottom: 30px;
86
+  }
87
+  /* Remove the bottom border on the jumbotron for visual effect */
88
+  .jumbotron {
89
+    border-bottom: 0;
90
+  }
91
+}
0 92
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+<p>This is the about view.</p>
0 1
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+<div class="jumbotron">
1
+  <p class="lead">
2
+    The v3 management console is coming soon...
3
+  </p>
4
+</div>
5
+
6
+
0 7
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+<div class="simple-controller">
1
+
2
+  <div class="row-fluid">
3
+    <div class="span6 offset3">
4
+      <h2>OpenShift 3.x Demo</h2>
5
+    </div>
6
+  </div>
7
+  <div class="row-fluid">
8
+    <div class="span6 offset3">
9
+      <h3>Minions:</h3>
10
+      <ul>
11
+        <li ng-repeat="minion in minions">{{minion.id}}</li>
12
+      </ul>
13
+    </div>
14
+  </div>
15
+</div>
0 16
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+<div class="simple-controller">
1
+
2
+  <div class="row-fluid">
3
+    <div class="span6 offset3">
4
+      <h2>OpenShift 3.x Demo</h2>
5
+    </div>
6
+  </div>
7
+  <div class="row-fluid">
8
+    <div class="span6 offset3">
9
+      <h3>Pod: {{pod.id}}</h3>
10
+      <ul>
11
+        <li ng-repeat="container in pod.desiredState.manifest.containers">
12
+        {{container.image}} - ports: <span ng-repeat="port in container.ports">{{port.hostPort}}:{{port.containerPort}}</span>
13
+        </li>
14
+      </ul>
15
+    </div>
16
+  </div>
17
+</div>
0 18
new file mode 100644
... ...
@@ -0,0 +1,23 @@
0
+<div class="simple-controller">
1
+
2
+  <div class="row-fluid">
3
+    <div class="span6 offset3">
4
+      <h2>OpenShift 3.x Demo</h2>
5
+    </div>
6
+  </div>
7
+  <div class="row-fluid">
8
+    <div class="span6 offset3">
9
+      <h3>Pods:</h3>
10
+      <ul>
11
+        <li ng-repeat="pod in pods">
12
+          <a href="#/pods/{{pod.id}}">{{pod.id}}</a> - containers:
13
+          <ul>
14
+            <li ng-repeat="container in pod.desiredState.manifest.containers">
15
+            {{container.image}} - ports: <span ng-repeat="port in container.ports">{{port.hostPort}}:{{port.containerPort}}</span>
16
+            </li>
17
+          </ul>
18
+        </li>
19
+      </ul>
20
+    </div>
21
+  </div>
22
+</div>
0 23
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+{
1
+  "name": "assets",
2
+  "version": "0.0.0",
3
+  "dependencies": {
4
+    "angular": "~1.2.0",
5
+    "json3": "~3.3.1",
6
+    "es5-shim": "~3.1.0",
7
+    "bootstrap-sass-official": "~3.2.0",
8
+    "angular-resource": "~1.2.0",
9
+    "angular-cookies": "~1.2.0",
10
+    "angular-sanitize": "~1.2.0",
11
+    "angular-animate": "~1.2.0",
12
+    "angular-touch": "~1.2.0",
13
+    "angular-route": "~1.2.0",
14
+    "angular-bootstrap": "~0.11.0"
15
+  },
16
+  "devDependencies": {
17
+    "angular-mocks": "~1.2.0",
18
+    "angular-scenario": "~1.2.0"
19
+  },
20
+  "appPath": "app"
21
+}
0 22
new file mode 100644
... ...
@@ -0,0 +1,43 @@
0
+{
1
+  "name": "assets",
2
+  "version": "0.0.0",
3
+  "dependencies": {},
4
+  "devDependencies": {
5
+    "grunt": "~0.4.5",
6
+    "grunt-autoprefixer": "^0.7.3",
7
+    "grunt-concurrent": "^0.5.0",
8
+    "grunt-contrib-clean": "^0.5.0",
9
+    "grunt-contrib-compass": "^0.7.2",
10
+    "grunt-contrib-concat": "^0.4.0",
11
+    "grunt-contrib-connect": "^0.7.1",
12
+    "grunt-contrib-copy": "^0.5.0",
13
+    "grunt-contrib-cssmin": "^0.9.0",
14
+    "grunt-contrib-htmlmin": "^0.3.0",
15
+    "grunt-contrib-imagemin": "^0.8.1",
16
+    "grunt-contrib-jshint": "^0.10.0",
17
+    "grunt-contrib-uglify": "^0.4.0",
18
+    "grunt-contrib-watch": "^0.6.1",
19
+    "grunt-filerev": "^0.2.1",
20
+    "grunt-google-cdn": "^0.4.0",
21
+    "grunt-newer": "^0.7.0",
22
+    "grunt-ng-annotate": "^0.3.0",
23
+    "grunt-svgmin": "^0.4.0",
24
+    "grunt-usemin": "^2.1.1",
25
+    "grunt-wiredep": "^1.7.0",
26
+    "jshint-stylish": "^0.2.0",
27
+    "load-grunt-tasks": "^0.4.0",
28
+    "time-grunt": "^0.3.1",
29
+    "karma-phantomjs-launcher": "~0.1.4",
30
+    "karma": "~0.12.23",
31
+    "karma-jasmine": "~0.1.5",
32
+    "grunt-karma": "~0.9.0",
33
+    "karma-coverage": "~0.2.6",
34
+    "grunt-istanbul-coverage": "0.0.5"
35
+  },
36
+  "engines": {
37
+    "node": ">=0.10.0"
38
+  },
39
+  "scripts": {
40
+    "test": "grunt test"
41
+  }
42
+}
0 43
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+coverage
0 1
\ No newline at end of file
1 2
new file mode 100644
... ...
@@ -0,0 +1,36 @@
0
+{
1
+  "node": true,
2
+  "browser": true,
3
+  "esnext": true,
4
+  "bitwise": true,
5
+  "camelcase": true,
6
+  "curly": true,
7
+  "eqeqeq": true,
8
+  "immed": true,
9
+  "indent": 2,
10
+  "latedef": true,
11
+  "newcap": true,
12
+  "noarg": true,
13
+  "quotmark": "single",
14
+  "regexp": true,
15
+  "undef": true,
16
+  "unused": true,
17
+  "strict": true,
18
+  "trailing": true,
19
+  "smarttabs": true,
20
+  "globals": {
21
+    "after": false,
22
+    "afterEach": false,
23
+    "angular": false,
24
+    "before": false,
25
+    "beforeEach": false,
26
+    "browser": false,
27
+    "describe": false,
28
+    "expect": false,
29
+    "inject": false,
30
+    "it": false,
31
+    "jasmine": false,
32
+    "spyOn": false
33
+  }
34
+}
35
+
0 36
new file mode 100644
... ...
@@ -0,0 +1,92 @@
0
+// Karma configuration
1
+// http://karma-runner.github.io/0.12/config/configuration-file.html
2
+// Generated on 2014-09-12 using
3
+// generator-karma 0.8.3
4
+
5
+module.exports = function(config) {
6
+  'use strict';
7
+
8
+  config.set({
9
+    // enable / disable watching file and executing tests whenever any file changes
10
+    autoWatch: true,
11
+
12
+    // base path, that will be used to resolve files and exclude
13
+    basePath: '../',
14
+
15
+    // testing framework to use (jasmine/mocha/qunit/...)
16
+    frameworks: ['jasmine'],
17
+
18
+    // list of files / patterns to load in the browser
19
+    files: [
20
+      'bower_components/angular/angular.js',
21
+      'bower_components/angular-mocks/angular-mocks.js',
22
+      'bower_components/angular-animate/angular-animate.js',
23
+      'bower_components/angular-cookies/angular-cookies.js',
24
+      'bower_components/angular-resource/angular-resource.js',
25
+      'bower_components/angular-route/angular-route.js',
26
+      'bower_components/angular-sanitize/angular-sanitize.js',
27
+      'bower_components/angular-touch/angular-touch.js',
28
+      'app/scripts/**/*.js',
29
+      //'test/mock/**/*.js',
30
+      'test/spec/**/*.js'
31
+    ],
32
+
33
+    // list of files / patterns to exclude
34
+    exclude: [],
35
+
36
+    // web server port
37
+    port: 8080,
38
+
39
+    // Start these browsers, currently available:
40
+    // - Chrome
41
+    // - ChromeCanary
42
+    // - Firefox
43
+    // - Opera
44
+    // - Safari (only Mac)
45
+    // - PhantomJS
46
+    // - IE (only Windows)
47
+    browsers: [
48
+      'PhantomJS'
49
+    ],
50
+
51
+    // Which plugins to enable
52
+    plugins: [
53
+      'karma-phantomjs-launcher',
54
+      'karma-jasmine',
55
+      'karma-coverage'
56
+    ],
57
+
58
+    // Continuous Integration mode
59
+    // if true, it capture browsers, run tests and exit
60
+    singleRun: false,
61
+
62
+    colors: true,
63
+
64
+    // level of logging
65
+    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
66
+    logLevel: config.LOG_INFO,
67
+
68
+    // Uncomment the following lines if you are using grunt's server to run the tests
69
+    // proxies: {
70
+    //   '/': 'http://localhost:9000/'
71
+    // },
72
+    // URL root prevent conflicts with the site root
73
+    // urlRoot: '_karma_'
74
+
75
+    preprocessors: {
76
+      // source files, that you wanna generate coverage for
77
+      // do not include tests or libraries
78
+      // (these files will be instrumented by Istanbul)
79
+      'app/**/*.js': ['coverage']
80
+    },
81
+
82
+    reporters: ['progress', 'coverage'],
83
+
84
+    coverageReporter: {
85
+      reporters:[
86
+        {type: 'json', dir:'test/coverage/'},
87
+        {type: 'text-summary', dir:'test/coverage/'}
88
+      ]
89
+    }    
90
+  });
91
+};
0 92
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+'use strict';
1
+
2
+describe('Controller: AboutCtrl', function () {
3
+
4
+  // load the controller's module
5
+  beforeEach(module('openshiftConsole'));
6
+
7
+  var AboutCtrl,
8
+    scope;
9
+
10
+  // Initialize the controller and a mock scope
11
+  beforeEach(inject(function ($controller, $rootScope) {
12
+    scope = $rootScope.$new();
13
+    AboutCtrl = $controller('AboutCtrl', {
14
+      $scope: scope
15
+    });
16
+  }));
17
+
18
+  it('should attach a list of awesomeThings to the scope', function () {
19
+    expect(scope.awesomeThings.length).toBe(3);
20
+  });
21
+});
0 22
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+'use strict';
1
+
2
+describe('Controller: MainCtrl', function () {
3
+
4
+  // load the controller's module
5
+  beforeEach(module('openshiftConsole'));
6
+
7
+  var MainCtrl,
8
+    scope;
9
+
10
+  // Initialize the controller and a mock scope
11
+  beforeEach(inject(function ($controller, $rootScope) {
12
+    scope = $rootScope.$new();
13
+    MainCtrl = $controller('MainCtrl', {
14
+      $scope: scope
15
+    });
16
+  }));
17
+
18
+  it('should attach a list of awesomeThings to the scope', function () {
19
+    expect(scope.awesomeThings.length).toBe(3);
20
+  });
21
+});
0 22
new file mode 100755
... ...
@@ -0,0 +1,11 @@
0
+#!/bin/bash
1
+
2
+set -e
3
+
4
+# If we are running inside of Travis then do not run the rest of this
5
+# script unless we want to TEST_ASSETS
6
+if [[ "${TRAVIS}" == "true" && "${TEST_ASSETS}" == "false" ]]; then
7
+  exit
8
+fi
9
+
10
+sudo apt-get install -qq ruby
0 11
\ No newline at end of file
... ...
@@ -28,4 +28,10 @@ for arg; do
28 28
   binaries+=("${OS_GO_PACKAGE}/${arg}")
29 29
 done
30 30
 
31
-go install -ldflags "-X github.com/GoogleCloudPlatform/kubernetes/pkg/version.gitCommit '${kube_version}' -X github.com/openshift/origin/pkg/version.commitFromGit '${version}'" "${binaries[@]}"
31
+build_tags=""
32
+if [[ ! -z "$OS_BUILD_TAGS" ]]; then
33
+  build_tags="-tags \"$OS_BUILD_TAGS\""
34
+fi
35
+
36
+
37
+go install $build_tags -ldflags "-X github.com/GoogleCloudPlatform/kubernetes/pkg/version.gitCommit '${kube_version}' -X github.com/openshift/origin/pkg/version.commitFromGit '${version}'" "${binaries[@]}"
... ...
@@ -17,6 +17,8 @@ function gitcommit() {
17 17
     # Check if the tree is dirty.
18 18
     if ! dirty_tree=$(git status --porcelain) || [[ -n "${dirty_tree}" ]]; then
19 19
       echo "${git_commit}-dirty"
20
+    else
21
+      echo "${git_commit}"
20 22
     fi
21 23
   else
22 24
     echo "(none)"
... ...
@@ -71,3 +73,5 @@ export GOPATH
71 71
 
72 72
 # Unset GOBIN in case it already exists in the current session.
73 73
 unset GOBIN
74
+
75
+OS_BUILD_TAGS=${OS_BUILD_TAGS-}
74 76
\ No newline at end of file
75 77
new file mode 100755
... ...
@@ -0,0 +1,16 @@
0
+#!/bin/bash
1
+
2
+set -e
3
+
4
+# If we are running inside of Travis then do not run the rest of this
5
+# script unless we want to TEST_ASSETS
6
+if [[ "${TRAVIS}" == "true" && "${TEST_ASSETS}" == "false" ]]; then
7
+  exit
8
+fi
9
+
10
+npm install -g bower grunt-cli
11
+pushd assets > /dev/null
12
+  npm install
13
+  bower install
14
+popd > /dev/null
15
+gem install compass
0 16
\ No newline at end of file
1 17
new file mode 100755
... ...
@@ -0,0 +1,13 @@
0
+#!/bin/bash
1
+
2
+set -e
3
+
4
+# If we are running inside of Travis then do not run the rest of this
5
+# script unless we want to TEST_ASSETS
6
+if [[ "${TRAVIS}" == "true" && "${TEST_ASSETS}" == "false" ]]; then
7
+  exit
8
+fi
9
+
10
+pushd assets > /dev/null
11
+  grunt test
12
+popd > /dev/null
0 13
\ No newline at end of file
1 14
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+bindata.go
0 1
\ No newline at end of file
1 2
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+// +build !release
1
+
2
+package assets
3
+
4
+import (
5
+	"fmt"
6
+)
7
+
8
+// This file contains no-op versions of the methods for use during non-release builds
9
+
10
+// Asset loads and returns the asset for the given name.
11
+// It returns an error if the asset could not be found or
12
+// could not be loaded.
13
+func Asset(name string) ([]byte, error) {
14
+	return nil, fmt.Errorf("Asset %s not found", name)
15
+}
16
+
17
+// AssetNames returns the names of the assets.
18
+func AssetNames() []string {
19
+	return []string{}
20
+}
21
+
22
+// AssetDir returns the file names below a certain
23
+// directory embedded in the file by go-bindata.
24
+// For example if you run go-bindata on data/... and data contains the
25
+// following hierarchy:
26
+//     data/
27
+//       foo.txt
28
+//       img/
29
+//         a.png
30
+//         b.png
31
+// then AssetDir("data") would return []string{"foo.txt", "img"}
32
+// AssetDir("data/img") would return []string{"a.png", "b.png"}
33
+// AssetDir("foo.txt") and AssetDir("notexist") would return an error
34
+// AssetDir("") will return []string{"data"}.
35
+func AssetDir(name string) ([]string, error) {
36
+	return []string{}, nil
37
+}
... ...
@@ -1,6 +1,7 @@
1 1
 package master
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"net/http"
5 6
 	"os"
6 7
 	"path"
... ...
@@ -23,12 +24,14 @@ import (
23 23
 	etcdconfig "github.com/coreos/etcd/config"
24 24
 	"github.com/coreos/etcd/etcd"
25 25
 	etcdclient "github.com/coreos/go-etcd/etcd"
26
+	"github.com/elazarl/go-bindata-assetfs"
26 27
 	"github.com/golang/glog"
27 28
 	cadvisor "github.com/google/cadvisor/client"
28 29
 	"github.com/spf13/cobra"
29 30
 
30 31
 	"github.com/openshift/origin/pkg/api/latest"
31 32
 	"github.com/openshift/origin/pkg/api/v1beta1"
33
+	"github.com/openshift/origin/pkg/assets"
32 34
 	"github.com/openshift/origin/pkg/build"
33 35
 	buildapi "github.com/openshift/origin/pkg/build/api"
34 36
 	buildregistry "github.com/openshift/origin/pkg/build/registry/build"
... ...
@@ -48,6 +51,7 @@ import (
48 48
 	"github.com/openshift/origin/pkg/image/registry/imagerepository"
49 49
 	"github.com/openshift/origin/pkg/image/registry/imagerepositorymapping"
50 50
 	"github.com/openshift/origin/pkg/template"
51
+	"github.com/openshift/origin/pkg/version"
51 52
 
52 53
 	// Register versioned api types
53 54
 	_ "github.com/openshift/origin/pkg/config/api/v1beta1"
... ...
@@ -158,6 +162,7 @@ func (c *config) getEtcdClient() (*etcdclient.Client, []string) {
158 158
 func (c *config) startAllInOne() {
159 159
 	c.runEtcd()
160 160
 	c.runApiserver()
161
+	c.runAssetServer()
161 162
 	c.runKubelet()
162 163
 	c.runProxy()
163 164
 	c.runScheduler()
... ...
@@ -266,6 +271,38 @@ func (c *config) runApiserver() {
266 266
 	}, 0)
267 267
 }
268 268
 
269
+func (c *config) runAssetServer() {
270
+	// TODO prefix should be able to be overridden at the command line
271
+	// move this out to a helper / config
272
+	prefix := fmt.Sprintf("/assets/%s/", version.Get().GitCommit)
273
+	// TODO configurable listen address
274
+	addr := c.masterHost + ":8091"
275
+	// TODO - For now redirect requests to the root to the commit-based index.html URL
276
+	// Next step is to have the root page served without redirecting.  May require build
277
+	// changes or altering index.html while serving.
278
+	mux := http.NewServeMux()
279
+	mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
280
+		urlStr := fmt.Sprintf("%sindex.html", prefix)
281
+		http.Redirect(w, req, urlStr, http.StatusTemporaryRedirect)
282
+	}))
283
+
284
+	mux.Handle(prefix, http.StripPrefix(prefix, http.FileServer(
285
+		&assetfs.AssetFS{assets.Asset, assets.AssetDir, ""})))
286
+
287
+	osAssets := &http.Server{
288
+		Addr:           addr,
289
+		Handler:        mux,
290
+		ReadTimeout:    5 * time.Minute,
291
+		WriteTimeout:   5 * time.Minute,
292
+		MaxHeaderBytes: 1 << 20,
293
+	}
294
+
295
+	go util.Forever(func() {
296
+		glog.Infof("Started OpenShift static asset server at http://%s", addr)
297
+		glog.Fatal(osAssets.ListenAndServe())
298
+	}, 0)
299
+}
300
+
269 301
 func (c *config) runKubelet() {
270 302
 	rootDirectory := path.Clean(c.VolumeDir)
271 303
 	minionHost := c.bindAddr