1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2024-10-29 23:22:34 +01:00

Updated build and versioning system

Added versioning file instead of using git tags
(Step towards removing git as a dependancy in the future)

Updated gulpfile to fit with verisioning system and cleaned
up node dependancies.

Fixes #108
This commit is contained in:
Dan Brown 2016-10-30 17:44:00 +00:00
parent a6c6c6e300
commit ab468bac3c
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
14 changed files with 72 additions and 128 deletions

3
.gitignore vendored
View File

@ -11,4 +11,5 @@ Homestead.yaml
/storage/images /storage/images
_ide_helper.php _ide_helper.php
/storage/debugbar /storage/debugbar
.phpstorm.meta.php .phpstorm.meta.php
yarn.lock

View File

@ -17,10 +17,7 @@ class SettingController extends Controller
$this->setPageTitle('Settings'); $this->setPageTitle('Settings');
// Get application version // Get application version
$version = false; $version = trim(file_get_contents(base_path('version')));
if (function_exists('exec')) {
$version = exec('git describe --always --tags ');
}
return view('settings/index', ['version' => $version]); return view('settings/index', ['version' => $version]);
} }

View File

@ -11,29 +11,20 @@ use BookStack\Ownable;
*/ */
function versioned_asset($file = '') function versioned_asset($file = '')
{ {
// Don't require css and JS assets for testing static $version = null;
if (config('app.env') === 'testing') return '';
static $manifest = null; if (is_null($version)) {
$manifestPath = 'build/manifest.json'; $versionFile = base_path('version');
$version = trim(file_get_contents($versionFile));
if (is_null($manifest) && file_exists($manifestPath)) {
$manifest = json_decode(file_get_contents(public_path($manifestPath)), true);
} else if (!file_exists($manifestPath)) {
if (config('app.env') !== 'production') {
$path = public_path($manifestPath);
$error = "No {$path} file found, Ensure you have built the css/js assets using gulp.";
} else {
$error = "No {$manifestPath} file found, Ensure you are using the release version of BookStack";
}
throw new \Exception($error);
} }
if (isset($manifest[$file])) { $additional = '';
return baseUrl($manifest[$file]); if (config('app.env') === 'development') {
$additional = sha1_file(public_path($file));
} }
throw new InvalidArgumentException("File {$file} not defined in asset manifest."); $path = $file . '?version=' . urlencode($version) . $additional;
return baseUrl($path);
} }
/** /**
@ -138,14 +129,14 @@ function sortUrl($path, $data, $overrideData = [])
{ {
$queryStringSections = []; $queryStringSections = [];
$queryData = array_merge($data, $overrideData); $queryData = array_merge($data, $overrideData);
// Change sorting direction is already sorted on current attribute // Change sorting direction is already sorted on current attribute
if (isset($overrideData['sort']) && $overrideData['sort'] === $data['sort']) { if (isset($overrideData['sort']) && $overrideData['sort'] === $data['sort']) {
$queryData['order'] = ($data['order'] === 'asc') ? 'desc' : 'asc'; $queryData['order'] = ($data['order'] === 'asc') ? 'desc' : 'asc';
} else { } else {
$queryData['order'] = 'asc'; $queryData['order'] = 'asc';
} }
foreach ($queryData as $name => $value) { foreach ($queryData as $name => $value) {
$trimmedVal = trim($value); $trimmedVal = trim($value);
if ($trimmedVal === '') continue; if ($trimmedVal === '') continue;
@ -155,4 +146,4 @@ function sortUrl($path, $data, $overrideData = [])
if (count($queryStringSections) === 0) return $path; if (count($queryStringSections) === 0) return $path;
return baseUrl($path . '?' . implode('&', $queryStringSections)); return baseUrl($path . '?' . implode('&', $queryStringSections));
} }

View File

@ -1,27 +1,8 @@
var elixir = require('laravel-elixir'); var elixir = require('laravel-elixir');
// Custom extensions elixir(mix => {
var gulp = require('gulp'); mix.sass('styles.scss');
var Task = elixir.Task; mix.sass('print-styles.scss');
var fs = require('fs'); mix.sass('export-styles.scss');
mix.browserify('global.js', './public/js/common.js');
elixir.extend('queryVersion', function(inputFiles) {
new Task('queryVersion', function() {
var manifestObject = {};
var uidString = Date.now().toString(16).slice(4);
for (var i = 0; i < inputFiles.length; i++) {
var file = inputFiles[i];
manifestObject[file] = file + '?version=' + uidString;
}
var fileContents = JSON.stringify(manifestObject, null, 1);
fs.writeFileSync('public/build/manifest.json', fileContents);
}).watch(['./public/css/*.css', './public/js/*.js']);
});
elixir(function(mix) {
mix.sass('styles.scss')
.sass('print-styles.scss')
.sass('export-styles.scss')
.browserify('global.js', 'public/js/common.js')
.queryVersion(['css/styles.css', 'css/print-styles.css', 'js/common.js']);
}); });

View File

@ -1,18 +1,19 @@
{ {
"private": true, "private": true,
"devDependencies": { "scripts": {
"gulp": "^3.9.0" "prod": "gulp --production",
"dev": "gulp watch"
}, },
"dependencies": { "devDependencies": {
"angular": "^1.5.5", "angular": "^1.5.5",
"angular-animate": "^1.5.5", "angular-animate": "^1.5.5",
"angular-resource": "^1.5.5", "angular-resource": "^1.5.5",
"angular-sanitize": "^1.5.5", "angular-sanitize": "^1.5.5",
"angular-ui-sortable": "^0.14.0", "angular-ui-sortable": "^0.15.0",
"babel-runtime": "^5.8.29",
"bootstrap-sass": "^3.0.0",
"dropzone": "^4.0.1", "dropzone": "^4.0.1",
"laravel-elixir": "^5.0.0", "gulp": "^3.9.0",
"laravel-elixir": "^6.0.0-11",
"laravel-elixir-browserify-official": "^0.1.3",
"marked": "^0.3.5", "marked": "^0.3.5",
"moment": "^2.12.0", "moment": "^2.12.0",
"zeroclipboard": "^2.2.0" "zeroclipboard": "^2.2.0"

View File

@ -30,6 +30,7 @@
<env name="AUTH_METHOD" value="standard"/> <env name="AUTH_METHOD" value="standard"/>
<env name="DISABLE_EXTERNAL_SERVICES" value="true"/> <env name="DISABLE_EXTERNAL_SERVICES" value="true"/>
<env name="LDAP_VERSION" value="3"/> <env name="LDAP_VERSION" value="3"/>
<env name="STORAGE_TYPE" value="local"/>
<env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/> <env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
<env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/> <env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
<env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/> <env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>

View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -2,13 +2,15 @@
[![GitHub release](https://img.shields.io/github/release/ssddanbrown/BookStack.svg?maxAge=2592000)](https://github.com/ssddanbrown/BookStack/releases/latest) [![GitHub release](https://img.shields.io/github/release/ssddanbrown/BookStack.svg?maxAge=2592000)](https://github.com/ssddanbrown/BookStack/releases/latest)
[![license](https://img.shields.io/github/license/ssddanbrown/BookStack.svg?maxAge=2592000)](https://github.com/ssddanbrown/BookStack/blob/master/LICENSE) [![license](https://img.shields.io/github/license/ssddanbrown/BookStack.svg?maxAge=2592000)](https://github.com/ssddanbrown/BookStack/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/ssddanbrown/BookStack.svg)](https://travis-ci.org/ssddanbrown/BookStack) [![Build Status](https://travis-ci.org/BookStackApp/BookStack.svg)](https://travis-ci.org/BookStackApp/BookStack)
A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/. A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/.
* [Installation Instructions](https://www.bookstackapp.com/docs/admin/installation) * [Installation Instructions](https://www.bookstackapp.com/docs/admin/installation)
* [Documentation](https://www.bookstackapp.com/docs) * [Documentation](https://www.bookstackapp.com/docs)
* [Demo Instance](https://demo.bookstackapp.com) *(Login username: `admin@example.com`. Password: `password`)* * [Demo Instance](https://demo.bookstackapp.com)
* *Username: `admin@example.com`*
* *Password: `password`*
* [BookStack Blog](https://www.bookstackapp.com/blog) * [BookStack Blog](https://www.bookstackapp.com/blog)
## Development & Testing ## Development & Testing
@ -29,7 +31,7 @@ php artisan migrate --database=mysql_testing
php artisan db:seed --class=DummyContentSeeder --database=mysql_testing php artisan db:seed --class=DummyContentSeeder --database=mysql_testing
``` ```
Once done you can run `phpunit` (or `./vendor/bin/phpunit` if `phpunit` is not found) in the application root directory to run all tests. Once done you can run `phpunit` in the application root directory to run all tests.
## License ## License
@ -51,3 +53,5 @@ These are the great projects used to help build BookStack:
* [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html) * [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html)
* [Marked](https://github.com/chjj/marked) * [Marked](https://github.com/chjj/marked)
* [Moment.js](http://momentjs.com/) * [Moment.js](http://momentjs.com/)
Additionally, Thank you [BrowserStack](https://www.browserstack.com/) for supporting us and making cross-browser testing easy.

View File

@ -1,3 +0,0 @@
<div class="dropzone-container">
<div class="dz-message">Drop files or click here to upload</div>
</div>

View File

@ -1,15 +0,0 @@
<div class="image-picker">
<div>
<img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
<img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
</div>
<button class="button" type="button" ng-click="showImageManager()">Select Image</button>
<br>
<button class="text-button" ng-click="reset()" type="button">Reset</button>
<span ng-show="showRemove" class="sep">|</span>
<button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
<input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
</div>

View File

@ -1,4 +0,0 @@
<div class="toggle-switch" ng-click="switch()" ng-class="{'active': isActive}">
<input type="hidden" ng-attr-name="{{name}}" ng-attr-value="{{value}}"/>
<div class="switch-handle"></div>
</div>

View File

@ -1,6 +1,8 @@
"use strict"; "use strict";
const moment = require('moment'); import moment from 'moment';
import 'moment/locale/en-gb';
moment.locale('en-gb');
module.exports = function (ngApp, events) { module.exports = function (ngApp, events) {
@ -17,7 +19,7 @@ module.exports = function (ngApp, events) {
$scope.imageDeleteSuccess = false; $scope.imageDeleteSuccess = false;
$scope.uploadedTo = $attrs.uploadedTo; $scope.uploadedTo = $attrs.uploadedTo;
$scope.view = 'all'; $scope.view = 'all';
$scope.searching = false; $scope.searching = false;
$scope.searchTerm = ''; $scope.searchTerm = '';
@ -48,7 +50,7 @@ module.exports = function (ngApp, events) {
$scope.hasMore = preSearchHasMore; $scope.hasMore = preSearchHasMore;
} }
$scope.cancelSearch = cancelSearch; $scope.cancelSearch = cancelSearch;
/** /**
* Runs on image upload, Adds an image to local list of images * Runs on image upload, Adds an image to local list of images
@ -437,7 +439,7 @@ module.exports = function (ngApp, events) {
const pageId = Number($attrs.pageId); const pageId = Number($attrs.pageId);
$scope.tags = []; $scope.tags = [];
$scope.sortOptions = { $scope.sortOptions = {
handle: '.handle', handle: '.handle',
items: '> tr', items: '> tr',
@ -729,20 +731,3 @@ module.exports = function (ngApp, events) {
}]); }]);
}; };

View File

@ -2,10 +2,6 @@
const DropZone = require('dropzone'); const DropZone = require('dropzone');
const markdown = require('marked'); const markdown = require('marked');
const toggleSwitchTemplate = require('./components/toggle-switch.html');
const imagePickerTemplate = require('./components/image-picker.html');
const dropZoneTemplate = require('./components/drop-zone.html');
module.exports = function (ngApp, events) { module.exports = function (ngApp, events) {
/** /**
@ -16,7 +12,12 @@ module.exports = function (ngApp, events) {
ngApp.directive('toggleSwitch', function () { ngApp.directive('toggleSwitch', function () {
return { return {
restrict: 'A', restrict: 'A',
template: toggleSwitchTemplate, template: `
<div class="toggle-switch" ng-click="switch()" ng-class="{'active': isActive}">
<input type="hidden" ng-attr-name="{{name}}" ng-attr-value="{{value}}"/>
<div class="switch-handle"></div>
</div>
`,
scope: true, scope: true,
link: function (scope, element, attrs) { link: function (scope, element, attrs) {
scope.name = attrs.name; scope.name = attrs.name;
@ -77,7 +78,7 @@ module.exports = function (ngApp, events) {
}); });
element.find('button[type="submit"]').click(submitEvent); element.find('button[type="submit"]').click(submitEvent);
function submitEvent(e) { function submitEvent(e) {
e.preventDefault() e.preventDefault()
if (attrs.subForm) scope.$eval(attrs.subForm); if (attrs.subForm) scope.$eval(attrs.subForm);
@ -94,7 +95,22 @@ module.exports = function (ngApp, events) {
ngApp.directive('imagePicker', ['$http', 'imageManagerService', function ($http, imageManagerService) { ngApp.directive('imagePicker', ['$http', 'imageManagerService', function ($http, imageManagerService) {
return { return {
restrict: 'E', restrict: 'E',
template: imagePickerTemplate, template: `
<div class="image-picker">
<div>
<img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
<img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
</div>
<button class="button" type="button" ng-click="showImageManager()">Select Image</button>
<br>
<button class="text-button" ng-click="reset()" type="button">Reset</button>
<span ng-show="showRemove" class="sep">|</span>
<button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
<input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
</div>
`,
scope: { scope: {
name: '@', name: '@',
resizeHeight: '@', resizeHeight: '@',
@ -161,7 +177,11 @@ module.exports = function (ngApp, events) {
ngApp.directive('dropZone', [function () { ngApp.directive('dropZone', [function () {
return { return {
restrict: 'E', restrict: 'E',
template: dropZoneTemplate, template: `
<div class="dropzone-container">
<div class="dz-message">Drop files or click here to upload</div>
</div>
`,
scope: { scope: {
uploadUrl: '@', uploadUrl: '@',
eventSuccess: '=', eventSuccess: '=',
@ -603,7 +623,7 @@ module.exports = function (ngApp, events) {
let val = $input.val(); let val = $input.val();
let url = $input.attr('autosuggest'); let url = $input.attr('autosuggest');
let type = $input.attr('autosuggest-type'); let type = $input.attr('autosuggest-type');
// Add name param to request if for a value // Add name param to request if for a value
if (type.toLowerCase() === 'value') { if (type.toLowerCase() === 'value') {
let $nameInput = $input.closest('tr').find('[autosuggest-type="name"]').first(); let $nameInput = $input.closest('tr').find('[autosuggest-type="name"]').first();
@ -904,17 +924,3 @@ module.exports = function (ngApp, events) {
}; };
}]); }]);
}; };

1
version Normal file
View File

@ -0,0 +1 @@
v0.13-dev