Show More
The requested changes are too big and content was truncated. Show full diff
@@ -0,0 +1,15 b'' | |||
|
1 | { | |
|
2 | "name": "rhodecode-elements", | |
|
3 | "description": "User interface for elements for rhodecode", | |
|
4 | "main": "index.html", | |
|
5 | "dependencies": { | |
|
6 | "webcomponentsjs": "^0.7.22", | |
|
7 | "polymer": "Polymer/polymer#^1.6.1", | |
|
8 | "paper-button": "PolymerElements/paper-button#^1.0.13", | |
|
9 | "paper-spinner": "PolymerElements/paper-spinner#^1.2.0", | |
|
10 | "paper-tooltip": "PolymerElements/paper-tooltip#^1.1.2", | |
|
11 | "paper-toast": "PolymerElements/paper-toast#^1.3.0", | |
|
12 | "paper-toggle-button": "PolymerElements/paper-toggle-button#^1.2.0", | |
|
13 | "iron-ajax": "PolymerElements/iron-ajax#^1.4.3" | |
|
14 | } | |
|
15 | } |
@@ -0,0 +1,60 b'' | |||
|
1 | ||
|
2 | ======================= | |
|
3 | Dependency management | |
|
4 | ======================= | |
|
5 | ||
|
6 | ||
|
7 | Overview | |
|
8 | ======== | |
|
9 | ||
|
10 | We use the Nix package manager to handle our dependencies. In general we use the | |
|
11 | packages out of the package collection `nixpkgs`. For frequently changing | |
|
12 | dependencies for Python and JavaScript we use the tools which are described in | |
|
13 | this section to generate the needed Nix derivations. | |
|
14 | ||
|
15 | ||
|
16 | Python dependencies | |
|
17 | =================== | |
|
18 | ||
|
19 | We use the tool `pip2nix` to generate the Nix derivations for our Python | |
|
20 | dependencies. | |
|
21 | ||
|
22 | Generating the dependencies should be done with the following command: | |
|
23 | ||
|
24 | .. code:: shell | |
|
25 | ||
|
26 | pip2nix generate --license | |
|
27 | ||
|
28 | ||
|
29 | .. note:: | |
|
30 | ||
|
31 | License extraction support is still experimental, use the version from the | |
|
32 | following pull request: https://github.com/ktosiek/pip2nix/pull/30 | |
|
33 | ||
|
34 | ||
|
35 | ||
|
36 | Node dependencies | |
|
37 | ================= | |
|
38 | ||
|
39 | After adding new dependencies via ``npm install --save``, use `node2nix` to | |
|
40 | update the corresponding Nix derivations: | |
|
41 | ||
|
42 | .. code:: shell | |
|
43 | ||
|
44 | cd pkgs | |
|
45 | node2nix --input ../package.json \ | |
|
46 | -o node-packages.nix \ | |
|
47 | -e node-env.nix \ | |
|
48 | -c node-default.nix \ | |
|
49 | -d --flatten | |
|
50 | ||
|
51 | ||
|
52 | Bower dependencies | |
|
53 | ================== | |
|
54 | ||
|
55 | Frontend dependencies are managed based on `bower`, with `bower2nix` a tool | |
|
56 | exists which can generate the needed Nix derivations: | |
|
57 | ||
|
58 | .. code:: shell | |
|
59 | ||
|
60 | bower2nix bower.json pkgs/bower-packages.nix |
@@ -0,0 +1,78 b'' | |||
|
1 | |RCE| 4.4.0 |RNS| | |
|
2 | ----------------- | |
|
3 | ||
|
4 | Release Date | |
|
5 | ^^^^^^^^^^^^ | |
|
6 | ||
|
7 | - 2016-09-16 | |
|
8 | ||
|
9 | ||
|
10 | General | |
|
11 | ^^^^^^^ | |
|
12 | ||
|
13 | - UI: introduced Polymer webcomponents into core application. RhodeCode will | |
|
14 | be now shipped together with Polymer framework webcomponents. Most of | |
|
15 | dynamic UI components that require large amounts of interaction | |
|
16 | will be done now with Polymer. | |
|
17 | - live-notifications: use rhodecode-toast for live notifications instead of | |
|
18 | toastr jquery plugin. | |
|
19 | - Svn: moved svn http support out of labs settings. It's tested and stable now. | |
|
20 | ||
|
21 | ||
|
22 | New Features | |
|
23 | ^^^^^^^^^^^^ | |
|
24 | ||
|
25 | - Integrations: integrations can now be configure on whole repo group to apply | |
|
26 | same integrations on multiple projects/groups at once. | |
|
27 | - Integrations: added scopes on integrations, scopes are: Global, | |
|
28 | Repository Group (with/without children), Repositories, Root Repositories Only. | |
|
29 | It will allow to configure exactly which projects use which integrations. | |
|
30 | - Integrations: show branches/commits separately when posting push events | |
|
31 | to hipchat/slack, fixes #4192. | |
|
32 | - Pull-requests: summary page now shows update dates for pull request to | |
|
33 | easier see which one were receantly updated. | |
|
34 | - UI: hidden inline comments will be shown in side view when browsing the diffs | |
|
35 | - Diffs: added inline comments toggle into pull requests diff view. #2884 | |
|
36 | - Live-chat: added summon reviewers functionality. You can now request | |
|
37 | presence from online users into a chat for collaborative code-review. | |
|
38 | This requires channelstream to be enabled. | |
|
39 | - UX: added a static 502 page for gateway error. Once configured via | |
|
40 | Nginx or Apache it will present a custom RhodeCode page while | |
|
41 | backend servers are offline. Fixes #4202. | |
|
42 | ||
|
43 | ||
|
44 | Security | |
|
45 | ^^^^^^^^ | |
|
46 | ||
|
47 | - Passwords: forced password change will not allow users to put in the | |
|
48 | old password as new one. | |
|
49 | ||
|
50 | ||
|
51 | Performance | |
|
52 | ^^^^^^^^^^^ | |
|
53 | ||
|
54 | - Vcs: refactor vcs-middleware to handle order of .ini file backends in | |
|
55 | detection of vcs protocol. Detection ends now on first match and speeds | |
|
56 | overall transaction speed. | |
|
57 | - Summary: Improve the algorithm and performance of detection README files | |
|
58 | inside summary page. In some cases we reduced cold-cache time from 50s to 1s. | |
|
59 | - Safari: improved speed of large diffs on Safari browser. | |
|
60 | - UX: remove position relative on diff td as it causes very slow | |
|
61 | rendering in browsers. | |
|
62 | ||
|
63 | Fixes | |
|
64 | ^^^^^ | |
|
65 | ||
|
66 | - UX: change confirm password widget to have spacing between the fields to | |
|
67 | match rest of ui, fixes: #4200. | |
|
68 | - UX: show multiple tags/branches in changelog/summary instead of | |
|
69 | truncating them. | |
|
70 | - My-account: fix test notifications for IE10+ | |
|
71 | - Vcs: change way refs are retrieved for git so same name branch/tags and | |
|
72 | remotes can be supported, fixes #298. | |
|
73 | - Lexers: added small extensions table to extend syntax highlighting for file | |
|
74 | sources. Fixes #4227. | |
|
75 | - Search: fix bug where file path link was wrong when the repository name was | |
|
76 | in the file path, fixes #4228 | |
|
77 | - Fixed INT overflow bug | |
|
78 | - Events: send pushed commits always in the correct in order. |
@@ -0,0 +1,186 b'' | |||
|
1 | { | |
|
2 | "dirs": { | |
|
3 | "css": { | |
|
4 | "src":"rhodecode/public/css", | |
|
5 | "dest":"rhodecode/public/css" | |
|
6 | }, | |
|
7 | "js": { | |
|
8 | "src": "rhodecode/public/js/src", | |
|
9 | "dest": "rhodecode/public/js" | |
|
10 | } | |
|
11 | }, | |
|
12 | "copy": { | |
|
13 | "main": { | |
|
14 | "expand": true, | |
|
15 | "cwd": "bower_components", | |
|
16 | "src": "webcomponentsjs/webcomponents-lite.js", | |
|
17 | "dest": "<%= dirs.js.dest %>/vendors" | |
|
18 | } | |
|
19 | }, | |
|
20 | "concat": { | |
|
21 | "polymercss": { | |
|
22 | "src": [ | |
|
23 | "<%= dirs.js.src %>/components/root-styles-prefix.html", | |
|
24 | "<%= dirs.css.src %>/style-polymer.css", | |
|
25 | "<%= dirs.js.src %>/components/root-styles-suffix.html" | |
|
26 | ], | |
|
27 | "dest": "<%= dirs.js.dest %>/src/components/root-styles.gen.html", | |
|
28 | "nonull": true | |
|
29 | }, | |
|
30 | "dist": { | |
|
31 | "src": [ | |
|
32 | "<%= dirs.js.src %>/jquery-1.11.1.min.js", | |
|
33 | "<%= dirs.js.src %>/logging.js", | |
|
34 | "<%= dirs.js.src %>/bootstrap.js", | |
|
35 | "<%= dirs.js.src %>/mousetrap.js", | |
|
36 | "<%= dirs.js.src %>/moment.js", | |
|
37 | "<%= dirs.js.src %>/appenlight-client-0.4.1.min.js", | |
|
38 | "<%= dirs.js.src %>/i18n_utils.js", | |
|
39 | "<%= dirs.js.src %>/deform.js", | |
|
40 | "<%= dirs.js.src %>/plugins/jquery.pjax.js", | |
|
41 | "<%= dirs.js.src %>/plugins/jquery.dataTables.js", | |
|
42 | "<%= dirs.js.src %>/plugins/flavoured_checkbox.js", | |
|
43 | "<%= dirs.js.src %>/plugins/jquery.auto-grow-input.js", | |
|
44 | "<%= dirs.js.src %>/plugins/jquery.autocomplete.js", | |
|
45 | "<%= dirs.js.src %>/plugins/jquery.debounce.js", | |
|
46 | "<%= dirs.js.src %>/plugins/jquery.mark.js", | |
|
47 | "<%= dirs.js.src %>/plugins/jquery.timeago.js", | |
|
48 | "<%= dirs.js.src %>/plugins/jquery.timeago-extension.js", | |
|
49 | "<%= dirs.js.src %>/select2/select2.js", | |
|
50 | "<%= dirs.js.src %>/codemirror/codemirror.js", | |
|
51 | "<%= dirs.js.src %>/codemirror/codemirror_loadmode.js", | |
|
52 | "<%= dirs.js.src %>/codemirror/codemirror_hint.js", | |
|
53 | "<%= dirs.js.src %>/codemirror/codemirror_overlay.js", | |
|
54 | "<%= dirs.js.src %>/codemirror/codemirror_placeholder.js", | |
|
55 | "<%= dirs.js.dest %>/mode/meta.js", | |
|
56 | "<%= dirs.js.dest %>/mode/meta_ext.js", | |
|
57 | "<%= dirs.js.dest %>/rhodecode/i18n/select2/translations.js", | |
|
58 | "<%= dirs.js.src %>/rhodecode/utils/array.js", | |
|
59 | "<%= dirs.js.src %>/rhodecode/utils/string.js", | |
|
60 | "<%= dirs.js.src %>/rhodecode/utils/pyroutes.js", | |
|
61 | "<%= dirs.js.src %>/rhodecode/utils/ajax.js", | |
|
62 | "<%= dirs.js.src %>/rhodecode/utils/autocomplete.js", | |
|
63 | "<%= dirs.js.src %>/rhodecode/utils/colorgenerator.js", | |
|
64 | "<%= dirs.js.src %>/rhodecode/utils/ie.js", | |
|
65 | "<%= dirs.js.src %>/rhodecode/utils/os.js", | |
|
66 | "<%= dirs.js.src %>/rhodecode/utils/topics.js", | |
|
67 | "<%= dirs.js.src %>/rhodecode/widgets/multiselect.js", | |
|
68 | "<%= dirs.js.src %>/rhodecode/init.js", | |
|
69 | "<%= dirs.js.src %>/rhodecode/codemirror.js", | |
|
70 | "<%= dirs.js.src %>/rhodecode/comments.js", | |
|
71 | "<%= dirs.js.src %>/rhodecode/constants.js", | |
|
72 | "<%= dirs.js.src %>/rhodecode/files.js", | |
|
73 | "<%= dirs.js.src %>/rhodecode/followers.js", | |
|
74 | "<%= dirs.js.src %>/rhodecode/menus.js", | |
|
75 | "<%= dirs.js.src %>/rhodecode/notifications.js", | |
|
76 | "<%= dirs.js.src %>/rhodecode/permissions.js", | |
|
77 | "<%= dirs.js.src %>/rhodecode/pjax.js", | |
|
78 | "<%= dirs.js.src %>/rhodecode/pullrequests.js", | |
|
79 | "<%= dirs.js.src %>/rhodecode/settings.js", | |
|
80 | "<%= dirs.js.src %>/rhodecode/select2_widgets.js", | |
|
81 | "<%= dirs.js.src %>/rhodecode/tooltips.js", | |
|
82 | "<%= dirs.js.src %>/rhodecode/users.js", | |
|
83 | "<%= dirs.js.src %>/rhodecode/appenlight.js", | |
|
84 | "<%= dirs.js.src %>/rhodecode.js" | |
|
85 | ], | |
|
86 | "dest": "<%= dirs.js.dest %>/scripts.js", | |
|
87 | "nonull": true | |
|
88 | } | |
|
89 | }, | |
|
90 | "crisper": { | |
|
91 | "dist": { | |
|
92 | "options": { | |
|
93 | "cleanup": false, | |
|
94 | "onlySplit": true | |
|
95 | }, | |
|
96 | "src": "<%= dirs.js.dest %>/rhodecode-components.html", | |
|
97 | "dest": "<%= dirs.js.dest %>/rhodecode-components.js" | |
|
98 | } | |
|
99 | }, | |
|
100 | "less": { | |
|
101 | "development": { | |
|
102 | "options": { | |
|
103 | "compress": false, | |
|
104 | "yuicompress": false, | |
|
105 | "optimization": 0 | |
|
106 | }, | |
|
107 | "files": { | |
|
108 | "<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less", | |
|
109 | "<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less" | |
|
110 | } | |
|
111 | }, | |
|
112 | "production": { | |
|
113 | "options": { | |
|
114 | "compress": true, | |
|
115 | "yuicompress": true, | |
|
116 | "optimization": 2 | |
|
117 | }, | |
|
118 | "files": { | |
|
119 | "<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less", | |
|
120 | "<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less" | |
|
121 | } | |
|
122 | }, | |
|
123 | "components": { | |
|
124 | "files": [ | |
|
125 | { | |
|
126 | "cwd": "<%= dirs.js.src %>/components/", | |
|
127 | "dest": "<%= dirs.js.src %>/components/", | |
|
128 | "src": [ | |
|
129 | "**/*.less" | |
|
130 | ], | |
|
131 | "expand": true, | |
|
132 | "ext": ".css" | |
|
133 | } | |
|
134 | ] | |
|
135 | } | |
|
136 | }, | |
|
137 | "watch": { | |
|
138 | "less": { | |
|
139 | "files": [ | |
|
140 | "<%= dirs.css.src %>/**/*.less", | |
|
141 | "<%= dirs.js.src %>/components/**/*.less" | |
|
142 | ], | |
|
143 | "tasks": [ | |
|
144 | "less:development", | |
|
145 | "less:components", | |
|
146 | "concat:polymercss", | |
|
147 | "vulcanize" | |
|
148 | ] | |
|
149 | }, | |
|
150 | "js": { | |
|
151 | "files": [ | |
|
152 | "!<%= dirs.js.src %>/components/root-styles.gen.html", | |
|
153 | "<%= dirs.js.src %>/**/*.js", | |
|
154 | "<%= dirs.js.src %>/components/**/*.html" | |
|
155 | ], | |
|
156 | "tasks": [ | |
|
157 | "less:components", | |
|
158 | "concat:polymercss", | |
|
159 | "vulcanize", | |
|
160 | "crisper", | |
|
161 | "concat:dist" | |
|
162 | ] | |
|
163 | } | |
|
164 | }, | |
|
165 | "jshint": { | |
|
166 | "rhodecode": { | |
|
167 | "src": "<%= dirs.js.src %>/rhodecode/**/*.js", | |
|
168 | "options": { | |
|
169 | "jshintrc": ".jshintrc" | |
|
170 | } | |
|
171 | } | |
|
172 | }, | |
|
173 | "vulcanize": { | |
|
174 | "default": { | |
|
175 | "options": { | |
|
176 | "abspath": "", | |
|
177 | "inlineScripts": true, | |
|
178 | "inlineCss": true, | |
|
179 | "stripComments": true | |
|
180 | }, | |
|
181 | "files": { | |
|
182 | "<%= dirs.js.dest %>/rhodecode-components.html": "<%= dirs.js.src %>/components/shared-components.html" | |
|
183 | } | |
|
184 | } | |
|
185 | } | |
|
186 | } |
@@ -0,0 +1,67 b'' | |||
|
1 | # Backported buildBowerComponents so that we can also use it with the version | |
|
2 | # 16.03 which is the current stable at the time of this writing. | |
|
3 | # | |
|
4 | # This file can be removed once building with 16.03 is not needed anymore. | |
|
5 | ||
|
6 | { pkgs }: | |
|
7 | ||
|
8 | { buildInputs ? [], generated, ... } @ attrs: | |
|
9 | ||
|
10 | let | |
|
11 | bower2nix-src = pkgs.fetchzip { | |
|
12 | url = "https://github.com/rvl/bower2nix/archive/v3.0.1.tar.gz"; | |
|
13 | sha256 = "1zbvz96k2j6g0r4lvm5cgh41a73k9dgayk7x63cmg538dzznxvyb"; | |
|
14 | }; | |
|
15 | ||
|
16 | bower2nix = import "${bower2nix-src}/default.nix" { inherit pkgs; }; | |
|
17 | ||
|
18 | fetchbower = import ./backport-16.03-fetchbower.nix { | |
|
19 | inherit (pkgs) stdenv lib; | |
|
20 | inherit bower2nix; | |
|
21 | }; | |
|
22 | ||
|
23 | # Fetches the bower packages. `generated` should be the result of a | |
|
24 | # `bower2nix` command. | |
|
25 | bowerPackages = import generated { | |
|
26 | inherit (pkgs) buildEnv; | |
|
27 | inherit fetchbower; | |
|
28 | }; | |
|
29 | ||
|
30 | in pkgs.stdenv.mkDerivation ( | |
|
31 | attrs | |
|
32 | // | |
|
33 | { | |
|
34 | name = "bower_components-" + attrs.name; | |
|
35 | ||
|
36 | inherit bowerPackages; | |
|
37 | ||
|
38 | builder = builtins.toFile "builder.sh" '' | |
|
39 | source $stdenv/setup | |
|
40 | ||
|
41 | # The project's bower.json is required | |
|
42 | cp $src/bower.json . | |
|
43 | ||
|
44 | # Dereference symlinks -- bower doesn't like them | |
|
45 | cp --recursive --reflink=auto \ | |
|
46 | --dereference --no-preserve=mode \ | |
|
47 | $bowerPackages bc | |
|
48 | ||
|
49 | # Bower install in offline mode -- links together the fetched | |
|
50 | # bower packages. | |
|
51 | HOME=$PWD bower \ | |
|
52 | --config.storage.packages=bc/packages \ | |
|
53 | --config.storage.registry=bc/registry \ | |
|
54 | --offline install | |
|
55 | ||
|
56 | # Sets up a single bower_components directory within | |
|
57 | # the output derivation. | |
|
58 | mkdir -p $out | |
|
59 | mv bower_components $out | |
|
60 | ''; | |
|
61 | ||
|
62 | buildInputs = buildInputs ++ [ | |
|
63 | pkgs.git | |
|
64 | pkgs.nodePackages.bower | |
|
65 | ]; | |
|
66 | } | |
|
67 | ) |
@@ -0,0 +1,26 b'' | |||
|
1 | { stdenv, lib, bower2nix }: | |
|
2 | let | |
|
3 | bowerVersion = version: | |
|
4 | let | |
|
5 | components = lib.splitString "#" version; | |
|
6 | hash = lib.last components; | |
|
7 | ver = if builtins.length components == 1 then version else hash; | |
|
8 | in ver; | |
|
9 | ||
|
10 | fetchbower = name: version: target: outputHash: stdenv.mkDerivation { | |
|
11 | name = "${name}-${bowerVersion version}"; | |
|
12 | buildCommand = '' | |
|
13 | fetch-bower --quiet --out=$PWD/out "${name}" "${target}" "${version}" | |
|
14 | # In some cases, the result of fetchBower is different depending | |
|
15 | # on the output directory (e.g. if the bower package contains | |
|
16 | # symlinks). So use a local output directory before copying to | |
|
17 | # $out. | |
|
18 | cp -R out $out | |
|
19 | ''; | |
|
20 | outputHashMode = "recursive"; | |
|
21 | outputHashAlgo = "sha256"; | |
|
22 | inherit outputHash; | |
|
23 | buildInputs = [ bower2nix ]; | |
|
24 | }; | |
|
25 | ||
|
26 | in fetchbower |
@@ -0,0 +1,31 b'' | |||
|
1 | { fetchbower, buildEnv }: | |
|
2 | buildEnv { name = "bower-env"; ignoreCollisions = true; paths = [ | |
|
3 | (fetchbower "webcomponentsjs" "0.7.22" "^0.7.22" "0ggh3k8ssafd056ib1m5bvzi7cpz3ry7gr5176d79na1w0c3i7dz") | |
|
4 | (fetchbower "polymer" "Polymer/polymer#1.6.1" "Polymer/polymer#^1.6.1" "09mm0jgk457gvwqlc155swch7gjr6fs3g7spnvhi6vh5b6518540") | |
|
5 | (fetchbower "paper-button" "PolymerElements/paper-button#1.0.13" "PolymerElements/paper-button#^1.0.13" "0i3y153nqk06pn0gk282vyybnl3g1w3w41d5i9z659cgn27g3fvm") | |
|
6 | (fetchbower "paper-spinner" "PolymerElements/paper-spinner#1.2.0" "PolymerElements/paper-spinner#^1.2.0" "1av1m6y81jw3hjhz1yqy3rwcgxarjzl58ldfn4q6sn51pgzngfqb") | |
|
7 | (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#1.1.2" "PolymerElements/paper-tooltip#^1.1.2" "1j64nprcyk2d2bbl3qwjyr0lbjngm4wclpyfwgai1c4y6g6bigd2") | |
|
8 | (fetchbower "paper-toast" "PolymerElements/paper-toast#1.3.0" "PolymerElements/paper-toast#^1.3.0" "0x9rqxsks5455s8pk4aikpp99ijdn6kxr9gvhwh99nbcqdzcxq1m") | |
|
9 | (fetchbower "paper-toggle-button" "PolymerElements/paper-toggle-button#1.2.0" "PolymerElements/paper-toggle-button#^1.2.0" "0mphcng3ngspbpg4jjn0mb91nvr4xc1phq3qswib15h6sfww1b2w") | |
|
10 | (fetchbower "iron-ajax" "PolymerElements/iron-ajax#1.4.3" "PolymerElements/iron-ajax#^1.4.3" "0m3dx27arwmlcp00b7n516sc5a51f40p9vapr1nvd57l3i3z0pzm") | |
|
11 | (fetchbower "iron-flex-layout" "PolymerElements/iron-flex-layout#1.3.1" "PolymerElements/iron-flex-layout#^1.0.0" "0nswv3ih3bhflgcd2wjfmddqswzgqxb2xbq65jk9w3rkj26hplbl") | |
|
12 | (fetchbower "paper-behaviors" "PolymerElements/paper-behaviors#1.0.12" "PolymerElements/paper-behaviors#^1.0.0" "012bqk97awgz55cn7rm9g7cckrdhkqhls3zvp8l6nd4rdwcrdzq8") | |
|
13 | (fetchbower "paper-material" "PolymerElements/paper-material#1.0.6" "PolymerElements/paper-material#^1.0.0" "0rljmknfdbm5aabvx9pk77754zckj3l127c3mvnmwkpkkr353xnh") | |
|
14 | (fetchbower "paper-styles" "PolymerElements/paper-styles#1.1.4" "PolymerElements/paper-styles#^1.0.0" "0j8vg74xrcxlni8i93dsab3y80f34kk30lv4yblqpkp9c3nrilf7") | |
|
15 | (fetchbower "neon-animation" "PolymerElements/neon-animation#1.2.4" "PolymerElements/neon-animation#^1.0.0" "16mz9i2n5w0k5j8d6gha23cnbdgm5syz3fawyh89gdbq97bi2q5j") | |
|
16 | (fetchbower "iron-a11y-announcer" "PolymerElements/iron-a11y-announcer#1.0.5" "PolymerElements/iron-a11y-announcer#^1.0.0" "0n7c7j1pwk3835s7s2jd9125wdcsqf216yi5gj07wn5s8h8p7m9d") | |
|
17 | (fetchbower "iron-overlay-behavior" "PolymerElements/iron-overlay-behavior#1.8.6" "PolymerElements/iron-overlay-behavior#^1.0.9" "14brn9gz6qqskarg3fxk91xs7vg02vgcsz9a9743kidxr0l0413m") | |
|
18 | (fetchbower "iron-fit-behavior" "PolymerElements/iron-fit-behavior#1.2.5" "PolymerElements/iron-fit-behavior#^1.1.0" "1msnlh8lp1xg6v4h6dkjwj9kzac5q5q208ayla3x9hi483ki6rlf") | |
|
19 | (fetchbower "iron-checked-element-behavior" "PolymerElements/iron-checked-element-behavior#1.0.5" "PolymerElements/iron-checked-element-behavior#^1.0.0" "0l0yy4ah454s8bzfv076s8by7h67zy9ni6xb932qwyhx8br6c1m7") | |
|
20 | (fetchbower "promise-polyfill" "polymerlabs/promise-polyfill#1.0.1" "polymerlabs/promise-polyfill#^1.0.0" "045bj2caav3famr5hhxgs1dx7n08r4s46mlzwb313vdy17is38xb") | |
|
21 | (fetchbower "iron-behaviors" "PolymerElements/iron-behaviors#1.0.17" "PolymerElements/iron-behaviors#^1.0.0" "021qvkmbk32jrrmmphpmwgby4bzi5jyf47rh1bxmq2ip07ly4bpr") | |
|
22 | (fetchbower "paper-ripple" "PolymerElements/paper-ripple#1.0.8" "PolymerElements/paper-ripple#^1.0.0" "0r9sq8ik7wwrw0qb82c3rw0c030ljwd3s466c9y4qbcrsbvfjnns") | |
|
23 | (fetchbower "font-roboto" "PolymerElements/font-roboto#1.0.1" "PolymerElements/font-roboto#^1.0.1" "02jz43r0wkyr3yp7rq2rc08l5cwnsgca9fr54sr4rhsnl7cjpxrj") | |
|
24 | (fetchbower "iron-meta" "PolymerElements/iron-meta#1.1.2" "PolymerElements/iron-meta#^1.0.0" "1wl4dx8fnsknw9z9xi8bpc4cy9x70c11x4zxwxnj73hf3smifppl") | |
|
25 | (fetchbower "iron-resizable-behavior" "PolymerElements/iron-resizable-behavior#1.0.5" "PolymerElements/iron-resizable-behavior#^1.0.0" "1fd5zmbr2hax42vmcasncvk7lzi38fmb1kyii26nn8pnnjak7zkn") | |
|
26 | (fetchbower "iron-selector" "PolymerElements/iron-selector#1.5.2" "PolymerElements/iron-selector#^1.0.0" "1ajv46llqzvahm5g6g75w7nfyjcslp53ji0wm96l2k94j87spv3r") | |
|
27 | (fetchbower "web-animations-js" "web-animations/web-animations-js#2.2.2" "web-animations/web-animations-js#^2.2.0" "1izfvm3l67vwys0bqbhidi9rqziw2f8wv289386sc6jsxzgkzhga") | |
|
28 | (fetchbower "iron-a11y-keys-behavior" "PolymerElements/iron-a11y-keys-behavior#1.1.7" "PolymerElements/iron-a11y-keys-behavior#^1.0.0" "070z46dbbz242002gmqrgy28x0y1fcqp9hnvbi05r3zphiqfx3l7") | |
|
29 | (fetchbower "iron-validatable-behavior" "PolymerElements/iron-validatable-behavior#1.1.1" "PolymerElements/iron-validatable-behavior#^1.0.0" "1yhxlvywhw2klbbgm3f3cmanxfxggagph4ii635zv0c13707wslv") | |
|
30 | (fetchbower "iron-form-element-behavior" "PolymerElements/iron-form-element-behavior#1.0.6" "PolymerElements/iron-form-element-behavior#^1.0.0" "0rdhxivgkdhhz2yadgdbjfc70l555p3y83vjh8rfj5hr0asyn6q1") | |
|
31 | ]; } |
@@ -0,0 +1,15 b'' | |||
|
1 | # This file has been generated by node2nix 1.0.0. Do not edit! | |
|
2 | ||
|
3 | {pkgs ? import <nixpkgs> { | |
|
4 | inherit system; | |
|
5 | }, system ? builtins.currentSystem}: | |
|
6 | ||
|
7 | let | |
|
8 | nodeEnv = import ./node-env.nix { | |
|
9 | inherit (pkgs) stdenv python utillinux runCommand writeTextFile nodejs; | |
|
10 | }; | |
|
11 | in | |
|
12 | import ./node-packages.nix { | |
|
13 | inherit (pkgs) fetchurl fetchgit; | |
|
14 | inherit nodeEnv; | |
|
15 | } No newline at end of file |
@@ -0,0 +1,292 b'' | |||
|
1 | # This file originates from node2nix | |
|
2 | ||
|
3 | {stdenv, python, nodejs, utillinux, runCommand, writeTextFile}: | |
|
4 | ||
|
5 | let | |
|
6 | # Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise | |
|
7 | tarWrapper = runCommand "tarWrapper" {} '' | |
|
8 | mkdir -p $out/bin | |
|
9 | ||
|
10 | cat > $out/bin/tar <<EOF | |
|
11 | #! ${stdenv.shell} -e | |
|
12 | $(type -p tar) "\$@" --warning=no-unknown-keyword | |
|
13 | EOF | |
|
14 | ||
|
15 | chmod +x $out/bin/tar | |
|
16 | ''; | |
|
17 | ||
|
18 | # Function that generates a TGZ file from a NPM project | |
|
19 | buildNodeSourceDist = | |
|
20 | { name, version, src, ... }: | |
|
21 | ||
|
22 | stdenv.mkDerivation { | |
|
23 | name = "node-tarball-${name}-${version}"; | |
|
24 | inherit src; | |
|
25 | buildInputs = [ nodejs ]; | |
|
26 | buildPhase = '' | |
|
27 | export HOME=$TMPDIR | |
|
28 | tgzFile=$(npm pack) | |
|
29 | ''; | |
|
30 | installPhase = '' | |
|
31 | mkdir -p $out/tarballs | |
|
32 | mv $tgzFile $out/tarballs | |
|
33 | mkdir -p $out/nix-support | |
|
34 | echo "file source-dist $out/tarballs/$tgzFile" >> $out/nix-support/hydra-build-products | |
|
35 | ''; | |
|
36 | }; | |
|
37 | ||
|
38 | includeDependencies = {dependencies}: | |
|
39 | stdenv.lib.optionalString (dependencies != []) | |
|
40 | (stdenv.lib.concatMapStrings (dependency: | |
|
41 | '' | |
|
42 | # Bundle the dependencies of the package | |
|
43 | mkdir -p node_modules | |
|
44 | cd node_modules | |
|
45 | ||
|
46 | # Only include dependencies if they don't exist. They may also be bundled in the package. | |
|
47 | if [ ! -e "${dependency.name}" ] | |
|
48 | then | |
|
49 | ${composePackage dependency} | |
|
50 | fi | |
|
51 | ||
|
52 | cd .. | |
|
53 | '' | |
|
54 | ) dependencies); | |
|
55 | ||
|
56 | # Recursively composes the dependencies of a package | |
|
57 | composePackage = { name, packageName, src, dependencies ? [], ... }@args: | |
|
58 | let | |
|
59 | fixImpureDependencies = writeTextFile { | |
|
60 | name = "fixDependencies.js"; | |
|
61 | text = '' | |
|
62 | var fs = require('fs'); | |
|
63 | var url = require('url'); | |
|
64 | ||
|
65 | /* | |
|
66 | * Replaces an impure version specification by * | |
|
67 | */ | |
|
68 | function replaceImpureVersionSpec(versionSpec) { | |
|
69 | var parsedUrl = url.parse(versionSpec); | |
|
70 | ||
|
71 | if(versionSpec == "latest" || versionSpec == "unstable" || | |
|
72 | versionSpec.substr(0, 2) == ".." || dependency.substr(0, 2) == "./" || dependency.substr(0, 2) == "~/" || dependency.substr(0, 1) == '/') | |
|
73 | return '*'; | |
|
74 | else if(parsedUrl.protocol == "git:" || parsedUrl.protocol == "git+ssh:" || parsedUrl.protocol == "git+http:" || parsedUrl.protocol == "git+https:" || | |
|
75 | parsedUrl.protocol == "http:" || parsedUrl.protocol == "https:") | |
|
76 | return '*'; | |
|
77 | else | |
|
78 | return versionSpec; | |
|
79 | } | |
|
80 | ||
|
81 | var packageObj = JSON.parse(fs.readFileSync('./package.json')); | |
|
82 | ||
|
83 | /* Replace dependencies */ | |
|
84 | if(packageObj.dependencies !== undefined) { | |
|
85 | for(var dependency in packageObj.dependencies) { | |
|
86 | var versionSpec = packageObj.dependencies[dependency]; | |
|
87 | packageObj.dependencies[dependency] = replaceImpureVersionSpec(versionSpec); | |
|
88 | } | |
|
89 | } | |
|
90 | ||
|
91 | /* Replace development dependencies */ | |
|
92 | if(packageObj.devDependencies !== undefined) { | |
|
93 | for(var dependency in packageObj.devDependencies) { | |
|
94 | var versionSpec = packageObj.devDependencies[dependency]; | |
|
95 | packageObj.devDependencies[dependency] = replaceImpureVersionSpec(versionSpec); | |
|
96 | } | |
|
97 | } | |
|
98 | ||
|
99 | /* Replace optional dependencies */ | |
|
100 | if(packageObj.optionalDependencies !== undefined) { | |
|
101 | for(var dependency in packageObj.optionalDependencies) { | |
|
102 | var versionSpec = packageObj.optionalDependencies[dependency]; | |
|
103 | packageObj.optionalDependencies[dependency] = replaceImpureVersionSpec(versionSpec); | |
|
104 | } | |
|
105 | } | |
|
106 | ||
|
107 | /* Write the fixed JSON file */ | |
|
108 | fs.writeFileSync("package.json", JSON.stringify(packageObj)); | |
|
109 | ''; | |
|
110 | }; | |
|
111 | in | |
|
112 | '' | |
|
113 | DIR=$(pwd) | |
|
114 | cd $TMPDIR | |
|
115 | ||
|
116 | unpackFile ${src} | |
|
117 | ||
|
118 | # Make the base dir in which the target dependency resides first | |
|
119 | mkdir -p "$(dirname "$DIR/${packageName}")" | |
|
120 | ||
|
121 | if [ -f "${src}" ] | |
|
122 | then | |
|
123 | # Figure out what directory has been unpacked | |
|
124 | packageDir=$(find . -type d -maxdepth 1 | tail -1) | |
|
125 | ||
|
126 | # Restore write permissions to make building work | |
|
127 | chmod -R u+w "$packageDir" | |
|
128 | ||
|
129 | # Move the extracted tarball into the output folder | |
|
130 | mv "$packageDir" "$DIR/${packageName}" | |
|
131 | elif [ -d "${src}" ] | |
|
132 | then | |
|
133 | # Restore write permissions to make building work | |
|
134 | chmod -R u+w $strippedName | |
|
135 | ||
|
136 | # Move the extracted directory into the output folder | |
|
137 | mv $strippedName "$DIR/${packageName}" | |
|
138 | fi | |
|
139 | ||
|
140 | # Unset the stripped name to not confuse the next unpack step | |
|
141 | unset strippedName | |
|
142 | ||
|
143 | # Some version specifiers (latest, unstable, URLs, file paths) force NPM to make remote connections or consult paths outside the Nix store. | |
|
144 | # The following JavaScript replaces these by * to prevent that | |
|
145 | cd "$DIR/${packageName}" | |
|
146 | node ${fixImpureDependencies} | |
|
147 | ||
|
148 | # Include the dependencies of the package | |
|
149 | ${includeDependencies { inherit dependencies; }} | |
|
150 | cd .. | |
|
151 | ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} | |
|
152 | ''; | |
|
153 | ||
|
154 | # Extract the Node.js source code which is used to compile packages with | |
|
155 | # native bindings | |
|
156 | nodeSources = runCommand "node-sources" {} '' | |
|
157 | tar --no-same-owner --no-same-permissions -xf ${nodejs.src} | |
|
158 | mv node-* $out | |
|
159 | ''; | |
|
160 | ||
|
161 | # Builds and composes an NPM package including all its dependencies | |
|
162 | buildNodePackage = { name, packageName, version, dependencies ? [], production ? true, npmFlags ? "", dontNpmInstall ? false, preRebuild ? "", ... }@args: | |
|
163 | ||
|
164 | stdenv.lib.makeOverridable stdenv.mkDerivation (builtins.removeAttrs args [ "dependencies" ] // { | |
|
165 | name = "node-${name}-${version}"; | |
|
166 | buildInputs = [ tarWrapper python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ args.buildInputs or []; | |
|
167 | dontStrip = args.dontStrip or true; # Striping may fail a build for some package deployments | |
|
168 | ||
|
169 | inherit dontNpmInstall preRebuild; | |
|
170 | ||
|
171 | unpackPhase = args.unpackPhase or "true"; | |
|
172 | ||
|
173 | buildPhase = args.buildPhase or "true"; | |
|
174 | ||
|
175 | compositionScript = composePackage args; | |
|
176 | passAsFile = [ "compositionScript" ]; | |
|
177 | ||
|
178 | installPhase = args.installPhase or '' | |
|
179 | # Create and enter a root node_modules/ folder | |
|
180 | mkdir -p $out/lib/node_modules | |
|
181 | cd $out/lib/node_modules | |
|
182 | ||
|
183 | # Compose the package and all its dependencies | |
|
184 | source $compositionScriptPath | |
|
185 | ||
|
186 | # Patch the shebangs of the bundled modules to prevent them from | |
|
187 | # calling executables outside the Nix store as much as possible | |
|
188 | patchShebangs . | |
|
189 | ||
|
190 | # Deploy the Node.js package by running npm install. Since the | |
|
191 | # dependencies have been provided already by ourselves, it should not | |
|
192 | # attempt to install them again, which is good, because we want to make | |
|
193 | # it Nix's responsibility. If it needs to install any dependencies | |
|
194 | # anyway (e.g. because the dependency parameters are | |
|
195 | # incomplete/incorrect), it fails. | |
|
196 | # | |
|
197 | # The other responsibilities of NPM are kept -- version checks, build | |
|
198 | # steps, postprocessing etc. | |
|
199 | ||
|
200 | export HOME=$TMPDIR | |
|
201 | cd "${packageName}" | |
|
202 | runHook preRebuild | |
|
203 | npm --registry http://www.example.com --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild | |
|
204 | ||
|
205 | if [ "$dontNpmInstall" != "1" ] | |
|
206 | then | |
|
207 | npm --registry http://www.example.com --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install | |
|
208 | fi | |
|
209 | ||
|
210 | # Create symlink to the deployed executable folder, if applicable | |
|
211 | if [ -d "$out/lib/node_modules/.bin" ] | |
|
212 | then | |
|
213 | ln -s $out/lib/node_modules/.bin $out/bin | |
|
214 | fi | |
|
215 | ||
|
216 | # Create symlinks to the deployed manual page folders, if applicable | |
|
217 | if [ -d "$out/lib/node_modules/${packageName}/man" ] | |
|
218 | then | |
|
219 | mkdir -p $out/share | |
|
220 | for dir in "$out/lib/node_modules/${packageName}/man/"* | |
|
221 | do | |
|
222 | mkdir -p $out/share/man/$(basename "$dir") | |
|
223 | for page in "$dir"/* | |
|
224 | do | |
|
225 | ln -s $page $out/share/man/$(basename "$dir") | |
|
226 | done | |
|
227 | done | |
|
228 | fi | |
|
229 | ''; | |
|
230 | }); | |
|
231 | ||
|
232 | # Builds a development shell | |
|
233 | buildNodeShell = { name, packageName, version, src, dependencies ? [], production ? true, npmFlags ? "", dontNpmInstall ? false, ... }@args: | |
|
234 | let | |
|
235 | nodeDependencies = stdenv.mkDerivation { | |
|
236 | name = "node-dependencies-${name}-${version}"; | |
|
237 | ||
|
238 | buildInputs = [ tarWrapper python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ args.buildInputs or []; | |
|
239 | ||
|
240 | includeScript = includeDependencies { inherit dependencies; }; | |
|
241 | passAsFile = [ "includeScript" ]; | |
|
242 | ||
|
243 | buildCommand = '' | |
|
244 | mkdir -p $out/lib | |
|
245 | cd $out/lib | |
|
246 | source $includeScriptPath | |
|
247 | ||
|
248 | # Create fake package.json to make the npm commands work properly | |
|
249 | cat > package.json <<EOF | |
|
250 | { | |
|
251 | "name": "${packageName}", | |
|
252 | "version": "${version}" | |
|
253 | } | |
|
254 | EOF | |
|
255 | ||
|
256 | # Patch the shebangs of the bundled modules to prevent them from | |
|
257 | # calling executables outside the Nix store as much as possible | |
|
258 | patchShebangs . | |
|
259 | ||
|
260 | export HOME=$TMPDIR | |
|
261 | npm --registry http://www.example.com --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild | |
|
262 | ||
|
263 | ${stdenv.lib.optionalString (!dontNpmInstall) '' | |
|
264 | npm --registry http://www.example.com --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install | |
|
265 | ''} | |
|
266 | ||
|
267 | ln -s $out/lib/node_modules/.bin $out/bin | |
|
268 | ''; | |
|
269 | }; | |
|
270 | in | |
|
271 | stdenv.lib.makeOverridable stdenv.mkDerivation { | |
|
272 | name = "node-shell-${name}-${version}"; | |
|
273 | ||
|
274 | buildInputs = [ python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ args.buildInputs or []; | |
|
275 | buildCommand = '' | |
|
276 | mkdir -p $out/bin | |
|
277 | cat > $out/bin/shell <<EOF | |
|
278 | #! ${stdenv.shell} -e | |
|
279 | $shellHook | |
|
280 | exec ${stdenv.shell} | |
|
281 | EOF | |
|
282 | chmod +x $out/bin/shell | |
|
283 | ''; | |
|
284 | ||
|
285 | # Provide the dependencies in a development shell through the NODE_PATH environment variable | |
|
286 | inherit nodeDependencies; | |
|
287 | shellHook = stdenv.lib.optionalString (dependencies != []) '' | |
|
288 | export NODE_PATH=$nodeDependencies/lib/node_modules | |
|
289 | ''; | |
|
290 | }; | |
|
291 | in | |
|
292 | { inherit buildNodeSourceDist buildNodePackage buildNodeShell; } |
@@ -0,0 +1,33 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2010-2016 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | ||
|
21 | """ | |
|
22 | Base module for form rendering / validation - currently just a wrapper for | |
|
23 | deform - later can be replaced with something custom. | |
|
24 | """ | |
|
25 | ||
|
26 | from rhodecode.translation import _ | |
|
27 | from deform import Button, Form, widget, ValidationFailure | |
|
28 | ||
|
29 | ||
|
30 | class buttons: | |
|
31 | save = Button(name='Save', type='submit') | |
|
32 | reset = Button(name=_('Reset'), type='reset') | |
|
33 | delete = Button(name=_('Delete'), type='submit') |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
@@ -1,5 +1,5 b'' | |||
|
1 | 1 | [bumpversion] |
|
2 |
current_version = 4. |
|
|
2 | current_version = 4.4.0 | |
|
3 | 3 | message = release: Bump version {current_version} to {new_version} |
|
4 | 4 | |
|
5 | 5 | [bumpversion:file:rhodecode/VERSION] |
@@ -8,6 +8,7 b' syntax: glob' | |||
|
8 | 8 | *.swp |
|
9 | 9 | *.tox |
|
10 | 10 | *.DS_Store* |
|
11 | rhodecode/public/js/src/components/**/*.css | |
|
11 | 12 | |
|
12 | 13 | syntax: regexp |
|
13 | 14 | |
@@ -23,6 +24,7 b' syntax: regexp' | |||
|
23 | 24 | ^_dev |
|
24 | 25 | ^._dev |
|
25 | 26 | ^build/ |
|
27 | ^bower_components/ | |
|
26 | 28 | ^coverage\.xml$ |
|
27 | 29 | ^data$ |
|
28 | 30 | ^\.eggs/ |
@@ -38,7 +40,11 b' syntax: regexp' | |||
|
38 | 40 | ^rcextensions/ |
|
39 | 41 | ^result$ |
|
40 | 42 | ^rhodecode/public/css/style.css$ |
|
43 | ^rhodecode/public/css/style-polymer.css$ | |
|
44 | ^rhodecode/public/js/rhodecode-components.html$ | |
|
41 | 45 | ^rhodecode/public/js/scripts.js$ |
|
46 | ^rhodecode/public/js/src/components/root-styles.gen.html$ | |
|
47 | ^rhodecode/public/js/vendors/webcomponentsjs/ | |
|
42 | 48 | ^rhodecode\.db$ |
|
43 | 49 | ^rhodecode\.log$ |
|
44 | 50 | ^rhodecode_dev\.log$ |
@@ -4,26 +4,21 b' done = false' | |||
|
4 | 4 | [task:bump_version] |
|
5 | 5 | done = true |
|
6 | 6 | |
|
7 | [task:rc_tools_pinned] | |
|
8 | done = true | |
|
9 | ||
|
10 | 7 | [task:fixes_on_stable] |
|
11 | done = true | |
|
12 | 8 | |
|
13 | 9 | [task:pip2nix_generated] |
|
14 | done = true | |
|
15 | 10 | |
|
16 | 11 | [task:changelog_updated] |
|
17 | done = true | |
|
18 | 12 | |
|
19 | 13 | [task:generate_api_docs] |
|
20 | done = true | |
|
14 | ||
|
15 | [task:updated_translation] | |
|
21 | 16 | |
|
22 | 17 | [release] |
|
23 |
state = |
|
|
24 |
version = 4. |
|
|
18 | state = in_progress | |
|
19 | version = 4.4.0 | |
|
25 | 20 | |
|
26 | [task:updated_translation] | |
|
21 | [task:rc_tools_pinned] | |
|
27 | 22 | |
|
28 | 23 | [task:generate_js_routes] |
|
29 | 24 |
@@ -1,144 +1,15 b'' | |||
|
1 | module.exports = function(grunt) { | |
|
2 | grunt.initConfig({ | |
|
3 | ||
|
4 | dirs: { | |
|
5 | css: "rhodecode/public/css", | |
|
6 | js: { | |
|
7 | "src": "rhodecode/public/js/src", | |
|
8 | "dest": "rhodecode/public/js" | |
|
9 | } | |
|
10 | }, | |
|
11 | ||
|
12 | concat: { | |
|
13 | dist: { | |
|
14 | src: [ | |
|
15 | // Base libraries | |
|
16 | '<%= dirs.js.src %>/jquery-1.11.1.min.js', | |
|
17 | '<%= dirs.js.src %>/logging.js', | |
|
18 | '<%= dirs.js.src %>/bootstrap.js', | |
|
19 | '<%= dirs.js.src %>/mousetrap.js', | |
|
20 | '<%= dirs.js.src %>/moment.js', | |
|
21 | '<%= dirs.js.src %>/appenlight-client-0.4.1.min.js', | |
|
22 | '<%= dirs.js.src %>/i18n_utils.js', | |
|
23 | '<%= dirs.js.src %>/deform.js', | |
|
24 | ||
|
25 | // Plugins | |
|
26 | '<%= dirs.js.src %>/plugins/jquery.pjax.js', | |
|
27 | '<%= dirs.js.src %>/plugins/jquery.dataTables.js', | |
|
28 | '<%= dirs.js.src %>/plugins/flavoured_checkbox.js', | |
|
29 | '<%= dirs.js.src %>/plugins/jquery.auto-grow-input.js', | |
|
30 | '<%= dirs.js.src %>/plugins/jquery.autocomplete.js', | |
|
31 | '<%= dirs.js.src %>/plugins/jquery.debounce.js', | |
|
32 | '<%= dirs.js.src %>/plugins/jquery.mark.js', | |
|
33 | '<%= dirs.js.src %>/plugins/jquery.timeago.js', | |
|
34 | '<%= dirs.js.src %>/plugins/jquery.timeago-extension.js', | |
|
35 | '<%= dirs.js.src %>/plugins/toastr.js', | |
|
36 | ||
|
37 | // Select2 | |
|
38 | '<%= dirs.js.src %>/select2/select2.js', | |
|
39 | ||
|
40 | // Code-mirror | |
|
41 | '<%= dirs.js.src %>/codemirror/codemirror.js', | |
|
42 | '<%= dirs.js.src %>/codemirror/codemirror_loadmode.js', | |
|
43 | '<%= dirs.js.src %>/codemirror/codemirror_hint.js', | |
|
44 | '<%= dirs.js.src %>/codemirror/codemirror_overlay.js', | |
|
45 | '<%= dirs.js.src %>/codemirror/codemirror_placeholder.js', | |
|
46 | // TODO: mikhail: this is an exception. Since the code mirror modes | |
|
47 | // are loaded "on the fly", we need to keep them in a public folder | |
|
48 | '<%= dirs.js.dest %>/mode/meta.js', | |
|
49 | '<%= dirs.js.dest %>/mode/meta_ext.js', | |
|
50 | '<%= dirs.js.dest %>/rhodecode/i18n/select2/translations.js', | |
|
51 | ||
|
52 | // Rhodecode utilities | |
|
53 | '<%= dirs.js.src %>/rhodecode/utils/array.js', | |
|
54 | '<%= dirs.js.src %>/rhodecode/utils/string.js', | |
|
55 | '<%= dirs.js.src %>/rhodecode/utils/pyroutes.js', | |
|
56 | '<%= dirs.js.src %>/rhodecode/utils/ajax.js', | |
|
57 | '<%= dirs.js.src %>/rhodecode/utils/autocomplete.js', | |
|
58 | '<%= dirs.js.src %>/rhodecode/utils/colorgenerator.js', | |
|
59 | '<%= dirs.js.src %>/rhodecode/utils/ie.js', | |
|
60 | '<%= dirs.js.src %>/rhodecode/utils/os.js', | |
|
61 | '<%= dirs.js.src %>/rhodecode/utils/topics.js', | |
|
62 | ||
|
63 | // Rhodecode widgets | |
|
64 | '<%= dirs.js.src %>/rhodecode/widgets/multiselect.js', | |
|
1 | var gruntConfig = require('./grunt_config.json'); | |
|
65 | 2 | |
|
66 | // Rhodecode components | |
|
67 | '<%= dirs.js.src %>/rhodecode/init.js', | |
|
68 | '<%= dirs.js.src %>/rhodecode/connection_controller.js', | |
|
69 | '<%= dirs.js.src %>/rhodecode/codemirror.js', | |
|
70 | '<%= dirs.js.src %>/rhodecode/comments.js', | |
|
71 | '<%= dirs.js.src %>/rhodecode/constants.js', | |
|
72 | '<%= dirs.js.src %>/rhodecode/files.js', | |
|
73 | '<%= dirs.js.src %>/rhodecode/followers.js', | |
|
74 | '<%= dirs.js.src %>/rhodecode/menus.js', | |
|
75 | '<%= dirs.js.src %>/rhodecode/notifications.js', | |
|
76 | '<%= dirs.js.src %>/rhodecode/permissions.js', | |
|
77 | '<%= dirs.js.src %>/rhodecode/pjax.js', | |
|
78 | '<%= dirs.js.src %>/rhodecode/pullrequests.js', | |
|
79 | '<%= dirs.js.src %>/rhodecode/settings.js', | |
|
80 | '<%= dirs.js.src %>/rhodecode/select2_widgets.js', | |
|
81 | '<%= dirs.js.src %>/rhodecode/tooltips.js', | |
|
82 | '<%= dirs.js.src %>/rhodecode/users.js', | |
|
83 | '<%= dirs.js.src %>/rhodecode/utils/notifications.js', | |
|
84 | '<%= dirs.js.src %>/rhodecode/appenlight.js', | |
|
85 | ||
|
86 | // Rhodecode main module | |
|
87 | '<%= dirs.js.src %>/rhodecode.js' | |
|
88 | ], | |
|
89 | dest: '<%= dirs.js.dest %>/scripts.js', | |
|
90 | nonull: true | |
|
91 | } | |
|
92 | }, | |
|
93 | ||
|
94 | less: { | |
|
95 | development: { | |
|
96 | options: { | |
|
97 | compress: false, | |
|
98 | yuicompress: false, | |
|
99 | optimization: 0 | |
|
100 | }, | |
|
101 | files: { | |
|
102 | "<%= dirs.css %>/style.css": "<%= dirs.css %>/main.less" | |
|
103 | } | |
|
104 | }, | |
|
105 | production: { | |
|
106 | options: { | |
|
107 | compress: true, | |
|
108 | yuicompress: true, | |
|
109 | optimization: 2 | |
|
110 | }, | |
|
111 | files: { | |
|
112 | "<%= dirs.css %>/style.css": "<%= dirs.css %>/main.less" | |
|
113 | } | |
|
114 | } | |
|
115 | }, | |
|
116 | ||
|
117 | watch: { | |
|
118 | less: { | |
|
119 | files: ["<%= dirs.css %>/*.less"], | |
|
120 | tasks: ["less:production"] | |
|
121 | }, | |
|
122 | js: { | |
|
123 | files: ["<%= dirs.js.src %>/**/*.js"], | |
|
124 | tasks: ["concat:dist"] | |
|
125 | } | |
|
126 | }, | |
|
127 | ||
|
128 | jshint: { | |
|
129 | rhodecode: { | |
|
130 | src: '<%= dirs.js.src %>/rhodecode/**/*.js', | |
|
131 | options: { | |
|
132 | jshintrc: '.jshintrc' | |
|
133 | } | |
|
134 | } | |
|
135 | } | |
|
136 | }); | |
|
3 | module.exports = function(grunt) { | |
|
4 | grunt.initConfig(gruntConfig); | |
|
137 | 5 | |
|
138 | 6 | grunt.loadNpmTasks('grunt-contrib-less'); |
|
139 | 7 | grunt.loadNpmTasks('grunt-contrib-concat'); |
|
140 | 8 | grunt.loadNpmTasks('grunt-contrib-watch'); |
|
141 | 9 | grunt.loadNpmTasks('grunt-contrib-jshint'); |
|
10 | grunt.loadNpmTasks('grunt-vulcanize'); | |
|
11 | grunt.loadNpmTasks('grunt-crisper'); | |
|
12 | grunt.loadNpmTasks('grunt-contrib-copy'); | |
|
142 | 13 | |
|
143 | grunt.registerTask('default', ['less:production', 'concat:dist']); | |
|
14 | grunt.registerTask('default', ['less:production', 'less:components', 'concat:polymercss', 'copy','vulcanize', 'crisper', 'concat:dist']); | |
|
144 | 15 | }; |
@@ -29,6 +29,9 b' recursive-include rhodecode *.mako' | |||
|
29 | 29 | # 502 page |
|
30 | 30 | include rhodecode/public/502.html |
|
31 | 31 | |
|
32 | # 502 page | |
|
33 | include rhodecode/public/502.html | |
|
34 | ||
|
32 | 35 | # images, css |
|
33 | 36 | include rhodecode/public/css/*.css |
|
34 | 37 | include rhodecode/public/images/*.* |
@@ -414,7 +414,7 b' search.location = %(here)s/data/index' | |||
|
414 | 414 | ## channelstream enables persistent connections and live notification |
|
415 | 415 | ## in the system. It's also used by the chat system |
|
416 | 416 | |
|
417 |
channelstream.enabled = |
|
|
417 | channelstream.enabled = false | |
|
418 | 418 | ## location of channelstream server on the backend |
|
419 | 419 | channelstream.server = 127.0.0.1:9800 |
|
420 | 420 | ## location of the channelstream server from outside world |
@@ -388,7 +388,7 b' search.location = %(here)s/data/index' | |||
|
388 | 388 | ## channelstream enables persistent connections and live notification |
|
389 | 389 | ## in the system. It's also used by the chat system |
|
390 | 390 | |
|
391 |
channelstream.enabled = |
|
|
391 | channelstream.enabled = false | |
|
392 | 392 | ## location of channelstream server on the backend |
|
393 | 393 | channelstream.server = 127.0.0.1:9800 |
|
394 | 394 | ## location of the channelstream server from outside world |
@@ -30,6 +30,10 b' let' | |||
|
30 | 30 | then pythonPackages |
|
31 | 31 | else getAttr pythonPackages pkgs; |
|
32 | 32 | |
|
33 | buildBowerComponents = | |
|
34 | pkgs.buildBowerComponents or | |
|
35 | (import ./pkgs/backport-16.03-build-bower-components.nix { inherit pkgs; }); | |
|
36 | ||
|
33 | 37 | elem = builtins.elem; |
|
34 | 38 | basename = path: with pkgs.lib; last (splitString "/" path); |
|
35 | 39 | startsWith = prefix: full: let |
@@ -41,31 +45,28 b' let' | |||
|
41 | 45 | ext = last (splitString "." path); |
|
42 | 46 | in |
|
43 | 47 | !elem (basename path) [ |
|
44 |
".git" ".hg" "__pycache__" ".eggs" |
|
|
45 | "build" "data" "tmp"] && | |
|
48 | ".git" ".hg" "__pycache__" ".eggs" | |
|
49 | "bower_components" "node_modules" | |
|
50 | "build" "data" "result" "tmp"] && | |
|
46 | 51 | !elem ext ["egg-info" "pyc"] && |
|
52 | # TODO: johbo: This check is wrong, since "path" contains an absolute path, | |
|
53 | # it would still be good to restore it since we want to ignore "result-*". | |
|
47 | 54 | !startsWith "result" path; |
|
48 | 55 | |
|
49 | 56 | sources = pkgs.config.rc.sources or {}; |
|
57 | version = builtins.readFile ./rhodecode/VERSION; | |
|
50 | 58 | rhodecode-enterprise-ce-src = builtins.filterSource src-filter ./.; |
|
51 | 59 | |
|
52 | # Load the generated node packages | |
|
53 | nodePackages = pkgs.callPackage "${pkgs.path}/pkgs/top-level/node-packages.nix" rec { | |
|
54 | self = nodePackages; | |
|
55 | generated = pkgs.callPackage ./pkgs/node-packages.nix { inherit self; }; | |
|
60 | nodeEnv = import ./pkgs/node-default.nix { | |
|
61 | inherit pkgs; | |
|
56 | 62 | }; |
|
63 | nodeDependencies = nodeEnv.shell.nodeDependencies; | |
|
57 | 64 | |
|
58 | # TODO: Should be taken automatically out of the generates packages. | |
|
59 | # apps.nix has one solution for this, although I'd prefer to have the deps | |
|
60 | # from package.json mapped in here. | |
|
61 | nodeDependencies = with nodePackages; [ | |
|
62 | grunt | |
|
63 | grunt-contrib-concat | |
|
64 | grunt-contrib-jshint | |
|
65 | grunt-contrib-less | |
|
66 | grunt-contrib-watch | |
|
67 | jshint | |
|
68 | ]; | |
|
65 | bowerComponents = buildBowerComponents { | |
|
66 | name = "enterprise-ce-${version}"; | |
|
67 | generated = ./pkgs/bower-packages.nix; | |
|
68 | src = rhodecode-enterprise-ce-src; | |
|
69 | }; | |
|
69 | 70 | |
|
70 | 71 | pythonGeneratedPackages = self: basePythonPackages.override (a: { |
|
71 | 72 | inherit self; |
@@ -86,16 +87,25 b' let' | |||
|
86 | 87 | pythonLocalOverrides = self: super: { |
|
87 | 88 | rhodecode-enterprise-ce = |
|
88 | 89 | let |
|
89 | version = builtins.readFile ./rhodecode/VERSION; | |
|
90 | linkNodeModules = '' | |
|
90 | linkNodeAndBowerPackages = '' | |
|
91 | echo "Export RhodeCode CE path" | |
|
92 | export RHODECODE_CE_PATH=${rhodecode-enterprise-ce-src} | |
|
91 | 93 | echo "Link node packages" |
|
92 | # TODO: check if this adds stuff as a dependency, closure size | |
|
93 | 94 | rm -fr node_modules |
|
94 |
mkdir |
|
|
95 | ${pkgs.lib.concatMapStrings (dep: '' | |
|
96 | ln -sfv ${dep}/lib/node_modules/${dep.pkgName} node_modules/ | |
|
97 | '') nodeDependencies} | |
|
95 | mkdir node_modules | |
|
96 | # johbo: Linking individual packages allows us to run "npm install" | |
|
97 | # inside of a shell to try things out. Re-entering the shell will | |
|
98 | # restore a clean environment. | |
|
99 | ln -s ${nodeDependencies}/lib/node_modules/* node_modules/ | |
|
100 | ||
|
98 | 101 | echo "DONE: Link node packages" |
|
102 | ||
|
103 | echo "Link bower packages" | |
|
104 | rm -fr bower_components | |
|
105 | mkdir bower_components | |
|
106 | ||
|
107 | ln -s ${bowerComponents}/bower_components/* bower_components/ | |
|
108 | echo "DONE: Link bower packages" | |
|
99 | 109 | ''; |
|
100 | 110 | in super.rhodecode-enterprise-ce.override (attrs: { |
|
101 | 111 | |
@@ -109,6 +119,7 b' let' | |||
|
109 | 119 | buildInputs = |
|
110 | 120 | attrs.buildInputs ++ |
|
111 | 121 | (with self; [ |
|
122 | pkgs.nodePackages.bower | |
|
112 | 123 | pkgs.nodePackages.grunt-cli |
|
113 | 124 | pkgs.subversion |
|
114 | 125 | pytest-catchlog |
@@ -123,7 +134,8 b' let' | |||
|
123 | 134 | # pkgs/default.nix? |
|
124 | 135 | passthru = { |
|
125 | 136 | inherit |
|
126 | linkNodeModules | |
|
137 | bowerComponents | |
|
138 | linkNodeAndBowerPackages | |
|
127 | 139 | myPythonPackagesUnfix |
|
128 | 140 | pythonLocalOverrides; |
|
129 | 141 | pythonPackages = self; |
@@ -145,7 +157,7 b' let' | |||
|
145 | 157 | export PYTHONPATH="$tmp_path/${self.python.sitePackages}:$PYTHONPATH" |
|
146 | 158 | mkdir -p $tmp_path/${self.python.sitePackages} |
|
147 | 159 | python setup.py develop --prefix $tmp_path --allow-hosts "" |
|
148 |
'' + linkNode |
|
|
160 | '' + linkNodeAndBowerPackages; | |
|
149 | 161 | |
|
150 | 162 | preCheck = '' |
|
151 | 163 | export PATH="$out/bin:$PATH" |
@@ -156,7 +168,7 b' let' | |||
|
156 | 168 | rm -rf $out/lib/${self.python.libPrefix}/site-packages/rhodecode/tests |
|
157 | 169 | ''; |
|
158 | 170 | |
|
159 |
preBuild = linkNode |
|
|
171 | preBuild = linkNodeAndBowerPackages + '' | |
|
160 | 172 | grunt |
|
161 | 173 | rm -fr node_modules |
|
162 | 174 | ''; |
@@ -29,13 +29,3 b' 4. You will see the labs setting on the' | |||
|
29 | 29 | :menuselection:`Admin --> Settings --> labs` page. |
|
30 | 30 | |
|
31 | 31 | .. image:: ../images/lab-setting.png |
|
32 | ||
|
33 | Available Lab Extras | |
|
34 | -------------------- | |
|
35 | ||
|
36 | Once lab settings are enabled, the following features are available. | |
|
37 | ||
|
38 | .. toctree:: | |
|
39 | :maxdepth: 1 | |
|
40 | ||
|
41 | svn-http |
@@ -26,6 +26,7 b' For more information, see the following ' | |||
|
26 | 26 | * :ref:`vcs-server-versions` |
|
27 | 27 | * :ref:`vcs-server-maintain` |
|
28 | 28 | * :ref:`vcs-server-config-file` |
|
29 | * :ref:`svn-http` | |
|
29 | 30 | |
|
30 | 31 | .. _install-vcs: |
|
31 | 32 | |
@@ -297,5 +298,133 b' For a more detailed explanation of the l' | |||
|
297 | 298 | format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s |
|
298 | 299 | datefmt = %Y-%m-%d %H:%M:%S |
|
299 | 300 | |
|
301 | .. _svn-http: | |
|
300 | 302 | |
|
301 | .. _Ask Ubuntu: http://askubuntu.com/questions/162391/how-do-i-fix-my-locale-issue | |
|
303 | |svn| With Write Over HTTP | |
|
304 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
|
305 | ||
|
306 | To use |svn| with read/write support over the |svn| HTTP protocol, you have to | |
|
307 | configure the HTTP |svn| backend. | |
|
308 | ||
|
309 | Prerequisites | |
|
310 | ============= | |
|
311 | ||
|
312 | - Enable HTTP support inside the admin VCS settings on your |RCE| instance | |
|
313 | - You need to install the following tools on the machine that is running an | |
|
314 | instance of |RCE|: | |
|
315 | ``Apache HTTP Server`` and | |
|
316 | ``mod_dav_svn``. | |
|
317 | ||
|
318 | ||
|
319 | Using Ubuntu Distribution as an example you can run: | |
|
320 | ||
|
321 | .. code-block:: bash | |
|
322 | ||
|
323 | $ sudo apt-get install apache2 libapache2-mod-svn | |
|
324 | ||
|
325 | Once installed you need to enable ``dav_svn``: | |
|
326 | ||
|
327 | .. code-block:: bash | |
|
328 | ||
|
329 | $ sudo a2enmod dav_svn | |
|
330 | ||
|
331 | Configuring Apache Setup | |
|
332 | ======================== | |
|
333 | ||
|
334 | .. tip:: | |
|
335 | ||
|
336 | It is recommended to run Apache on a port other than 80, due to possible | |
|
337 | conflicts with other HTTP servers like nginx. To do this, set the | |
|
338 | ``Listen`` parameter in the ``/etc/apache2/ports.conf`` file, for example | |
|
339 | ``Listen 8090``. | |
|
340 | ||
|
341 | ||
|
342 | .. warning:: | |
|
343 | ||
|
344 | Make sure your Apache instance which runs the mod_dav_svn module is | |
|
345 | only accessible by RhodeCode. Otherwise everyone is able to browse | |
|
346 | the repositories or run subversion operations (checkout/commit/etc.). | |
|
347 | ||
|
348 | It is also recommended to run apache as the same user as |RCE|, otherwise | |
|
349 | permission issues could occur. To do this edit the ``/etc/apache2/envvars`` | |
|
350 | ||
|
351 | .. code-block:: apache | |
|
352 | ||
|
353 | export APACHE_RUN_USER=rhodecode | |
|
354 | export APACHE_RUN_GROUP=rhodecode | |
|
355 | ||
|
356 | 1. To configure Apache, create and edit a virtual hosts file, for example | |
|
357 | :file:`/etc/apache2/sites-available/default.conf`. Below is an example | |
|
358 | how to use one with auto-generated config ```mod_dav_svn.conf``` | |
|
359 | from configured |RCE| instance. | |
|
360 | ||
|
361 | .. code-block:: apache | |
|
362 | ||
|
363 | <VirtualHost *:8080> | |
|
364 | ServerAdmin rhodecode-admin@localhost | |
|
365 | DocumentRoot /var/www/html | |
|
366 | ErrorLog ${'${APACHE_LOG_DIR}'}/error.log | |
|
367 | CustomLog ${'${APACHE_LOG_DIR}'}/access.log combined | |
|
368 | Include /home/user/.rccontrol/enterprise-1/mod_dav_svn.conf | |
|
369 | </VirtualHost> | |
|
370 | ||
|
371 | ||
|
372 | 2. Go to the :menuselection:`Admin --> Settings --> VCS` page, and | |
|
373 | enable :guilabel:`Proxy Subversion HTTP requests`, and specify the | |
|
374 | :guilabel:`Subversion HTTP Server URL`. | |
|
375 | ||
|
376 | 3. Open the |RCE| configuration file, | |
|
377 | :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` | |
|
378 | ||
|
379 | 4. Add the following configuration option in the ``[app:main]`` | |
|
380 | section if you don't have it yet. | |
|
381 | ||
|
382 | This enables mapping of the created |RCE| repo groups into special |svn| paths. | |
|
383 | Each time a new repository group is created, the system will update | |
|
384 | the template file and create new mapping. Apache web server needs to be | |
|
385 | reloaded to pick up the changes on this file. | |
|
386 | It's recommended to add reload into a crontab so the changes can be picked | |
|
387 | automatically once someone creates a repository group inside RhodeCode. | |
|
388 | ||
|
389 | ||
|
390 | .. code-block:: ini | |
|
391 | ||
|
392 | ############################################## | |
|
393 | ### Subversion proxy support (mod_dav_svn) ### | |
|
394 | ############################################## | |
|
395 | ## Enable or disable the config file generation. | |
|
396 | svn.proxy.generate_config = true | |
|
397 | ## Generate config file with `SVNListParentPath` set to `On`. | |
|
398 | svn.proxy.list_parent_path = true | |
|
399 | ## Set location and file name of generated config file. | |
|
400 | svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf | |
|
401 | ## File system path to the directory containing the repositories served by | |
|
402 | ## RhodeCode. | |
|
403 | svn.proxy.parent_path_root = /path/to/repo_store | |
|
404 | ## Used as a prefix to the <Location> block in the generated config file. In | |
|
405 | ## most cases it should be set to `/`. | |
|
406 | svn.proxy.location_root = / | |
|
407 | ||
|
408 | ||
|
409 | This would create a special template file called ```mod_dav_svn.conf```. We | |
|
410 | used that file path in the apache config above inside the Include statement. | |
|
411 | ||
|
412 | ||
|
413 | Using |svn| | |
|
414 | =========== | |
|
415 | ||
|
416 | Once |svn| has been enabled on your instance, you can use it with the | |
|
417 | following examples. For more |svn| information, see the `Subversion Red Book`_ | |
|
418 | ||
|
419 | .. code-block:: bash | |
|
420 | ||
|
421 | # To clone a repository | |
|
422 | svn checkout http://my-svn-server.example.com/my-svn-repo | |
|
423 | ||
|
424 | # svn commit | |
|
425 | svn commit | |
|
426 | ||
|
427 | .. _Subversion Red Book: http://svnbook.red-bean.com/en/1.7/svn-book.html#svn.ref.svn | |
|
428 | ||
|
429 | ||
|
430 | .. _Ask Ubuntu: http://askubuntu.com/questions/162391/how-do-i-fix-my-locale-issue No newline at end of file |
@@ -18,3 +18,4 b' Welcome to the contribution guides and d' | |||
|
18 | 18 | db-schema |
|
19 | 19 | dev-settings |
|
20 | 20 | api |
|
21 | dependencies |
@@ -111,15 +111,18 b' time operation::' | |||
|
111 | 111 | Compile CSS and JavaScript |
|
112 | 112 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
113 | 113 | |
|
114 | To use the application's frontend, you will need to compile the CSS and | |
|
115 | JavaScript with Grunt. This is easily done from within the nix-shell using the | |
|
116 | following command:: | |
|
114 | To use the application's frontend and prepare it for production deployment, | |
|
115 | you will need to compile the CSS and JavaScript with Grunt. | |
|
116 | This is easily done from within the nix-shell using the following command:: | |
|
117 | ||
|
118 | grunt | |
|
117 | 119 | |
|
118 | make web-build | |
|
120 | When developing new features you will need to recompile following any | |
|
121 | changes made to the CSS or JavaScript files when developing the code:: | |
|
119 | 122 |
|
|
120 | You will need to recompile following any changes made to the CSS or JavaScript | |
|
121 | files. | |
|
123 | grunt watch | |
|
122 | 124 | |
|
125 | This prepares the development (with comments/whitespace) versions of files. | |
|
123 | 126 | |
|
124 | 127 | Start the Development Server |
|
125 | 128 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
@@ -45,6 +45,11 b' JavaScript' | |||
|
45 | 45 | ---------- |
|
46 | 46 | This currently remains undefined. Suggestions welcome! |
|
47 | 47 | |
|
48 | However, we have decided to go forward with W3C standards and picked | |
|
49 | WebComponents as the foundation of user interface. New functionality should | |
|
50 | be implemented as components using the | |
|
51 | `Polymer Project` <https://www.polymer-project.org>`_ library | |
|
52 | and should avoid external dependencies like `jquery`. | |
|
48 | 53 | |
|
49 | 54 | HTML |
|
50 | 55 | ---- |
@@ -14,9 +14,6 b' py.test based test suite' | |||
|
14 | 14 | The test suite is in the folder :file:`rhodecode/tests/` and should be run with |
|
15 | 15 | the test runner `py.test` inside of your `nix-shell` environment:: |
|
16 | 16 | |
|
17 | # In case you need the cythonized version | |
|
18 | CYTHONIZE=1 python setup.py develop --prefix=$tmp_path | |
|
19 | ||
|
20 | 17 | py.test rhodecode |
|
21 | 18 | |
|
22 | 19 | |
@@ -26,20 +23,28 b' py.test integration' | |||
|
26 | 23 | |
|
27 | 24 | The integration with the test runner is based on the following three parts: |
|
28 | 25 | |
|
29 |
- |
|
|
30 |
Pylons web framework. It sets up the Pylons environment |
|
|
31 | file. | |
|
26 | - :file:`rhodecode/tests/pylons_plugin.py` is a py.test plugin which does the | |
|
27 | integration with the Pylons web framework. It sets up the Pylons environment | |
|
28 | based on the given ini file. | |
|
32 | 29 | |
|
33 | 30 | Tests which depend on the Pylons environment to be set up must request the |
|
34 | 31 | fixture `pylonsapp`. |
|
35 | 32 | |
|
36 | 33 | - :file:`rhodecode/tests/plugin.py` contains the integration of py.test with |
|
37 | RhodeCode Enterprise itself. | |
|
34 | RhodeCode Enterprise itself and it takes care of setting up the needed parts | |
|
35 | of the Pyramid framework. | |
|
38 | 36 | |
|
39 | 37 | - :file:`conftest.py` plugins are used to provide a special integration for |
|
40 | 38 | certain groups of tests based on the directory location. |
|
41 | 39 | |
|
42 | 40 | |
|
41 | .. note:: | |
|
42 | ||
|
43 | We are migrating from Pylons to its successor Pyramid. Eventually the role of | |
|
44 | the file `pylons_plugin.py` will change to provide only a Pyramid | |
|
45 | integration. | |
|
46 | ||
|
47 | ||
|
43 | 48 | |
|
44 | 49 | VCS backend selection |
|
45 | 50 | --------------------- |
@@ -19,8 +19,7 b' Quick Start Installation Guide' | |||
|
19 | 19 | |
|
20 | 20 | To get |RCE| up and running, run through the below steps: |
|
21 | 21 | |
|
22 |
1. Download the latest |RCC| installer from |
|
|
23 | or main page. | |
|
22 | 1. Download the latest |RCC| installer from `rhodecode.com/download`_. | |
|
24 | 23 | If you don't have an account, sign up at `rhodecode.com/register`_. |
|
25 | 24 | |
|
26 | 25 | 2. Run the |RCC| installer and accept the End User Licence using the |
@@ -107,3 +106,5 b' 5. Check the status of your installation' | |||
|
107 | 106 | .. _rhodecode.com/download/: https://rhodecode.com/download/ |
|
108 | 107 | .. _rhodecode.com: https://rhodecode.com/ |
|
109 | 108 | .. _rhodecode.com/register: https://rhodecode.com/register/ |
|
109 | .. _rhodecode.com/download: https://rhodecode.com/download/ | |
|
110 |
@@ -3,20 +3,20 b'' | |||
|
3 | 3 | PostgreSQL |
|
4 | 4 | ---------- |
|
5 | 5 | |
|
6 |
To use a PostgreSQL database you should install and configure |
|
|
7 |
before installing |RCV|. This is because |
|
|
8 |
setup |
|
|
6 | To use a PostgreSQL database, you should install and configure the database | |
|
7 | before installing |RCV|. This is because during |RCV| installation you will | |
|
8 | setup the connection to your PostgreSQL database. To work with PostgreSQL, | |
|
9 | 9 | use the following steps: |
|
10 | 10 | |
|
11 |
1. Depending on your |os|, install a |
|
|
11 | 1. Depending on your |os|, install a PostgreSQL database following the | |
|
12 | 12 | appropriate instructions from the `PostgreSQL website`_. |
|
13 | 2. Configure the database with a username and password which you will use | |
|
13 | 2. Configure the database with a username and password, which you will use | |
|
14 | 14 | with |RCV|. |
|
15 | 15 | 3. Install |RCV|, and during installation select PostgreSQL as your database. |
|
16 |
4. Enter the following information |
|
|
16 | 4. Enter the following information during the database setup: | |
|
17 | 17 | |
|
18 | 18 | * Your network IP Address |
|
19 |
* The port number for |
|
|
19 | * The port number for PostgreSQL access; the default port is ``5434`` | |
|
20 | 20 | * Your database username |
|
21 | 21 | * Your database password |
|
22 | 22 | * A new database name |
@@ -9,6 +9,7 b' Release Notes' | |||
|
9 | 9 | .. toctree:: |
|
10 | 10 | :maxdepth: 1 |
|
11 | 11 | |
|
12 | release-notes-4.4.0.rst | |
|
12 | 13 | release-notes-4.3.1.rst |
|
13 | 14 | release-notes-4.3.0.rst |
|
14 | 15 | release-notes-4.2.1.rst |
@@ -3,10 +3,16 b'' | |||
|
3 | 3 | "version": "0.0.1", |
|
4 | 4 | "devDependencies": { |
|
5 | 5 | "grunt": "^0.4.5", |
|
6 | "grunt-contrib-copy": "^1.0.0", | |
|
6 | 7 | "grunt-contrib-concat": "^0.5.1", |
|
7 | 8 | "grunt-contrib-jshint": "^0.12.0", |
|
8 | 9 | "grunt-contrib-less": "^1.1.0", |
|
9 | 10 | "grunt-contrib-watch": "^0.6.1", |
|
10 |
" |
|
|
11 | "crisper": "^2.0.2", | |
|
12 | "vulcanize": "^1.14.8", | |
|
13 | "grunt-crisper": "^1.0.1", | |
|
14 | "grunt-vulcanize": "^1.0.0", | |
|
15 | "jshint": "^2.9.1-rc3", | |
|
16 | "bower": "^1.7.9" | |
|
11 | 17 | } |
|
12 | 18 | } |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
@@ -14,6 +14,20 b' let' | |||
|
14 | 14 | url = http://www.repoze.org/LICENSE.txt; |
|
15 | 15 | }; |
|
16 | 16 | }; |
|
17 | ||
|
18 | # johbo: Interim bridge which allows us to build with the upcoming | |
|
19 | # nixos.16.09 branch (unstable at the moment of writing this note) and the | |
|
20 | # current stable nixos-16.03. | |
|
21 | backwardsCompatibleFetchgit = { ... }@args: | |
|
22 | let | |
|
23 | origSources = pkgs.fetchgit args; | |
|
24 | in | |
|
25 | pkgs.lib.overrideDerivation origSources (oldAttrs: { | |
|
26 | NIX_PREFETCH_GIT_CHECKOUT_HOOK = '' | |
|
27 | find $out -name '.git*' -print0 | xargs -0 rm -rf | |
|
28 | ''; | |
|
29 | }); | |
|
30 | ||
|
17 | 31 | in |
|
18 | 32 | |
|
19 | 33 | self: super: { |
@@ -96,7 +110,7 b' self: super: {' | |||
|
96 | 110 | }); |
|
97 | 111 | |
|
98 | 112 | py-gfm = super.py-gfm.override { |
|
99 |
src = |
|
|
113 | src = backwardsCompatibleFetchgit { | |
|
100 | 114 | url = "https://code.rhodecode.com/upstream/py-gfm"; |
|
101 | 115 | rev = "0d66a19bc16e3d49de273c0f797d4e4781e8c0f2"; |
|
102 | 116 | sha256 = "0ryp74jyihd3ckszq31bml5jr3bciimhfp7va7kw6ld92930ksv3"; |
@@ -120,7 +134,7 b' self: super: {' | |||
|
120 | 134 | |
|
121 | 135 | Pylons = super.Pylons.override (attrs: { |
|
122 | 136 | name = "Pylons-1.0.1-patch1"; |
|
123 |
src = |
|
|
137 | src = backwardsCompatibleFetchgit { | |
|
124 | 138 | url = "https://code.rhodecode.com/upstream/pylons"; |
|
125 | 139 | rev = "707354ee4261b9c10450404fc9852ccea4fd667d"; |
|
126 | 140 | sha256 = "b2763274c2780523a335f83a1df65be22ebe4ff413a7bc9e9288d23c1f62032e"; |
@@ -51,19 +51,6 b'' | |||
|
51 | 51 | license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ]; |
|
52 | 52 | }; |
|
53 | 53 | }; |
|
54 | Fabric = super.buildPythonPackage { | |
|
55 | name = "Fabric-1.10.0"; | |
|
56 | buildInputs = with self; []; | |
|
57 | doCheck = false; | |
|
58 | propagatedBuildInputs = with self; [paramiko]; | |
|
59 | src = fetchurl { | |
|
60 | url = "https://pypi.python.org/packages/e3/5f/b6ebdb5241d5ec9eab582a5c8a01255c1107da396f849e538801d2fe64a5/Fabric-1.10.0.tar.gz"; | |
|
61 | md5 = "2cb96473387f0e7aa035210892352f4a"; | |
|
62 | }; | |
|
63 | meta = { | |
|
64 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
65 | }; | |
|
66 | }; | |
|
67 | 54 | FormEncode = super.buildPythonPackage { |
|
68 | 55 | name = "FormEncode-1.2.4"; |
|
69 | 56 | buildInputs = with self; []; |
@@ -1430,7 +1417,7 b'' | |||
|
1430 | 1417 | }; |
|
1431 | 1418 | }; |
|
1432 | 1419 | rhodecode-enterprise-ce = super.buildPythonPackage { |
|
1433 |
name = "rhodecode-enterprise-ce-4. |
|
|
1420 | name = "rhodecode-enterprise-ce-4.4.0"; | |
|
1434 | 1421 | buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner]; |
|
1435 | 1422 | doCheck = true; |
|
1436 | 1423 | propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery channelstream colander decorator deform docutils gevent gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt]; |
@@ -1,7 +1,6 b'' | |||
|
1 | 1 | Babel==1.3 |
|
2 | 2 | Beaker==1.7.0 |
|
3 | 3 | CProfileV==1.0.6 |
|
4 | Fabric==1.10.0 | |
|
5 | 4 | FormEncode==1.2.4 |
|
6 | 5 | Jinja2==2.7.3 |
|
7 | 6 | Mako==1.0.1 |
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}' | |||
|
51 | 51 | EXTENSIONS = {} |
|
52 | 52 | |
|
53 | 53 | __version__ = ('.'.join((str(each) for each in VERSION[:3]))) |
|
54 |
__dbversion__ = 5 |
|
|
54 | __dbversion__ = 58 # defines current db version for migrations | |
|
55 | 55 | __platform__ = platform.system() |
|
56 | 56 | __license__ = 'AGPLv3, and Commercial License' |
|
57 | 57 | __author__ = 'RhodeCode GmbH' |
@@ -60,3 +60,4 b' EXTENSIONS = {}' | |||
|
60 | 60 | is_windows = __platform__ in ['Windows'] |
|
61 | 61 | is_unix = not is_windows |
|
62 | 62 | is_test = False |
|
63 | disable_error_handler = False |
@@ -29,7 +29,9 b' from rhodecode.lib.ext_json import json' | |||
|
29 | 29 | def url_gen(request): |
|
30 | 30 | urls = { |
|
31 | 31 | 'connect': request.route_url('channelstream_connect'), |
|
32 | 'subscribe': request.route_url('channelstream_subscribe') | |
|
32 | 'subscribe': request.route_url('channelstream_subscribe'), | |
|
33 | 'longpoll': request.registry.settings.get('channelstream.longpoll_url', ''), | |
|
34 | 'ws': request.registry.settings.get('channelstream.ws_url', '') | |
|
33 | 35 | } |
|
34 | 36 | return json.dumps(urls) |
|
35 | 37 |
@@ -95,6 +95,7 b' class ChannelstreamView(object):' | |||
|
95 | 95 | 'display_name': None, |
|
96 | 96 | 'display_link': None, |
|
97 | 97 | } |
|
98 | user_data['permissions'] = c.rhodecode_user.permissions | |
|
98 | 99 | payload = { |
|
99 | 100 | 'username': user.username, |
|
100 | 101 | 'user_state': user_data, |
@@ -28,7 +28,11 b' from rhodecode.lib.utils2 import __get_l' | |||
|
28 | 28 | |
|
29 | 29 | # language map is also used by whoosh indexer, which for those specified |
|
30 | 30 | # extensions will index it's content |
|
31 | LANGUAGES_EXTENSIONS_MAP = __get_lem() | |
|
31 | # custom extensions to lexers, format is 'ext': 'LexerClass' | |
|
32 | extra = { | |
|
33 | 'vbs': 'VbNet' | |
|
34 | } | |
|
35 | LANGUAGES_EXTENSIONS_MAP = __get_lem(extra) | |
|
32 | 36 | |
|
33 | 37 | DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" |
|
34 | 38 |
@@ -158,6 +158,8 b' def load_pyramid_environment(global_conf' | |||
|
158 | 158 | # This has to be done before the database connection is initialized. |
|
159 | 159 | if settings['is_test']: |
|
160 | 160 | rhodecode.is_test = True |
|
161 | rhodecode.disable_error_handler = True | |
|
162 | ||
|
161 | 163 | utils.initialize_test_environment(settings_merged) |
|
162 | 164 | |
|
163 | 165 | # Initialize the database connection. |
@@ -44,9 +44,10 b' from rhodecode.config import patches' | |||
|
44 | 44 | from rhodecode.config.routing import STATIC_FILE_PREFIX |
|
45 | 45 | from rhodecode.config.environment import ( |
|
46 | 46 | load_environment, load_pyramid_environment) |
|
47 | from rhodecode.lib.exceptions import VCSServerUnavailable | |
|
48 | from rhodecode.lib.vcs.exceptions import VCSCommunicationError | |
|
47 | 49 | from rhodecode.lib.middleware import csrf |
|
48 | 50 | from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled |
|
49 | from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper | |
|
50 | 51 | from rhodecode.lib.middleware.https_fixup import HttpsFixup |
|
51 | 52 | from rhodecode.lib.middleware.vcs import VCSMiddleware |
|
52 | 53 | from rhodecode.lib.plugins.utils import register_rhodecode_plugin |
@@ -193,10 +194,6 b' def make_not_found_view(config):' | |||
|
193 | 194 | |
|
194 | 195 | pylons_app_as_view = wsgiapp(pylons_app) |
|
195 | 196 | |
|
196 | # Protect from VCS Server error related pages when server is not available | |
|
197 | if not vcs_server_enabled: | |
|
198 | pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view) | |
|
199 | ||
|
200 | 197 | def pylons_app_with_error_handler(context, request): |
|
201 | 198 | """ |
|
202 | 199 | Handle exceptions from rc pylons app: |
@@ -221,10 +218,18 b' def make_not_found_view(config):' | |||
|
221 | 218 | return error_handler(response, request) |
|
222 | 219 | except HTTPError as e: # pyramid type exceptions |
|
223 | 220 | return error_handler(e, request) |
|
224 | except Exception: | |
|
225 | if settings.get('debugtoolbar.enabled', False): | |
|
221 | except Exception as e: | |
|
222 | log.exception(e) | |
|
223 | ||
|
224 | if (settings.get('debugtoolbar.enabled', False) or | |
|
225 | rhodecode.disable_error_handler): | |
|
226 | 226 | raise |
|
227 | ||
|
228 | if isinstance(e, VCSCommunicationError): | |
|
229 | return error_handler(VCSServerUnavailable(), request) | |
|
230 | ||
|
227 | 231 | return error_handler(HTTPInternalServerError(), request) |
|
232 | ||
|
228 | 233 | return response |
|
229 | 234 | |
|
230 | 235 | return pylons_app_with_error_handler |
@@ -249,7 +254,6 b' def webob_to_pyramid_http_response(webob' | |||
|
249 | 254 | |
|
250 | 255 | |
|
251 | 256 | def error_handler(exception, request): |
|
252 | # TODO: dan: replace the old pylons error controller with this | |
|
253 | 257 | from rhodecode.model.settings import SettingsModel |
|
254 | 258 | from rhodecode.lib.utils2 import AttributeDict |
|
255 | 259 | |
@@ -278,6 +282,10 b' def error_handler(exception, request):' | |||
|
278 | 282 | if not c.rhodecode_name: |
|
279 | 283 | c.rhodecode_name = 'Rhodecode' |
|
280 | 284 | |
|
285 | c.causes = [] | |
|
286 | if hasattr(base_response, 'causes'): | |
|
287 | c.causes = base_response.causes | |
|
288 | ||
|
281 | 289 | response = render_to_response( |
|
282 | 290 | '/errors/error_document.html', {'c': c}, request=request, |
|
283 | 291 | response=base_response) |
@@ -42,6 +42,7 b" STATIC_FILE_PREFIX = '/_static'" | |||
|
42 | 42 | URL_NAME_REQUIREMENTS = { |
|
43 | 43 | # group name can have a slash in them, but they must not end with a slash |
|
44 | 44 | 'group_name': r'.*?[^/]', |
|
45 | 'repo_group_name': r'.*?[^/]', | |
|
45 | 46 | # repo names can have a slash in them, but they must not end with a slash |
|
46 | 47 | 'repo_name': r'.*?[^/]', |
|
47 | 48 | # file path eats up everything at the end |
@@ -531,9 +532,7 b' def make_map(config):' | |||
|
531 | 532 | action='my_account_update', conditions={'method': ['POST']}) |
|
532 | 533 | |
|
533 | 534 | m.connect('my_account_password', '/my_account/password', |
|
534 | action='my_account_password', conditions={'method': ['GET']}) | |
|
535 | m.connect('my_account_password', '/my_account/password', | |
|
536 | action='my_account_password_update', conditions={'method': ['POST']}) | |
|
535 | action='my_account_password', conditions={'method': ['GET', 'POST']}) | |
|
537 | 536 | |
|
538 | 537 | m.connect('my_account_repos', '/my_account/repos', |
|
539 | 538 | action='my_account_repos', conditions={'method': ['GET']}) |
@@ -32,17 +32,21 b' from pylons.controllers.util import redi' | |||
|
32 | 32 | from pylons.i18n.translation import _ |
|
33 | 33 | from sqlalchemy.orm import joinedload |
|
34 | 34 | |
|
35 | from rhodecode import forms | |
|
35 | 36 | from rhodecode.lib import helpers as h |
|
36 | 37 | from rhodecode.lib import auth |
|
37 | 38 | from rhodecode.lib.auth import ( |
|
38 | 39 | LoginRequired, NotAnonymous, AuthUser, generate_auth_token) |
|
39 | 40 | from rhodecode.lib.base import BaseController, render |
|
41 | from rhodecode.lib.utils import jsonify | |
|
40 | 42 | from rhodecode.lib.utils2 import safe_int, md5 |
|
41 | 43 | from rhodecode.lib.ext_json import json |
|
44 | ||
|
45 | from rhodecode.model.validation_schema.schemas import user_schema | |
|
42 | 46 | from rhodecode.model.db import ( |
|
43 | 47 | Repository, PullRequest, PullRequestReviewers, UserEmailMap, User, |
|
44 | 48 | UserFollowing) |
|
45 |
from rhodecode.model.forms import UserForm |
|
|
49 | from rhodecode.model.forms import UserForm | |
|
46 | 50 | from rhodecode.model.scm import RepoList |
|
47 | 51 | from rhodecode.model.user import UserModel |
|
48 | 52 | from rhodecode.model.repo import RepoModel |
@@ -185,38 +189,44 b' class MyAccountController(BaseController' | |||
|
185 | 189 | force_defaults=False |
|
186 | 190 | ) |
|
187 | 191 | |
|
188 | @auth.CSRFRequired() | |
|
189 | def my_account_password_update(self): | |
|
190 | c.active = 'password' | |
|
191 | self.__load_data() | |
|
192 | _form = PasswordChangeForm(c.rhodecode_user.username)() | |
|
193 | try: | |
|
194 | form_result = _form.to_python(request.POST) | |
|
195 | UserModel().update_user(c.rhodecode_user.user_id, **form_result) | |
|
196 | instance = c.rhodecode_user.get_instance() | |
|
197 | instance.update_userdata(force_password_change=False) | |
|
198 | Session().commit() | |
|
199 | session.setdefault('rhodecode_user', {}).update( | |
|
200 | {'password': md5(instance.password)}) | |
|
201 | session.save() | |
|
202 | h.flash(_("Successfully updated password"), category='success') | |
|
203 | except formencode.Invalid as errors: | |
|
204 | return htmlfill.render( | |
|
205 | render('admin/my_account/my_account.html'), | |
|
206 | defaults=errors.value, | |
|
207 | errors=errors.error_dict or {}, | |
|
208 | prefix_error=False, | |
|
209 | encoding="UTF-8", | |
|
210 | force_defaults=False) | |
|
211 | except Exception: | |
|
212 | log.exception("Exception updating password") | |
|
213 | h.flash(_('Error occurred during update of user password'), | |
|
214 | category='error') | |
|
215 | return render('admin/my_account/my_account.html') | |
|
216 | ||
|
192 | @auth.CSRFRequired(except_methods=['GET']) | |
|
217 | 193 | def my_account_password(self): |
|
218 | 194 | c.active = 'password' |
|
219 | 195 | self.__load_data() |
|
196 | ||
|
197 | schema = user_schema.ChangePasswordSchema().bind( | |
|
198 | username=c.rhodecode_user.username) | |
|
199 | ||
|
200 | form = forms.Form(schema, | |
|
201 | buttons=(forms.buttons.save, forms.buttons.reset)) | |
|
202 | ||
|
203 | if request.method == 'POST': | |
|
204 | controls = request.POST.items() | |
|
205 | try: | |
|
206 | valid_data = form.validate(controls) | |
|
207 | UserModel().update_user(c.rhodecode_user.user_id, **valid_data) | |
|
208 | instance = c.rhodecode_user.get_instance() | |
|
209 | instance.update_userdata(force_password_change=False) | |
|
210 | Session().commit() | |
|
211 | except forms.ValidationFailure as e: | |
|
212 | request.session.flash( | |
|
213 | _('Error occurred during update of user password'), | |
|
214 | queue='error') | |
|
215 | form = e | |
|
216 | except Exception: | |
|
217 | log.exception("Exception updating password") | |
|
218 | request.session.flash( | |
|
219 | _('Error occurred during update of user password'), | |
|
220 | queue='error') | |
|
221 | else: | |
|
222 | session.setdefault('rhodecode_user', {}).update( | |
|
223 | {'password': md5(instance.password)}) | |
|
224 | session.save() | |
|
225 | request.session.flash( | |
|
226 | _("Successfully updated password"), queue='success') | |
|
227 | return redirect(url('my_account_password')) | |
|
228 | ||
|
229 | c.form = form | |
|
220 | 230 | return render('admin/my_account/my_account.html') |
|
221 | 231 | |
|
222 | 232 | def my_account_repos(self): |
@@ -352,11 +362,10 b' class MyAccountController(BaseController' | |||
|
352 | 362 | return render('admin/my_account/my_account.html') |
|
353 | 363 | |
|
354 | 364 | @auth.CSRFRequired() |
|
365 | @jsonify | |
|
355 | 366 | def my_notifications_toggle_visibility(self): |
|
356 | 367 | user = c.rhodecode_user.get_instance() |
|
357 | user_data = user.user_data | |
|
358 |
status |
|
|
359 | user_data['notification_status'] = not status | |
|
360 | user.user_data = user_data | |
|
368 | new_status = not user.user_data.get('notification_status', True) | |
|
369 | user.update_userdata(notification_status=new_status) | |
|
361 | 370 | Session().commit() |
|
362 |
return |
|
|
371 | return user.user_data['notification_status'] |
@@ -135,6 +135,7 b' class SettingsController(BaseController)' | |||
|
135 | 135 | c.svn_tag_patterns = model.get_global_svn_tag_patterns() |
|
136 | 136 | |
|
137 | 137 | application_form = ApplicationUiSettingsForm()() |
|
138 | ||
|
138 | 139 | try: |
|
139 | 140 | form_result = application_form.to_python(dict(request.POST)) |
|
140 | 141 | except formencode.Invalid as errors: |
@@ -151,12 +152,14 b' class SettingsController(BaseController)' | |||
|
151 | 152 | ) |
|
152 | 153 | |
|
153 | 154 | try: |
|
154 | model.update_global_ssl_setting(form_result['web_push_ssl']) | |
|
155 | 155 | if c.visual.allow_repo_location_change: |
|
156 | 156 | model.update_global_path_setting( |
|
157 | 157 | form_result['paths_root_path']) |
|
158 | ||
|
159 | model.update_global_ssl_setting(form_result['web_push_ssl']) | |
|
158 | 160 | model.update_global_hook_settings(form_result) |
|
159 | model.create_global_svn_settings(form_result) | |
|
161 | ||
|
162 | model.create_or_update_global_svn_settings(form_result) | |
|
160 | 163 | model.create_or_update_global_hg_settings(form_result) |
|
161 | 164 | model.create_or_update_global_pr_settings(form_result) |
|
162 | 165 | except Exception: |
@@ -789,18 +792,5 b' LabSetting = collections.namedtuple(' | |||
|
789 | 792 | # This list has to be kept in sync with the form |
|
790 | 793 | # rhodecode.model.forms.LabsSettingsForm. |
|
791 | 794 | _LAB_SETTINGS = [ |
|
792 | LabSetting( | |
|
793 | key='rhodecode_proxy_subversion_http_requests', | |
|
794 | type='bool', | |
|
795 | group=lazy_ugettext('Subversion HTTP Support'), | |
|
796 | label=lazy_ugettext('Proxy subversion HTTP requests'), | |
|
797 | help='' # Do not translate the empty string! | |
|
798 | ), | |
|
799 | LabSetting( | |
|
800 | key='rhodecode_subversion_http_server_url', | |
|
801 | type='str', | |
|
802 | group=lazy_ugettext('Subversion HTTP Server URL'), | |
|
803 | label='', # Do not translate the empty string! | |
|
804 | help=lazy_ugettext('e.g. http://localhost:8080/') | |
|
805 | ), | |
|
795 | ||
|
806 | 796 | ] |
@@ -44,6 +44,8 b' from rhodecode.lib.vcs.backends.base imp' | |||
|
44 | 44 | from rhodecode.lib.vcs.exceptions import ( |
|
45 | 45 | CommitError, EmptyRepositoryError, NodeDoesNotExistError) |
|
46 | 46 | from rhodecode.model.db import Statistics, CacheKey, User |
|
47 | from rhodecode.model.repo import ReadmeFinder | |
|
48 | ||
|
47 | 49 | |
|
48 | 50 | log = logging.getLogger(__name__) |
|
49 | 51 | |
@@ -61,37 +63,16 b' class SummaryController(BaseRepoControll' | |||
|
61 | 63 | @cache_region('long_term') |
|
62 | 64 | def _generate_readme(cache_key): |
|
63 | 65 | readme_data = None |
|
64 |
readme_ |
|
|
65 | try: | |
|
66 | # gets the landing revision or tip if fails | |
|
67 | commit = db_repo.get_landing_commit() | |
|
68 | if isinstance(commit, EmptyCommit): | |
|
69 | raise EmptyRepositoryError() | |
|
70 | renderer = MarkupRenderer() | |
|
71 | for f in renderer.pick_readme_order(default_renderer): | |
|
72 | try: | |
|
73 | node = commit.get_node(f) | |
|
74 | except NodeDoesNotExistError: | |
|
75 | continue | |
|
76 | ||
|
77 | if not node.is_file(): | |
|
78 | continue | |
|
79 | ||
|
80 | readme_file = f | |
|
81 | log.debug('Found README file `%s` rendering...', | |
|
82 | readme_file) | |
|
83 | readme_data = renderer.render(node.content, | |
|
84 | filename=f) | |
|
85 | break | |
|
86 | except CommitError: | |
|
87 | log.exception("Problem getting commit") | |
|
88 | pass | |
|
89 | except EmptyRepositoryError: | |
|
90 | pass | |
|
91 | except Exception: | |
|
92 | log.exception("General failure") | |
|
93 | ||
|
94 | return readme_data, readme_file | |
|
66 | readme_node = None | |
|
67 | readme_filename = None | |
|
68 | commit = self._get_landing_commit_or_none(db_repo) | |
|
69 | if commit: | |
|
70 | log.debug("Searching for a README file.") | |
|
71 | readme_node = ReadmeFinder(default_renderer).search(commit) | |
|
72 | if readme_node: | |
|
73 | readme_data = self._render_readme_or_none(commit, readme_node) | |
|
74 | readme_filename = readme_node.path | |
|
75 | return readme_data, readme_filename | |
|
95 | 76 | |
|
96 | 77 | invalidator_context = CacheKey.repo_context_cache( |
|
97 | 78 | _generate_readme, repo_name, CacheKey.CACHE_TYPE_README) |
@@ -102,11 +83,36 b' class SummaryController(BaseRepoControll' | |||
|
102 | 83 | |
|
103 | 84 | return computed |
|
104 | 85 | |
|
86 | def _get_landing_commit_or_none(self, db_repo): | |
|
87 | log.debug("Getting the landing commit.") | |
|
88 | try: | |
|
89 | commit = db_repo.get_landing_commit() | |
|
90 | if not isinstance(commit, EmptyCommit): | |
|
91 | return commit | |
|
92 | else: | |
|
93 | log.debug("Repository is empty, no README to render.") | |
|
94 | except CommitError: | |
|
95 | log.exception( | |
|
96 | "Problem getting commit when trying to render the README.") | |
|
97 | ||
|
98 | def _render_readme_or_none(self, commit, readme_node): | |
|
99 | log.debug( | |
|
100 | 'Found README file `%s` rendering...', readme_node.path) | |
|
101 | renderer = MarkupRenderer() | |
|
102 | try: | |
|
103 | return renderer.render( | |
|
104 | readme_node.content, filename=readme_node.path) | |
|
105 | except Exception: | |
|
106 | log.exception( | |
|
107 | "Exception while trying to render the README") | |
|
105 | 108 | |
|
106 | 109 | @LoginRequired() |
|
107 | 110 | @HasRepoPermissionAnyDecorator( |
|
108 | 111 | 'repository.read', 'repository.write', 'repository.admin') |
|
109 | 112 | def index(self, repo_name): |
|
113 | ||
|
114 | # Prepare the clone URL | |
|
115 | ||
|
110 | 116 | username = '' |
|
111 | 117 | if c.rhodecode_user.username != User.DEFAULT_USER: |
|
112 | 118 | username = safe_str(c.rhodecode_user.username) |
@@ -124,6 +130,8 b' class SummaryController(BaseRepoControll' | |||
|
124 | 130 | c.clone_repo_url_id = c.rhodecode_db_repo.clone_url( |
|
125 | 131 | user=username, uri_tmpl=_def_clone_uri_by_id) |
|
126 | 132 | |
|
133 | # If enabled, get statistics data | |
|
134 | ||
|
127 | 135 | c.show_stats = bool(c.rhodecode_db_repo.enable_statistics) |
|
128 | 136 | |
|
129 | 137 | stats = self.sa.query(Statistics)\ |
@@ -47,7 +47,7 b' def _commits_as_dict(commit_ids, repos):' | |||
|
47 | 47 | if not commit_ids: |
|
48 | 48 | return [] |
|
49 | 49 | |
|
50 |
needed_commits = s |
|
|
50 | needed_commits = list(commit_ids) | |
|
51 | 51 | |
|
52 | 52 | commits = [] |
|
53 | 53 | reviewers = [] |
@@ -57,6 +57,7 b' def _commits_as_dict(commit_ids, repos):' | |||
|
57 | 57 | |
|
58 | 58 | vcs_repo = repo.scm_instance(cache=False) |
|
59 | 59 | try: |
|
60 | # use copy of needed_commits since we modify it while iterating | |
|
60 | 61 | for commit_id in list(needed_commits): |
|
61 | 62 | try: |
|
62 | 63 | cs = vcs_repo.get_changeset(commit_id) |
@@ -78,7 +79,7 b' def _commits_as_dict(commit_ids, repos):' | |||
|
78 | 79 | repo.repo_name) |
|
79 | 80 | commits.append(cs_data) |
|
80 | 81 | |
|
81 |
needed_commits. |
|
|
82 | needed_commits.remove(commit_id) | |
|
82 | 83 | |
|
83 | 84 | except Exception as e: |
|
84 | 85 | log.exception(e) |
@@ -1,21 +1,22 b'' | |||
|
1 |
# |
|
|
2 |
# Copyright (C) 201 |
|
|
3 | # This file is distributed under the same license as the rhodecode project. | |
|
4 | # FIRST AUTHOR <EMAIL@ADDRESS>, 2010. | |
|
1 | # Translations template for rhodecode-enterprise-ce. | |
|
2 | # Copyright (C) 2016 RhodeCode GmbH | |
|
3 | # This file is distributed under the same license as the rhodecode-enterprise-ce project. | |
|
5 | 4 | # |
|
5 | # Translators: | |
|
6 | 6 | msgid "" |
|
7 | 7 | msgstr "" |
|
8 |
"Project-Id-Version: |
|
|
9 |
"Report-Msgid-Bugs-To: |
|
|
8 | "Project-Id-Version: RhodeCode\n" | |
|
9 | "Report-Msgid-Bugs-To: marcin@rhodecode.com\n" | |
|
10 | 10 | "POT-Creation-Date: 2013-06-01 18:38+0200\n" |
|
11 | 11 | "PO-Revision-Date: 2011-02-25 19:13+0100\n" |
|
12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | |
|
13 |
"Language-Team: en < |
|
|
14 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" | |
|
12 | "Last-Translator: Marcin Kuzminski <marcin@rhodecode.com>\n" | |
|
13 | "Language-Team: en <admin@rhodecode.com>\n" | |
|
15 | 14 | "MIME-Version: 1.0\n" |
|
16 |
"Content-Type: text/plain; charset= |
|
|
15 | "Content-Type: text/plain; charset=UTF-8\n" | |
|
17 | 16 | "Content-Transfer-Encoding: 8bit\n" |
|
18 |
"Generated-By: Babel |
|
|
17 | "Generated-By: Babel 1.3\n" | |
|
18 | "Language: en\n" | |
|
19 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" | |
|
19 | 20 | |
|
20 | 21 | #: rhodecode/controllers/changelog.py:149 |
|
21 | 22 | msgid "All Branches" |
@@ -20,7 +20,7 b'' | |||
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | |
|
23 | from rhodecode.model.db import Repository, Integration | |
|
23 | from rhodecode.model.db import Repository, Integration, RepoGroup | |
|
24 | 24 | from rhodecode.config.routing import ( |
|
25 | 25 | ADMIN_PREFIX, add_route_requirements, URL_NAME_REQUIREMENTS) |
|
26 | 26 | from rhodecode.integrations import integration_type_registry |
@@ -29,6 +29,17 b' log = logging.getLogger(__name__)' | |||
|
29 | 29 | |
|
30 | 30 | |
|
31 | 31 | def includeme(config): |
|
32 | ||
|
33 | # global integrations | |
|
34 | ||
|
35 | config.add_route('global_integrations_new', | |
|
36 | ADMIN_PREFIX + '/integrations/new') | |
|
37 | config.add_view('rhodecode.integrations.views.GlobalIntegrationsView', | |
|
38 | attr='new_integration', | |
|
39 | renderer='rhodecode:templates/admin/integrations/new.html', | |
|
40 | request_method='GET', | |
|
41 | route_name='global_integrations_new') | |
|
42 | ||
|
32 | 43 | config.add_route('global_integrations_home', |
|
33 | 44 | ADMIN_PREFIX + '/integrations') |
|
34 | 45 | config.add_route('global_integrations_list', |
@@ -46,18 +57,80 b' def includeme(config):' | |||
|
46 | 57 | config.add_route('global_integrations_edit', |
|
47 | 58 | ADMIN_PREFIX + '/integrations/{integration}/{integration_id}', |
|
48 | 59 | custom_predicates=(valid_integration,)) |
|
60 | ||
|
61 | ||
|
49 | 62 | for route_name in ['global_integrations_create', 'global_integrations_edit']: |
|
50 | 63 | config.add_view('rhodecode.integrations.views.GlobalIntegrationsView', |
|
51 | 64 | attr='settings_get', |
|
52 |
renderer='rhodecode:templates/admin/integrations/ |
|
|
65 | renderer='rhodecode:templates/admin/integrations/form.html', | |
|
53 | 66 | request_method='GET', |
|
54 | 67 | route_name=route_name) |
|
55 | 68 | config.add_view('rhodecode.integrations.views.GlobalIntegrationsView', |
|
56 | 69 | attr='settings_post', |
|
57 |
renderer='rhodecode:templates/admin/integrations/ |
|
|
70 | renderer='rhodecode:templates/admin/integrations/form.html', | |
|
58 | 71 | request_method='POST', |
|
59 | 72 | route_name=route_name) |
|
60 | 73 | |
|
74 | ||
|
75 | # repo group integrations | |
|
76 | config.add_route('repo_group_integrations_home', | |
|
77 | add_route_requirements( | |
|
78 | '{repo_group_name}/settings/integrations', | |
|
79 | URL_NAME_REQUIREMENTS | |
|
80 | ), | |
|
81 | custom_predicates=(valid_repo_group,) | |
|
82 | ) | |
|
83 | config.add_route('repo_group_integrations_list', | |
|
84 | add_route_requirements( | |
|
85 | '{repo_group_name}/settings/integrations/{integration}', | |
|
86 | URL_NAME_REQUIREMENTS | |
|
87 | ), | |
|
88 | custom_predicates=(valid_repo_group, valid_integration)) | |
|
89 | for route_name in ['repo_group_integrations_home', 'repo_group_integrations_list']: | |
|
90 | config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView', | |
|
91 | attr='index', | |
|
92 | renderer='rhodecode:templates/admin/integrations/list.html', | |
|
93 | request_method='GET', | |
|
94 | route_name=route_name) | |
|
95 | ||
|
96 | config.add_route('repo_group_integrations_new', | |
|
97 | add_route_requirements( | |
|
98 | '{repo_group_name}/settings/integrations/new', | |
|
99 | URL_NAME_REQUIREMENTS | |
|
100 | ), | |
|
101 | custom_predicates=(valid_repo_group,)) | |
|
102 | config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView', | |
|
103 | attr='new_integration', | |
|
104 | renderer='rhodecode:templates/admin/integrations/new.html', | |
|
105 | request_method='GET', | |
|
106 | route_name='repo_group_integrations_new') | |
|
107 | ||
|
108 | config.add_route('repo_group_integrations_create', | |
|
109 | add_route_requirements( | |
|
110 | '{repo_group_name}/settings/integrations/{integration}/new', | |
|
111 | URL_NAME_REQUIREMENTS | |
|
112 | ), | |
|
113 | custom_predicates=(valid_repo_group, valid_integration)) | |
|
114 | config.add_route('repo_group_integrations_edit', | |
|
115 | add_route_requirements( | |
|
116 | '{repo_group_name}/settings/integrations/{integration}/{integration_id}', | |
|
117 | URL_NAME_REQUIREMENTS | |
|
118 | ), | |
|
119 | custom_predicates=(valid_repo_group, valid_integration)) | |
|
120 | for route_name in ['repo_group_integrations_edit', 'repo_group_integrations_create']: | |
|
121 | config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView', | |
|
122 | attr='settings_get', | |
|
123 | renderer='rhodecode:templates/admin/integrations/form.html', | |
|
124 | request_method='GET', | |
|
125 | route_name=route_name) | |
|
126 | config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView', | |
|
127 | attr='settings_post', | |
|
128 | renderer='rhodecode:templates/admin/integrations/form.html', | |
|
129 | request_method='POST', | |
|
130 | route_name=route_name) | |
|
131 | ||
|
132 | ||
|
133 | # repo integrations | |
|
61 | 134 | config.add_route('repo_integrations_home', |
|
62 | 135 | add_route_requirements( |
|
63 | 136 | '{repo_name}/settings/integrations', |
@@ -74,8 +147,21 b' def includeme(config):' | |||
|
74 | 147 | config.add_view('rhodecode.integrations.views.RepoIntegrationsView', |
|
75 | 148 | attr='index', |
|
76 | 149 | request_method='GET', |
|
150 | renderer='rhodecode:templates/admin/integrations/list.html', | |
|
77 | 151 | route_name=route_name) |
|
78 | 152 | |
|
153 | config.add_route('repo_integrations_new', | |
|
154 | add_route_requirements( | |
|
155 | '{repo_name}/settings/integrations/new', | |
|
156 | URL_NAME_REQUIREMENTS | |
|
157 | ), | |
|
158 | custom_predicates=(valid_repo,)) | |
|
159 | config.add_view('rhodecode.integrations.views.RepoIntegrationsView', | |
|
160 | attr='new_integration', | |
|
161 | renderer='rhodecode:templates/admin/integrations/new.html', | |
|
162 | request_method='GET', | |
|
163 | route_name='repo_integrations_new') | |
|
164 | ||
|
79 | 165 | config.add_route('repo_integrations_create', |
|
80 | 166 | add_route_requirements( |
|
81 | 167 | '{repo_name}/settings/integrations/{integration}/new', |
@@ -91,12 +177,12 b' def includeme(config):' | |||
|
91 | 177 | for route_name in ['repo_integrations_edit', 'repo_integrations_create']: |
|
92 | 178 | config.add_view('rhodecode.integrations.views.RepoIntegrationsView', |
|
93 | 179 | attr='settings_get', |
|
94 |
renderer='rhodecode:templates/admin/integrations/ |
|
|
180 | renderer='rhodecode:templates/admin/integrations/form.html', | |
|
95 | 181 | request_method='GET', |
|
96 | 182 | route_name=route_name) |
|
97 | 183 | config.add_view('rhodecode.integrations.views.RepoIntegrationsView', |
|
98 | 184 | attr='settings_post', |
|
99 |
renderer='rhodecode:templates/admin/integrations/ |
|
|
185 | renderer='rhodecode:templates/admin/integrations/form.html', | |
|
100 | 186 | request_method='POST', |
|
101 | 187 | route_name=route_name) |
|
102 | 188 | |
@@ -107,20 +193,37 b' def valid_repo(info, request):' | |||
|
107 | 193 | return True |
|
108 | 194 | |
|
109 | 195 | |
|
196 | def valid_repo_group(info, request): | |
|
197 | repo_group = RepoGroup.get_by_group_name(info['match']['repo_group_name']) | |
|
198 | if repo_group: | |
|
199 | return True | |
|
200 | return False | |
|
201 | ||
|
202 | ||
|
110 | 203 | def valid_integration(info, request): |
|
111 | 204 | integration_type = info['match']['integration'] |
|
112 | 205 | integration_id = info['match'].get('integration_id') |
|
113 | 206 | repo_name = info['match'].get('repo_name') |
|
207 | repo_group_name = info['match'].get('repo_group_name') | |
|
114 | 208 | |
|
115 | 209 | if integration_type not in integration_type_registry: |
|
116 | 210 | return False |
|
117 | 211 | |
|
118 | repo = None | |
|
212 | repo, repo_group = None, None | |
|
119 | 213 | if repo_name: |
|
120 |
repo = Repository.get_by_repo_name( |
|
|
214 | repo = Repository.get_by_repo_name(repo_name) | |
|
121 | 215 | if not repo: |
|
122 | 216 | return False |
|
123 | 217 | |
|
218 | if repo_group_name: | |
|
219 | repo_group = RepoGroup.get_by_group_name(repo_group_name) | |
|
220 | if not repo_group: | |
|
221 | return False | |
|
222 | ||
|
223 | if repo_name and repo_group: | |
|
224 | raise Exception('Either repo or repo_group can be set, not both') | |
|
225 | ||
|
226 | ||
|
124 | 227 | if integration_id: |
|
125 | 228 | integration = Integration.get(integration_id) |
|
126 | 229 | if not integration: |
@@ -129,5 +232,7 b' def valid_integration(info, request):' | |||
|
129 | 232 | return False |
|
130 | 233 | if repo and repo.repo_id != integration.repo_id: |
|
131 | 234 | return False |
|
235 | if repo_group and repo_group.group_id != integration.repo_group_id: | |
|
236 | return False | |
|
132 | 237 | |
|
133 | 238 | return True |
@@ -20,26 +20,52 b'' | |||
|
20 | 20 | |
|
21 | 21 | import colander |
|
22 | 22 | |
|
23 |
from rhodecode.translation import |
|
|
23 | from rhodecode.translation import _ | |
|
24 | 24 | |
|
25 | 25 | |
|
26 |
class Integration |
|
|
27 | """ | |
|
28 | This base schema is intended for use in integrations. | |
|
29 | It adds a few default settings (e.g., "enabled"), so that integration | |
|
30 | authors don't have to maintain a bunch of boilerplate. | |
|
31 | """ | |
|
26 | class IntegrationOptionsSchemaBase(colander.MappingSchema): | |
|
32 | 27 | enabled = colander.SchemaNode( |
|
33 | 28 | colander.Bool(), |
|
34 | 29 | default=True, |
|
35 |
description= |
|
|
30 | description=_('Enable or disable this integration.'), | |
|
36 | 31 | missing=False, |
|
37 |
title= |
|
|
32 | title=_('Enabled'), | |
|
38 | 33 | ) |
|
39 | 34 | |
|
40 | 35 | name = colander.SchemaNode( |
|
41 | 36 | colander.String(), |
|
42 |
description= |
|
|
37 | description=_('Short name for this integration.'), | |
|
43 | 38 | missing=colander.required, |
|
44 |
title= |
|
|
39 | title=_('Integration name'), | |
|
45 | 40 | ) |
|
41 | ||
|
42 | ||
|
43 | class RepoIntegrationOptionsSchema(IntegrationOptionsSchemaBase): | |
|
44 | pass | |
|
45 | ||
|
46 | ||
|
47 | class RepoGroupIntegrationOptionsSchema(IntegrationOptionsSchemaBase): | |
|
48 | child_repos_only = colander.SchemaNode( | |
|
49 | colander.Bool(), | |
|
50 | default=True, | |
|
51 | description=_( | |
|
52 | 'Limit integrations to to work only on the direct children ' | |
|
53 | 'repositories of this repository group (no subgroups)'), | |
|
54 | missing=False, | |
|
55 | title=_('Limit to childen repos only'), | |
|
56 | ) | |
|
57 | ||
|
58 | ||
|
59 | class GlobalIntegrationOptionsSchema(IntegrationOptionsSchemaBase): | |
|
60 | child_repos_only = colander.SchemaNode( | |
|
61 | colander.Bool(), | |
|
62 | default=False, | |
|
63 | description=_( | |
|
64 | 'Limit integrations to to work only on root level repositories'), | |
|
65 | missing=False, | |
|
66 | title=_('Root repositories only'), | |
|
67 | ) | |
|
68 | ||
|
69 | ||
|
70 | class IntegrationSettingsSchemaBase(colander.MappingSchema): | |
|
71 | pass |
@@ -18,25 +18,84 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | from rhodecode.integrations.schema import IntegrationSettingsSchemaBase | |
|
21 | import colander | |
|
22 | from rhodecode.translation import _ | |
|
22 | 23 | |
|
23 | 24 | |
|
24 | 25 | class IntegrationTypeBase(object): |
|
25 | 26 | """ Base class for IntegrationType plugins """ |
|
26 | 27 | |
|
28 | description = '' | |
|
29 | icon = ''' | |
|
30 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
|
31 | <svg | |
|
32 | xmlns:dc="http://purl.org/dc/elements/1.1/" | |
|
33 | xmlns:cc="http://creativecommons.org/ns#" | |
|
34 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
|
35 | xmlns:svg="http://www.w3.org/2000/svg" | |
|
36 | xmlns="http://www.w3.org/2000/svg" | |
|
37 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
|
38 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
|
39 | viewBox="0 -256 1792 1792" | |
|
40 | id="svg3025" | |
|
41 | version="1.1" | |
|
42 | inkscape:version="0.48.3.1 r9886" | |
|
43 | width="100%" | |
|
44 | height="100%" | |
|
45 | sodipodi:docname="cog_font_awesome.svg"> | |
|
46 | <metadata | |
|
47 | id="metadata3035"> | |
|
48 | <rdf:RDF> | |
|
49 | <cc:Work | |
|
50 | rdf:about=""> | |
|
51 | <dc:format>image/svg+xml</dc:format> | |
|
52 | <dc:type | |
|
53 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |
|
54 | </cc:Work> | |
|
55 | </rdf:RDF> | |
|
56 | </metadata> | |
|
57 | <defs | |
|
58 | id="defs3033" /> | |
|
59 | <sodipodi:namedview | |
|
60 | pagecolor="#ffffff" | |
|
61 | bordercolor="#666666" | |
|
62 | borderopacity="1" | |
|
63 | objecttolerance="10" | |
|
64 | gridtolerance="10" | |
|
65 | guidetolerance="10" | |
|
66 | inkscape:pageopacity="0" | |
|
67 | inkscape:pageshadow="2" | |
|
68 | inkscape:window-width="640" | |
|
69 | inkscape:window-height="480" | |
|
70 | id="namedview3031" | |
|
71 | showgrid="false" | |
|
72 | inkscape:zoom="0.13169643" | |
|
73 | inkscape:cx="896" | |
|
74 | inkscape:cy="896" | |
|
75 | inkscape:window-x="0" | |
|
76 | inkscape:window-y="25" | |
|
77 | inkscape:window-maximized="0" | |
|
78 | inkscape:current-layer="svg3025" /> | |
|
79 | <g | |
|
80 | transform="matrix(1,0,0,-1,121.49153,1285.4237)" | |
|
81 | id="g3027"> | |
|
82 | <path | |
|
83 | d="m 1024,640 q 0,106 -75,181 -75,75 -181,75 -106,0 -181,-75 -75,-75 -75,-181 0,-106 75,-181 75,-75 181,-75 106,0 181,75 75,75 75,181 z m 512,109 V 527 q 0,-12 -8,-23 -8,-11 -20,-13 l -185,-28 q -19,-54 -39,-91 35,-50 107,-138 10,-12 10,-25 0,-13 -9,-23 -27,-37 -99,-108 -72,-71 -94,-71 -12,0 -26,9 l -138,108 q -44,-23 -91,-38 -16,-136 -29,-186 -7,-28 -36,-28 H 657 q -14,0 -24.5,8.5 Q 622,-111 621,-98 L 593,86 q -49,16 -90,37 L 362,16 Q 352,7 337,7 323,7 312,18 186,132 147,186 q -7,10 -7,23 0,12 8,23 15,21 51,66.5 36,45.5 54,70.5 -27,50 -41,99 L 29,495 Q 16,497 8,507.5 0,518 0,531 v 222 q 0,12 8,23 8,11 19,13 l 186,28 q 14,46 39,92 -40,57 -107,138 -10,12 -10,24 0,10 9,23 26,36 98.5,107.5 72.5,71.5 94.5,71.5 13,0 26,-10 l 138,-107 q 44,23 91,38 16,136 29,186 7,28 36,28 h 222 q 14,0 24.5,-8.5 Q 914,1391 915,1378 l 28,-184 q 49,-16 90,-37 l 142,107 q 9,9 24,9 13,0 25,-10 129,-119 165,-170 7,-8 7,-22 0,-12 -8,-23 -15,-21 -51,-66.5 -36,-45.5 -54,-70.5 26,-50 41,-98 l 183,-28 q 13,-2 21,-12.5 8,-10.5 8,-23.5 z" | |
|
84 | id="path3029" | |
|
85 | inkscape:connector-curvature="0" | |
|
86 | style="fill:currentColor" /> | |
|
87 | </g> | |
|
88 | </svg> | |
|
89 | ''' | |
|
90 | ||
|
27 | 91 | def __init__(self, settings): |
|
28 | 92 | """ |
|
29 | 93 | :param settings: dict of settings to be used for the integration |
|
30 | 94 | """ |
|
31 | 95 | self.settings = settings |
|
32 | 96 | |
|
33 | ||
|
34 | 97 | def settings_schema(self): |
|
35 | 98 | """ |
|
36 | 99 | A colander schema of settings for the integration type |
|
37 | ||
|
38 | Subclasses can return their own schema but should always | |
|
39 | inherit from IntegrationSettingsSchemaBase | |
|
40 | 100 | """ |
|
41 |
return |
|
|
42 | ||
|
101 | return colander.Schema() |
@@ -26,11 +26,10 b' import colander' | |||
|
26 | 26 | from mako.template import Template |
|
27 | 27 | |
|
28 | 28 | from rhodecode import events |
|
29 |
from rhodecode.translation import _ |
|
|
29 | from rhodecode.translation import _ | |
|
30 | 30 | from rhodecode.lib.celerylib import run_task |
|
31 | 31 | from rhodecode.lib.celerylib import tasks |
|
32 | 32 | from rhodecode.integrations.types.base import IntegrationTypeBase |
|
33 | from rhodecode.integrations.schema import IntegrationSettingsSchemaBase | |
|
34 | 33 | |
|
35 | 34 | |
|
36 | 35 | log = logging.getLogger(__name__) |
@@ -147,18 +146,79 b" repo_push_template_html = Template('''" | |||
|
147 | 146 | </html> |
|
148 | 147 | ''') |
|
149 | 148 | |
|
149 | email_icon = ''' | |
|
150 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
|
151 | <svg | |
|
152 | xmlns:dc="http://purl.org/dc/elements/1.1/" | |
|
153 | xmlns:cc="http://creativecommons.org/ns#" | |
|
154 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
|
155 | xmlns:svg="http://www.w3.org/2000/svg" | |
|
156 | xmlns="http://www.w3.org/2000/svg" | |
|
157 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
|
158 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
|
159 | viewBox="0 -256 1850 1850" | |
|
160 | id="svg2989" | |
|
161 | version="1.1" | |
|
162 | inkscape:version="0.48.3.1 r9886" | |
|
163 | width="100%" | |
|
164 | height="100%" | |
|
165 | sodipodi:docname="envelope_font_awesome.svg"> | |
|
166 | <metadata | |
|
167 | id="metadata2999"> | |
|
168 | <rdf:RDF> | |
|
169 | <cc:Work | |
|
170 | rdf:about=""> | |
|
171 | <dc:format>image/svg+xml</dc:format> | |
|
172 | <dc:type | |
|
173 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |
|
174 | </cc:Work> | |
|
175 | </rdf:RDF> | |
|
176 | </metadata> | |
|
177 | <defs | |
|
178 | id="defs2997" /> | |
|
179 | <sodipodi:namedview | |
|
180 | pagecolor="#ffffff" | |
|
181 | bordercolor="#666666" | |
|
182 | borderopacity="1" | |
|
183 | objecttolerance="10" | |
|
184 | gridtolerance="10" | |
|
185 | guidetolerance="10" | |
|
186 | inkscape:pageopacity="0" | |
|
187 | inkscape:pageshadow="2" | |
|
188 | inkscape:window-width="640" | |
|
189 | inkscape:window-height="480" | |
|
190 | id="namedview2995" | |
|
191 | showgrid="false" | |
|
192 | inkscape:zoom="0.13169643" | |
|
193 | inkscape:cx="896" | |
|
194 | inkscape:cy="896" | |
|
195 | inkscape:window-x="0" | |
|
196 | inkscape:window-y="25" | |
|
197 | inkscape:window-maximized="0" | |
|
198 | inkscape:current-layer="svg2989" /> | |
|
199 | <g | |
|
200 | transform="matrix(1,0,0,-1,37.966102,1282.678)" | |
|
201 | id="g2991"> | |
|
202 | <path | |
|
203 | d="m 1664,32 v 768 q -32,-36 -69,-66 -268,-206 -426,-338 -51,-43 -83,-67 -32,-24 -86.5,-48.5 Q 945,256 897,256 h -1 -1 Q 847,256 792.5,280.5 738,305 706,329 674,353 623,396 465,528 197,734 160,764 128,800 V 32 Q 128,19 137.5,9.5 147,0 160,0 h 1472 q 13,0 22.5,9.5 9.5,9.5 9.5,22.5 z m 0,1051 v 11 13.5 q 0,0 -0.5,13 -0.5,13 -3,12.5 -2.5,-0.5 -5.5,9 -3,9.5 -9,7.5 -6,-2 -14,2.5 H 160 q -13,0 -22.5,-9.5 Q 128,1133 128,1120 128,952 275,836 468,684 676,519 682,514 711,489.5 740,465 757,452 774,439 801.5,420.5 829,402 852,393 q 23,-9 43,-9 h 1 1 q 20,0 43,9 23,9 50.5,27.5 27.5,18.5 44.5,31.5 17,13 46,37.5 29,24.5 35,29.5 208,165 401,317 54,43 100.5,115.5 46.5,72.5 46.5,131.5 z m 128,37 V 32 q 0,-66 -47,-113 -47,-47 -113,-47 H 160 Q 94,-128 47,-81 0,-34 0,32 v 1088 q 0,66 47,113 47,47 113,47 h 1472 q 66,0 113,-47 47,-47 47,-113 z" | |
|
204 | id="path2993" | |
|
205 | inkscape:connector-curvature="0" | |
|
206 | style="fill:currentColor" /> | |
|
207 | </g> | |
|
208 | </svg> | |
|
209 | ''' | |
|
150 | 210 | |
|
151 |
class EmailSettingsSchema( |
|
|
211 | class EmailSettingsSchema(colander.Schema): | |
|
152 | 212 | @colander.instantiate(validator=colander.Length(min=1)) |
|
153 | 213 | class recipients(colander.SequenceSchema): |
|
154 |
title = |
|
|
155 |
description = |
|
|
214 | title = _('Recipients') | |
|
215 | description = _('Email addresses to send push events to') | |
|
156 | 216 | widget = deform.widget.SequenceWidget(min_len=1) |
|
157 | 217 | |
|
158 | 218 | recipient = colander.SchemaNode( |
|
159 | 219 | colander.String(), |
|
160 |
title= |
|
|
161 |
description= |
|
|
220 | title=_('Email address'), | |
|
221 | description=_('Email address'), | |
|
162 | 222 | default='', |
|
163 | 223 | validator=colander.Email(), |
|
164 | 224 | widget=deform.widget.TextInputWidget( |
@@ -169,8 +229,9 b' class EmailSettingsSchema(IntegrationSet' | |||
|
169 | 229 | |
|
170 | 230 | class EmailIntegrationType(IntegrationTypeBase): |
|
171 | 231 | key = 'email' |
|
172 |
display_name = |
|
|
173 | SettingsSchema = EmailSettingsSchema | |
|
232 | display_name = _('Email') | |
|
233 | description = _('Send repo push summaries to a list of recipients via email') | |
|
234 | icon = email_icon | |
|
174 | 235 | |
|
175 | 236 | def settings_schema(self): |
|
176 | 237 | schema = EmailSettingsSchema() |
@@ -29,29 +29,28 b' from celery.task import task' | |||
|
29 | 29 | from mako.template import Template |
|
30 | 30 | |
|
31 | 31 | from rhodecode import events |
|
32 |
from rhodecode.translation import |
|
|
32 | from rhodecode.translation import _ | |
|
33 | 33 | from rhodecode.lib import helpers as h |
|
34 | 34 | from rhodecode.lib.celerylib import run_task |
|
35 | 35 | from rhodecode.lib.colander_utils import strip_whitespace |
|
36 | 36 | from rhodecode.integrations.types.base import IntegrationTypeBase |
|
37 | from rhodecode.integrations.schema import IntegrationSettingsSchemaBase | |
|
38 | 37 | |
|
39 | 38 | log = logging.getLogger(__name__) |
|
40 | 39 | |
|
41 | 40 | |
|
42 |
class HipchatSettingsSchema( |
|
|
41 | class HipchatSettingsSchema(colander.Schema): | |
|
43 | 42 | color_choices = [ |
|
44 |
('yellow', |
|
|
45 |
('red', |
|
|
46 |
('green', |
|
|
47 |
('purple', |
|
|
48 |
('gray', |
|
|
43 | ('yellow', _('Yellow')), | |
|
44 | ('red', _('Red')), | |
|
45 | ('green', _('Green')), | |
|
46 | ('purple', _('Purple')), | |
|
47 | ('gray', _('Gray')), | |
|
49 | 48 | ] |
|
50 | 49 | |
|
51 | 50 | server_url = colander.SchemaNode( |
|
52 | 51 | colander.String(), |
|
53 |
title= |
|
|
54 |
description= |
|
|
52 | title=_('Hipchat server URL'), | |
|
53 | description=_('Hipchat integration url.'), | |
|
55 | 54 | default='', |
|
56 | 55 | preparer=strip_whitespace, |
|
57 | 56 | validator=colander.url, |
@@ -61,15 +60,15 b' class HipchatSettingsSchema(IntegrationS' | |||
|
61 | 60 | ) |
|
62 | 61 | notify = colander.SchemaNode( |
|
63 | 62 | colander.Bool(), |
|
64 |
title= |
|
|
65 |
description= |
|
|
63 | title=_('Notify'), | |
|
64 | description=_('Make a notification to the users in room.'), | |
|
66 | 65 | missing=False, |
|
67 | 66 | default=False, |
|
68 | 67 | ) |
|
69 | 68 | color = colander.SchemaNode( |
|
70 | 69 | colander.String(), |
|
71 |
title= |
|
|
72 |
description= |
|
|
70 | title=_('Color'), | |
|
71 | description=_('Background color of message.'), | |
|
73 | 72 | missing='', |
|
74 | 73 | validator=colander.OneOf([x[0] for x in color_choices]), |
|
75 | 74 | widget=deform.widget.Select2Widget( |
@@ -79,29 +78,28 b' class HipchatSettingsSchema(IntegrationS' | |||
|
79 | 78 | |
|
80 | 79 | |
|
81 | 80 | repo_push_template = Template(''' |
|
82 | <b>${data['actor']['username']}</b> pushed to | |
|
83 | %if data['push']['branches']: | |
|
84 | ${len(data['push']['branches']) > 1 and 'branches' or 'branch'} | |
|
85 | ${', '.join('<a href="%s">%s</a>' % (branch['url'], branch['name']) for branch in data['push']['branches'])} | |
|
86 | %else: | |
|
87 | unknown branch | |
|
88 | %endif | |
|
89 | in <a href="${data['repo']['url']}">${data['repo']['repo_name']}</a> | |
|
81 | <b>${data['actor']['username']}</b> pushed to repo <a href="${data['repo']['url']}">${data['repo']['repo_name']}</a>: | |
|
90 | 82 | <br> |
|
91 | 83 | <ul> |
|
92 | %for commit in data['push']['commits']: | |
|
84 | %for branch, branch_commits in branches_commits.items(): | |
|
93 | 85 | <li> |
|
94 | <a href="${commit['url']}">${commit['short_id']}</a> - ${commit['message_html']} | |
|
86 | <a href="${branch_commits['branch']['url']}">branch: ${branch_commits['branch']['name']}</a> | |
|
87 | <ul> | |
|
88 | %for commit in branch_commits['commits']: | |
|
89 | <li><a href="${commit['url']}">${commit['short_id']}</a> - ${commit['message_html']}</li> | |
|
90 | %endfor | |
|
91 | </ul> | |
|
95 | 92 | </li> |
|
96 | 93 | %endfor |
|
97 | </ul> | |
|
98 | 94 | ''') |
|
99 | 95 | |
|
100 | 96 | |
|
101 | ||
|
102 | 97 | class HipchatIntegrationType(IntegrationTypeBase): |
|
103 | 98 | key = 'hipchat' |
|
104 |
display_name = |
|
|
99 | display_name = _('Hipchat') | |
|
100 | description = _('Send events such as repo pushes and pull requests to ' | |
|
101 | 'your hipchat channel.') | |
|
102 | icon = '''<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve"><g><g transform="translate(0.000000,511.000000) scale(0.100000,-0.100000)"><path fill="#205281" d="M4197.1,4662.4c-1661.5-260.4-3018-1171.6-3682.6-2473.3C219.9,1613.6,100,1120.3,100,462.6c0-1014,376.8-1918.4,1127-2699.4C2326.7-3377.6,3878.5-3898.3,5701-3730.5l486.5,44.5l208.9-123.3c637.2-373.4,1551.8-640.6,2240.4-650.9c304.9-6.9,335.7,0,417.9,75.4c185,174.7,147.3,411.1-89.1,548.1c-315.2,181.6-620,544.7-733.1,870.1l-51.4,157.6l472.7,472.7c349.4,349.4,520.7,551.5,657.7,774.2c784.5,1281.2,784.5,2788.5,0,4052.6c-236.4,376.8-794.8,966-1178.4,1236.7c-572.1,407.7-1264.1,709.1-1993.7,870.1c-267.2,58.2-479.6,75.4-1038,82.2C4714.4,4686.4,4310.2,4679.6,4197.1,4662.4z M5947.6,3740.9c1856.7-380.3,3127.6-1709.4,3127.6-3275c0-1000.3-534.4-1949.2-1466.2-2600.1c-188.4-133.6-287.8-226.1-301.5-284.4c-41.1-157.6,263.8-938.6,397.4-1020.8c20.5-10.3,34.3-44.5,34.3-75.4c0-167.8-811.9,195.3-1363.4,609.8l-181.6,137l-332.3-58.2c-445.3-78.8-1281.2-78.8-1702.6,0C2796-2569.2,1734.1-1832.6,1220.2-801.5C983.8-318.5,905,51.5,929,613.3c27.4,640.6,243.2,1192.1,685.1,1740.3c620,770.8,1661.5,1305.2,2822.8,1452.5C4806.9,3854,5553.7,3819.7,5947.6,3740.9z"/><path fill="#205281" d="M2381.5-345.9c-75.4-106.2-68.5-167.8,34.3-322c332.3-500.2,1010.6-928.4,1760.8-1120.2c417.9-106.2,1226.4-106.2,1644.3,0c712.5,181.6,1270.9,517.3,1685.4,1014C7681-561.7,7715.3-424.7,7616-325.4c-89.1,89.1-167.9,65.1-431.7-133.6c-835.8-630.3-2028-856.4-3086.5-585.8C3683.3-938.6,3142-685,2830.3-448.7C2576.8-253.4,2463.7-229.4,2381.5-345.9z"/></g></g><!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon --></svg>''' | |
|
105 | 103 | valid_events = [ |
|
106 | 104 | events.PullRequestCloseEvent, |
|
107 | 105 | events.PullRequestMergeEvent, |
@@ -217,8 +215,23 b' class HipchatIntegrationType(Integration' | |||
|
217 | 215 | ) |
|
218 | 216 | |
|
219 | 217 | def format_repo_push_event(self, data): |
|
218 | branch_data = {branch['name']: branch | |
|
219 | for branch in data['push']['branches']} | |
|
220 | ||
|
221 | branches_commits = {} | |
|
222 | for commit in data['push']['commits']: | |
|
223 | log.critical(commit) | |
|
224 | if commit['branch'] not in branches_commits: | |
|
225 | branch_commits = {'branch': branch_data[commit['branch']], | |
|
226 | 'commits': []} | |
|
227 | branches_commits[commit['branch']] = branch_commits | |
|
228 | ||
|
229 | branch_commits = branches_commits[commit['branch']] | |
|
230 | branch_commits['commits'].append(commit) | |
|
231 | ||
|
220 | 232 | result = repo_push_template.render( |
|
221 | 233 | data=data, |
|
234 | branches_commits=branches_commits, | |
|
222 | 235 | ) |
|
223 | 236 | return result |
|
224 | 237 |
@@ -29,21 +29,20 b' from celery.task import task' | |||
|
29 | 29 | from mako.template import Template |
|
30 | 30 | |
|
31 | 31 | from rhodecode import events |
|
32 |
from rhodecode.translation import |
|
|
32 | from rhodecode.translation import _ | |
|
33 | 33 | from rhodecode.lib import helpers as h |
|
34 | 34 | from rhodecode.lib.celerylib import run_task |
|
35 | 35 | from rhodecode.lib.colander_utils import strip_whitespace |
|
36 | 36 | from rhodecode.integrations.types.base import IntegrationTypeBase |
|
37 | from rhodecode.integrations.schema import IntegrationSettingsSchemaBase | |
|
38 | 37 | |
|
39 | 38 | log = logging.getLogger(__name__) |
|
40 | 39 | |
|
41 | 40 | |
|
42 |
class SlackSettingsSchema( |
|
|
41 | class SlackSettingsSchema(colander.Schema): | |
|
43 | 42 | service = colander.SchemaNode( |
|
44 | 43 | colander.String(), |
|
45 |
title= |
|
|
46 |
description=h.literal( |
|
|
44 | title=_('Slack service URL'), | |
|
45 | description=h.literal(_( | |
|
47 | 46 | 'This can be setup at the ' |
|
48 | 47 | '<a href="https://my.slack.com/services/new/incoming-webhook/">' |
|
49 | 48 | 'slack app manager</a>')), |
@@ -56,8 +55,8 b' class SlackSettingsSchema(IntegrationSet' | |||
|
56 | 55 | ) |
|
57 | 56 | username = colander.SchemaNode( |
|
58 | 57 | colander.String(), |
|
59 |
title= |
|
|
60 |
description= |
|
|
58 | title=_('Username'), | |
|
59 | description=_('Username to show notifications coming from.'), | |
|
61 | 60 | missing='Rhodecode', |
|
62 | 61 | preparer=strip_whitespace, |
|
63 | 62 | widget=deform.widget.TextInputWidget( |
@@ -66,8 +65,8 b' class SlackSettingsSchema(IntegrationSet' | |||
|
66 | 65 | ) |
|
67 | 66 | channel = colander.SchemaNode( |
|
68 | 67 | colander.String(), |
|
69 |
title= |
|
|
70 |
description= |
|
|
68 | title=_('Channel'), | |
|
69 | description=_('Channel to send notifications to.'), | |
|
71 | 70 | missing='', |
|
72 | 71 | preparer=strip_whitespace, |
|
73 | 72 | widget=deform.widget.TextInputWidget( |
@@ -76,8 +75,8 b' class SlackSettingsSchema(IntegrationSet' | |||
|
76 | 75 | ) |
|
77 | 76 | icon_emoji = colander.SchemaNode( |
|
78 | 77 | colander.String(), |
|
79 |
title= |
|
|
80 |
description= |
|
|
78 | title=_('Emoji'), | |
|
79 | description=_('Emoji to use eg. :studio_microphone:'), | |
|
81 | 80 | missing='', |
|
82 | 81 | preparer=strip_whitespace, |
|
83 | 82 | widget=deform.widget.TextInputWidget( |
@@ -87,25 +86,22 b' class SlackSettingsSchema(IntegrationSet' | |||
|
87 | 86 | |
|
88 | 87 | |
|
89 | 88 | repo_push_template = Template(r''' |
|
90 | *${data['actor']['username']}* pushed to \ | |
|
91 | %if data['push']['branches']: | |
|
92 | ${len(data['push']['branches']) > 1 and 'branches' or 'branch'} \ | |
|
93 | ${', '.join('<%s|%s>' % (branch['url'], branch['name']) for branch in data['push']['branches'])} \ | |
|
94 | %else: | |
|
95 | unknown branch \ | |
|
96 | %endif | |
|
97 | in <${data['repo']['url']}|${data['repo']['repo_name']}> | |
|
98 | >>> | |
|
99 | %for commit in data['push']['commits']: | |
|
100 | <${commit['url']}|${commit['short_id']}> - ${commit['message_html']|html_to_slack_links} | |
|
89 | *${data['actor']['username']}* pushed to repo <${data['repo']['url']}|${data['repo']['repo_name']}>: | |
|
90 | %for branch, branch_commits in branches_commits.items(): | |
|
91 | branch: <${branch_commits['branch']['url']}|${branch_commits['branch']['name']}> | |
|
92 | %for commit in branch_commits['commits']: | |
|
93 | > <${commit['url']}|${commit['short_id']}> - ${commit['message_html']|html_to_slack_links} | |
|
94 | %endfor | |
|
101 | 95 | %endfor |
|
102 | 96 | ''') |
|
103 | 97 | |
|
104 | 98 | |
|
105 | 99 | class SlackIntegrationType(IntegrationTypeBase): |
|
106 | 100 | key = 'slack' |
|
107 |
display_name = |
|
|
108 | SettingsSchema = SlackSettingsSchema | |
|
101 | display_name = _('Slack') | |
|
102 | description = _('Send events such as repo pushes and pull requests to ' | |
|
103 | 'your slack channel.') | |
|
104 | icon = '''<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid"><g><path d="M165.963541,15.8384262 C162.07318,3.86308197 149.212328,-2.69009836 137.239082,1.20236066 C125.263738,5.09272131 118.710557,17.9535738 122.603016,29.9268197 L181.550164,211.292328 C185.597902,222.478689 197.682361,228.765377 209.282098,225.426885 C221.381246,221.943607 228.756984,209.093246 224.896,197.21023 C224.749115,196.756984 165.963541,15.8384262 165.963541,15.8384262" fill="#DFA22F"></path><path d="M74.6260984,45.515541 C70.7336393,33.5422951 57.8727869,26.9891148 45.899541,30.8794754 C33.9241967,34.7698361 27.3710164,47.6306885 31.2634754,59.6060328 L90.210623,240.971541 C94.2583607,252.157902 106.34282,258.44459 117.942557,255.104 C130.041705,251.62282 137.417443,238.772459 133.556459,226.887344 C133.409574,226.436197 74.6260984,45.515541 74.6260984,45.515541" fill="#3CB187"></path><path d="M240.161574,166.045377 C252.136918,162.155016 258.688,149.294164 254.797639,137.31882 C250.907279,125.345574 238.046426,118.792393 226.07318,122.682754 L44.7076721,181.632 C33.5213115,185.677639 27.234623,197.762098 30.5731148,209.361836 C34.0563934,221.460984 46.9067541,228.836721 58.7897705,224.975738 C59.2430164,224.828852 240.161574,166.045377 240.161574,166.045377" fill="#CE1E5B"></path><path d="M82.507541,217.270557 C94.312918,213.434754 109.528131,208.491016 125.855475,203.186361 C122.019672,191.380984 117.075934,176.163672 111.76918,159.83423 L68.4191475,173.924721 L82.507541,217.270557" fill="#392538"></path><path d="M173.847082,187.591344 C190.235279,182.267803 205.467279,177.31777 217.195016,173.507148 C213.359213,161.70177 208.413377,146.480262 203.106623,130.146623 L159.75659,144.237115 L173.847082,187.591344" fill="#BB242A"></path><path d="M210.484459,74.7058361 C222.457705,70.8154754 229.010885,57.954623 225.120525,45.9792787 C221.230164,34.0060328 208.369311,27.4528525 196.393967,31.3432131 L15.028459,90.292459 C3.84209836,94.3380984 -2.44459016,106.422557 0.896,118.022295 C4.37718033,130.121443 17.227541,137.49718 29.1126557,133.636197 C29.5638033,133.489311 210.484459,74.7058361 210.484459,74.7058361" fill="#72C5CD"></path><path d="M52.8220328,125.933115 C64.6274098,122.097311 79.8468197,117.151475 96.1762623,111.84682 C90.8527213,95.4565246 85.9026885,80.2245246 82.0920656,68.4946885 L38.731541,82.5872787 L52.8220328,125.933115" fill="#248C73"></path><path d="M144.159475,96.256 C160.551869,90.9303607 175.785967,85.9803279 187.515803,82.1676066 C182.190164,65.7752131 177.240131,50.5390164 173.42741,38.807082 L130.068984,52.8996721 L144.159475,96.256" fill="#62803A"></path></g></svg>''' | |
|
109 | 105 | valid_events = [ |
|
110 | 106 | events.PullRequestCloseEvent, |
|
111 | 107 | events.PullRequestMergeEvent, |
@@ -221,8 +217,23 b' class SlackIntegrationType(IntegrationTy' | |||
|
221 | 217 | ) |
|
222 | 218 | |
|
223 | 219 | def format_repo_push_event(self, data): |
|
220 | branch_data = {branch['name']: branch | |
|
221 | for branch in data['push']['branches']} | |
|
222 | ||
|
223 | branches_commits = {} | |
|
224 | for commit in data['push']['commits']: | |
|
225 | log.critical(commit) | |
|
226 | if commit['branch'] not in branches_commits: | |
|
227 | branch_commits = {'branch': branch_data[commit['branch']], | |
|
228 | 'commits': []} | |
|
229 | branches_commits[commit['branch']] = branch_commits | |
|
230 | ||
|
231 | branch_commits = branches_commits[commit['branch']] | |
|
232 | branch_commits['commits'].append(commit) | |
|
233 | ||
|
224 | 234 | result = repo_push_template.render( |
|
225 | 235 | data=data, |
|
236 | branches_commits=branches_commits, | |
|
226 | 237 | html_to_slack_links=html_to_slack_links, |
|
227 | 238 | ) |
|
228 | 239 | return result |
@@ -28,19 +28,19 b' from celery.task import task' | |||
|
28 | 28 | from mako.template import Template |
|
29 | 29 | |
|
30 | 30 | from rhodecode import events |
|
31 |
from rhodecode.translation import |
|
|
31 | from rhodecode.translation import _ | |
|
32 | 32 | from rhodecode.integrations.types.base import IntegrationTypeBase |
|
33 | from rhodecode.integrations.schema import IntegrationSettingsSchemaBase | |
|
34 | 33 | |
|
35 | 34 | log = logging.getLogger(__name__) |
|
36 | 35 | |
|
37 | 36 | |
|
38 |
class WebhookSettingsSchema( |
|
|
37 | class WebhookSettingsSchema(colander.Schema): | |
|
39 | 38 | url = colander.SchemaNode( |
|
40 | 39 | colander.String(), |
|
41 |
title= |
|
|
42 |
description= |
|
|
43 | default='', | |
|
40 | title=_('Webhook URL'), | |
|
41 | description=_('URL of the webhook to receive POST event.'), | |
|
42 | missing=colander.required, | |
|
43 | required=True, | |
|
44 | 44 | validator=colander.url, |
|
45 | 45 | widget=deform.widget.TextInputWidget( |
|
46 | 46 | placeholder='https://www.example.com/webhook' |
@@ -48,18 +48,24 b' class WebhookSettingsSchema(IntegrationS' | |||
|
48 | 48 | ) |
|
49 | 49 | secret_token = colander.SchemaNode( |
|
50 | 50 | colander.String(), |
|
51 |
title= |
|
|
52 |
description= |
|
|
51 | title=_('Secret Token'), | |
|
52 | description=_('String used to validate received payloads.'), | |
|
53 | 53 | default='', |
|
54 | missing='', | |
|
54 | 55 | widget=deform.widget.TextInputWidget( |
|
55 | 56 | placeholder='secret_token' |
|
56 | 57 | ), |
|
57 | 58 | ) |
|
58 | 59 | |
|
59 | 60 | |
|
61 | ||
|
62 | ||
|
60 | 63 | class WebhookIntegrationType(IntegrationTypeBase): |
|
61 | 64 | key = 'webhook' |
|
62 |
display_name = |
|
|
65 | display_name = _('Webhook') | |
|
66 | description = _('Post json events to a webhook endpoint') | |
|
67 | icon = '''<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg viewBox="0 0 256 239" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid"><g><path d="M119.540432,100.502743 C108.930124,118.338815 98.7646301,135.611455 88.3876025,152.753617 C85.7226696,157.154315 84.4040417,160.738531 86.5332204,166.333309 C92.4107024,181.787152 84.1193605,196.825836 68.5350381,200.908244 C53.8383677,204.759349 39.5192953,195.099955 36.6032893,179.365384 C34.0194114,165.437749 44.8274148,151.78491 60.1824106,149.608284 C61.4694072,149.424428 62.7821041,149.402681 64.944891,149.240571 C72.469175,136.623655 80.1773157,123.700312 88.3025935,110.073173 C73.611854,95.4654658 64.8677898,78.3885437 66.803227,57.2292132 C68.1712787,42.2715849 74.0527146,29.3462646 84.8033863,18.7517722 C105.393354,-1.53572199 136.805164,-4.82141828 161.048542,10.7510424 C184.333097,25.7086706 194.996783,54.8450075 185.906752,79.7822957 C179.052655,77.9239597 172.151111,76.049808 164.563565,73.9917997 C167.418285,60.1274266 165.306899,47.6765751 155.95591,37.0109123 C149.777932,29.9690049 141.850349,26.2780332 132.835442,24.9178894 C114.764113,22.1877169 97.0209573,33.7983633 91.7563309,51.5355878 C85.7800012,71.6669027 94.8245623,88.1111998 119.540432,100.502743 L119.540432,100.502743 Z" fill="#C73A63"></path><path d="M149.841194,79.4106285 C157.316054,92.5969067 164.905578,105.982857 172.427885,119.246236 C210.44865,107.483365 239.114472,128.530009 249.398582,151.063322 C261.81978,178.282014 253.328765,210.520191 228.933162,227.312431 C203.893073,244.551464 172.226236,241.605803 150.040866,219.46195 C155.694953,214.729124 161.376716,209.974552 167.44794,204.895759 C189.360489,219.088306 208.525074,218.420096 222.753207,201.614016 C234.885769,187.277151 234.622834,165.900356 222.138374,151.863988 C207.730339,135.66681 188.431321,135.172572 165.103273,150.721309 C155.426087,133.553447 145.58086,116.521995 136.210101,99.2295848 C133.05093,93.4015266 129.561608,90.0209366 122.440622,88.7873178 C110.547271,86.7253555 102.868785,76.5124151 102.408155,65.0698097 C101.955433,53.7537294 108.621719,43.5249733 119.04224,39.5394355 C129.363912,35.5914599 141.476705,38.7783085 148.419765,47.554004 C154.093621,54.7244134 155.896602,62.7943365 152.911402,71.6372484 C152.081082,74.1025091 151.00562,76.4886916 149.841194,79.4106285 L149.841194,79.4106285 Z" fill="#4B4B4B"></path><path d="M167.706921,187.209935 L121.936499,187.209935 C117.54964,205.253587 108.074103,219.821756 91.7464461,229.085759 C79.0544063,236.285822 65.3738898,238.72736 50.8136292,236.376762 C24.0061432,232.053165 2.08568567,207.920497 0.156179306,180.745298 C-2.02835403,149.962159 19.1309765,122.599149 47.3341915,116.452801 C49.2814904,123.524363 51.2485589,130.663141 53.1958579,137.716911 C27.3195169,150.919004 18.3639187,167.553089 25.6054984,188.352614 C31.9811726,206.657224 50.0900643,216.690262 69.7528413,212.809503 C89.8327554,208.847688 99.9567329,192.160226 98.7211371,165.37844 C117.75722,165.37844 136.809118,165.180745 155.847178,165.475311 C163.280522,165.591951 169.019617,164.820939 174.620326,158.267339 C183.840836,147.48306 200.811003,148.455721 210.741239,158.640984 C220.88894,169.049642 220.402609,185.79839 209.663799,195.768166 C199.302587,205.38802 182.933414,204.874012 173.240413,194.508846 C171.247644,192.37176 169.677943,189.835329 167.706921,187.209935 L167.706921,187.209935 Z" fill="#4A4A4A"></path></g></svg>''' | |
|
68 | ||
|
63 | 69 | valid_events = [ |
|
64 | 70 | events.PullRequestCloseEvent, |
|
65 | 71 | events.PullRequestMergeEvent, |
@@ -18,23 +18,29 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | import colander | |
|
22 | import logging | |
|
23 | 21 | import pylons |
|
24 | 22 | import deform |
|
23 | import logging | |
|
24 | import colander | |
|
25 | import peppercorn | |
|
26 | import webhelpers.paginate | |
|
25 | 27 | |
|
26 | from pyramid.httpexceptions import HTTPFound, HTTPForbidden | |
|
28 | from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest | |
|
27 | 29 | from pyramid.renderers import render |
|
28 | 30 | from pyramid.response import Response |
|
29 | 31 | |
|
30 | 32 | from rhodecode.lib import auth |
|
31 | 33 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
32 | from rhodecode.model.db import Repository, Session, Integration | |
|
34 | from rhodecode.lib.utils2 import safe_int | |
|
35 | from rhodecode.lib.helpers import Page | |
|
36 | from rhodecode.model.db import Repository, RepoGroup, Session, Integration | |
|
33 | 37 | from rhodecode.model.scm import ScmModel |
|
34 | 38 | from rhodecode.model.integration import IntegrationModel |
|
35 | 39 | from rhodecode.admin.navigation import navigation_list |
|
36 | 40 | from rhodecode.translation import _ |
|
37 | 41 | from rhodecode.integrations import integration_type_registry |
|
42 | from rhodecode.model.validation_schema.schemas.integration_schema import ( | |
|
43 | make_integration_schema, IntegrationScopeType) | |
|
38 | 44 | |
|
39 | 45 | log = logging.getLogger(__name__) |
|
40 | 46 | |
@@ -59,28 +65,51 b' class IntegrationSettingsViewBase(object' | |||
|
59 | 65 | |
|
60 | 66 | self.IntegrationType = None |
|
61 | 67 | self.repo = None |
|
68 | self.repo_group = None | |
|
62 | 69 | self.integration = None |
|
63 | 70 | self.integrations = {} |
|
64 | 71 | |
|
65 | 72 | request = self.request |
|
66 | 73 | |
|
67 |
if 'repo_name' in request.matchdict: # |
|
|
74 | if 'repo_name' in request.matchdict: # in repo settings context | |
|
68 | 75 | repo_name = request.matchdict['repo_name'] |
|
69 | 76 | self.repo = Repository.get_by_repo_name(repo_name) |
|
70 | 77 | |
|
71 |
if ' |
|
|
78 | if 'repo_group_name' in request.matchdict: # in group settings context | |
|
79 | repo_group_name = request.matchdict['repo_group_name'] | |
|
80 | self.repo_group = RepoGroup.get_by_group_name(repo_group_name) | |
|
81 | ||
|
82 | ||
|
83 | if 'integration' in request.matchdict: # integration type context | |
|
72 | 84 | integration_type = request.matchdict['integration'] |
|
73 | 85 | self.IntegrationType = integration_type_registry[integration_type] |
|
74 | 86 | |
|
75 | 87 | if 'integration_id' in request.matchdict: # single integration context |
|
76 | 88 | integration_id = request.matchdict['integration_id'] |
|
77 | 89 | self.integration = Integration.get(integration_id) |
|
78 | else: # list integrations context | |
|
79 | for integration in IntegrationModel().get_integrations(self.repo): | |
|
80 | self.integrations.setdefault(integration.integration_type, [] | |
|
81 | ).append(integration) | |
|
90 | ||
|
91 | # extra perms check just in case | |
|
92 | if not self._has_perms_for_integration(self.integration): | |
|
93 | raise HTTPForbidden() | |
|
82 | 94 | |
|
83 | 95 | self.settings = self.integration and self.integration.settings or {} |
|
96 | self.admin_view = not (self.repo or self.repo_group) | |
|
97 | ||
|
98 | def _has_perms_for_integration(self, integration): | |
|
99 | perms = self.request.user.permissions | |
|
100 | ||
|
101 | if 'hg.admin' in perms['global']: | |
|
102 | return True | |
|
103 | ||
|
104 | if integration.repo: | |
|
105 | return perms['repositories'].get( | |
|
106 | integration.repo.repo_name) == 'repository.admin' | |
|
107 | ||
|
108 | if integration.repo_group: | |
|
109 | return perms['repositories_groups'].get( | |
|
110 | integration.repo_group.group_name) == 'group.admin' | |
|
111 | ||
|
112 | return False | |
|
84 | 113 | |
|
85 | 114 | def _template_c_context(self): |
|
86 | 115 | # TODO: dan: this is a stopgap in order to inherit from current pylons |
@@ -91,7 +120,10 b' class IntegrationSettingsViewBase(object' | |||
|
91 | 120 | c.active = 'integrations' |
|
92 | 121 | c.rhodecode_user = self.request.user |
|
93 | 122 | c.repo = self.repo |
|
123 | c.repo_group = self.repo_group | |
|
94 | 124 | c.repo_name = self.repo and self.repo.repo_name or None |
|
125 | c.repo_group_name = self.repo_group and self.repo_group.group_name or None | |
|
126 | ||
|
95 | 127 | if self.repo: |
|
96 | 128 | c.repo_info = self.repo |
|
97 | 129 | c.rhodecode_db_repo = self.repo |
@@ -102,34 +134,77 b' class IntegrationSettingsViewBase(object' | |||
|
102 | 134 | return c |
|
103 | 135 | |
|
104 | 136 | def _form_schema(self): |
|
105 | if self.integration: | |
|
106 |
settings |
|
|
107 | else: | |
|
108 | settings = {} | |
|
109 | return self.IntegrationType(settings=settings).settings_schema() | |
|
137 | schema = make_integration_schema(IntegrationType=self.IntegrationType, | |
|
138 | settings=self.settings) | |
|
110 | 139 | |
|
111 | def settings_get(self, defaults=None, errors=None, form=None): | |
|
112 | """ | |
|
113 | View that displays the plugin settings as a form. | |
|
114 | """ | |
|
115 | defaults = defaults or {} | |
|
116 | errors = errors or {} | |
|
140 | # returns a clone, important if mutating the schema later | |
|
141 | return schema.bind( | |
|
142 | permissions=self.request.user.permissions, | |
|
143 | no_scope=not self.admin_view) | |
|
144 | ||
|
145 | ||
|
146 | def _form_defaults(self): | |
|
147 | defaults = {} | |
|
117 | 148 | |
|
118 | 149 | if self.integration: |
|
119 | defaults = self.integration.settings or {} | |
|
120 |
defaults[' |
|
|
121 |
|
|
|
150 | defaults['settings'] = self.integration.settings or {} | |
|
151 | defaults['options'] = { | |
|
152 | 'name': self.integration.name, | |
|
153 | 'enabled': self.integration.enabled, | |
|
154 | 'scope': { | |
|
155 | 'repo': self.integration.repo, | |
|
156 | 'repo_group': self.integration.repo_group, | |
|
157 | 'child_repos_only': self.integration.child_repos_only, | |
|
158 | }, | |
|
159 | } | |
|
122 | 160 | else: |
|
123 | 161 | if self.repo: |
|
124 |
scope = |
|
|
162 | scope = _('{repo_name} repository').format( | |
|
163 | repo_name=self.repo.repo_name) | |
|
164 | elif self.repo_group: | |
|
165 | scope = _('{repo_group_name} repo group').format( | |
|
166 | repo_group_name=self.repo_group.group_name) | |
|
125 | 167 | else: |
|
126 | 168 | scope = _('Global') |
|
127 | 169 | |
|
128 | defaults['name'] = '{} {} integration'.format(scope, | |
|
129 | self.IntegrationType.display_name) | |
|
130 | defaults['enabled'] = True | |
|
170 | defaults['options'] = { | |
|
171 | 'enabled': True, | |
|
172 | 'name': _('{name} integration').format( | |
|
173 | name=self.IntegrationType.display_name), | |
|
174 | } | |
|
175 | defaults['options']['scope'] = { | |
|
176 | 'repo': self.repo, | |
|
177 | 'repo_group': self.repo_group, | |
|
178 | } | |
|
179 | ||
|
180 | return defaults | |
|
131 | 181 | |
|
132 | schema = self._form_schema().bind(request=self.request) | |
|
182 | def _delete_integration(self, integration): | |
|
183 | Session().delete(self.integration) | |
|
184 | Session().commit() | |
|
185 | self.request.session.flash( | |
|
186 | _('Integration {integration_name} deleted successfully.').format( | |
|
187 | integration_name=self.integration.name), | |
|
188 | queue='success') | |
|
189 | ||
|
190 | if self.repo: | |
|
191 | redirect_to = self.request.route_url( | |
|
192 | 'repo_integrations_home', repo_name=self.repo.repo_name) | |
|
193 | elif self.repo_group: | |
|
194 | redirect_to = self.request.route_url( | |
|
195 | 'repo_group_integrations_home', | |
|
196 | repo_group_name=self.repo_group.group_name) | |
|
197 | else: | |
|
198 | redirect_to = self.request.route_url('global_integrations_home') | |
|
199 | raise HTTPFound(redirect_to) | |
|
200 | ||
|
201 | def settings_get(self, defaults=None, form=None): | |
|
202 | """ | |
|
203 | View that displays the integration settings as a form. | |
|
204 | """ | |
|
205 | ||
|
206 | defaults = defaults or self._form_defaults() | |
|
207 | schema = self._form_schema() | |
|
133 | 208 | |
|
134 | 209 | if self.integration: |
|
135 | 210 | buttons = ('submit', 'delete') |
@@ -138,23 +213,10 b' class IntegrationSettingsViewBase(object' | |||
|
138 | 213 | |
|
139 | 214 | form = form or deform.Form(schema, appstruct=defaults, buttons=buttons) |
|
140 | 215 | |
|
141 | for node in schema: | |
|
142 | setting = self.settings.get(node.name) | |
|
143 | if setting is not None: | |
|
144 | defaults.setdefault(node.name, setting) | |
|
145 | else: | |
|
146 | if node.default: | |
|
147 | defaults.setdefault(node.name, node.default) | |
|
148 | ||
|
149 | 216 | template_context = { |
|
150 | 217 | 'form': form, |
|
151 | 'defaults': defaults, | |
|
152 | 'errors': errors, | |
|
153 | 'schema': schema, | |
|
154 | 218 | 'current_IntegrationType': self.IntegrationType, |
|
155 | 219 | 'integration': self.integration, |
|
156 | 'settings': self.settings, | |
|
157 | 'resource': self.context, | |
|
158 | 220 | 'c': self._template_c_context(), |
|
159 | 221 | } |
|
160 | 222 | |
@@ -163,71 +225,93 b' class IntegrationSettingsViewBase(object' | |||
|
163 | 225 | @auth.CSRFRequired() |
|
164 | 226 | def settings_post(self): |
|
165 | 227 | """ |
|
166 |
View that validates and stores the |
|
|
228 | View that validates and stores the integration settings. | |
|
167 | 229 | """ |
|
168 | if self.request.params.get('delete'): | |
|
169 | Session().delete(self.integration) | |
|
170 | Session().commit() | |
|
171 | self.request.session.flash( | |
|
172 | _('Integration {integration_name} deleted successfully.').format( | |
|
173 | integration_name=self.integration.name), | |
|
174 | queue='success') | |
|
175 | if self.repo: | |
|
176 | redirect_to = self.request.route_url( | |
|
177 | 'repo_integrations_home', repo_name=self.repo.repo_name) | |
|
178 | else: | |
|
179 | redirect_to = self.request.route_url('global_integrations_home') | |
|
180 | raise HTTPFound(redirect_to) | |
|
230 | controls = self.request.POST.items() | |
|
231 | pstruct = peppercorn.parse(controls) | |
|
232 | ||
|
233 | if self.integration and pstruct.get('delete'): | |
|
234 | return self._delete_integration(self.integration) | |
|
235 | ||
|
236 | schema = self._form_schema() | |
|
237 | ||
|
238 | skip_settings_validation = False | |
|
239 | if self.integration and 'enabled' not in pstruct.get('options', {}): | |
|
240 | skip_settings_validation = True | |
|
241 | schema['settings'].validator = None | |
|
242 | for field in schema['settings'].children: | |
|
243 | field.validator = None | |
|
244 | field.missing = '' | |
|
181 | 245 | |
|
182 | schema = self._form_schema().bind(request=self.request) | |
|
246 | if self.integration: | |
|
247 | buttons = ('submit', 'delete') | |
|
248 | else: | |
|
249 | buttons = ('submit',) | |
|
183 | 250 | |
|
184 |
form = deform.Form(schema, buttons= |
|
|
251 | form = deform.Form(schema, buttons=buttons) | |
|
185 | 252 | |
|
186 | params = {} | |
|
187 | for node in schema.children: | |
|
188 | if type(node.typ) in (colander.Set, colander.List): | |
|
189 | val = self.request.params.getall(node.name) | |
|
190 | else: | |
|
191 | val = self.request.params.get(node.name) | |
|
192 | if val: | |
|
193 | params[node.name] = val | |
|
253 | if not self.admin_view: | |
|
254 | # scope is read only field in these cases, and has to be added | |
|
255 | options = pstruct.setdefault('options', {}) | |
|
256 | if 'scope' not in options: | |
|
257 | options['scope'] = IntegrationScopeType().serialize(None, { | |
|
258 | 'repo': self.repo, | |
|
259 | 'repo_group': self.repo_group, | |
|
260 | }) | |
|
194 | 261 | |
|
195 | controls = self.request.POST.items() | |
|
196 | 262 | try: |
|
197 |
valid_data = form.validate(c |
|
|
263 | valid_data = form.validate_pstruct(pstruct) | |
|
198 | 264 | except deform.ValidationFailure as e: |
|
199 | 265 | self.request.session.flash( |
|
200 | 266 | _('Errors exist when saving integration settings. ' |
|
201 | 267 | 'Please check the form inputs.'), |
|
202 | 268 | queue='error') |
|
203 |
return self.settings_get( |
|
|
269 | return self.settings_get(form=e) | |
|
204 | 270 | |
|
205 | 271 | if not self.integration: |
|
206 | 272 | self.integration = Integration() |
|
207 | 273 | self.integration.integration_type = self.IntegrationType.key |
|
208 | if self.repo: | |
|
209 | self.integration.repo = self.repo | |
|
210 | 274 | Session().add(self.integration) |
|
211 | 275 | |
|
212 | self.integration.enabled = valid_data.pop('enabled', False) | |
|
213 | self.integration.name = valid_data.pop('name') | |
|
214 | self.integration.settings = valid_data | |
|
276 | scope = valid_data['options']['scope'] | |
|
215 | 277 | |
|
278 | IntegrationModel().update_integration(self.integration, | |
|
279 | name=valid_data['options']['name'], | |
|
280 | enabled=valid_data['options']['enabled'], | |
|
281 | settings=valid_data['settings'], | |
|
282 | repo=scope['repo'], | |
|
283 | repo_group=scope['repo_group'], | |
|
284 | child_repos_only=scope['child_repos_only'], | |
|
285 | ) | |
|
286 | ||
|
287 | ||
|
288 | self.integration.settings = valid_data['settings'] | |
|
216 | 289 | Session().commit() |
|
217 | ||
|
218 | 290 | # Display success message and redirect. |
|
219 | 291 | self.request.session.flash( |
|
220 | 292 | _('Integration {integration_name} updated successfully.').format( |
|
221 | 293 | integration_name=self.IntegrationType.display_name), |
|
222 | 294 | queue='success') |
|
223 | 295 | |
|
224 | if self.repo: | |
|
225 | redirect_to = self.request.route_url( | |
|
226 | 'repo_integrations_edit', repo_name=self.repo.repo_name, | |
|
296 | ||
|
297 | # if integration scope changes, we must redirect to the right place | |
|
298 | # keeping in mind if the original view was for /repo/ or /_admin/ | |
|
299 | admin_view = not (self.repo or self.repo_group) | |
|
300 | ||
|
301 | if self.integration.repo and not admin_view: | |
|
302 | redirect_to = self.request.route_path( | |
|
303 | 'repo_integrations_edit', | |
|
304 | repo_name=self.integration.repo.repo_name, | |
|
305 | integration=self.integration.integration_type, | |
|
306 | integration_id=self.integration.integration_id) | |
|
307 | elif self.integration.repo_group and not admin_view: | |
|
308 | redirect_to = self.request.route_path( | |
|
309 | 'repo_group_integrations_edit', | |
|
310 | repo_group_name=self.integration.repo_group.group_name, | |
|
227 | 311 | integration=self.integration.integration_type, |
|
228 | 312 | integration_id=self.integration.integration_id) |
|
229 | 313 | else: |
|
230 |
redirect_to = self.request.route_ |
|
|
314 | redirect_to = self.request.route_path( | |
|
231 | 315 | 'global_integrations_edit', |
|
232 | 316 | integration=self.integration.integration_type, |
|
233 | 317 | integration_id=self.integration.integration_id) |
@@ -235,31 +319,60 b' class IntegrationSettingsViewBase(object' | |||
|
235 | 319 | return HTTPFound(redirect_to) |
|
236 | 320 | |
|
237 | 321 | def index(self): |
|
238 | current_integrations = self.integrations | |
|
239 |
if self. |
|
|
240 | current_integrations = { | |
|
241 | self.IntegrationType.key: self.integrations.get( | |
|
242 | self.IntegrationType.key, []) | |
|
243 |
|
|
|
322 | """ List integrations """ | |
|
323 | if self.repo: | |
|
324 | scope = self.repo | |
|
325 | elif self.repo_group: | |
|
326 | scope = self.repo_group | |
|
327 | else: | |
|
328 | scope = 'all' | |
|
329 | ||
|
330 | integrations = [] | |
|
331 | ||
|
332 | for integration in IntegrationModel().get_integrations( | |
|
333 | scope=scope, IntegrationType=self.IntegrationType): | |
|
334 | ||
|
335 | # extra permissions check *just in case* | |
|
336 | if not self._has_perms_for_integration(integration): | |
|
337 | continue | |
|
338 | integrations.append(integration) | |
|
339 | ||
|
340 | sort_arg = self.request.GET.get('sort', 'name:asc') | |
|
341 | if ':' in sort_arg: | |
|
342 | sort_field, sort_dir = sort_arg.split(':') | |
|
343 | else: | |
|
344 | sort_field = sort_arg, 'asc' | |
|
345 | ||
|
346 | assert sort_field in ('name', 'integration_type', 'enabled', 'scope') | |
|
347 | ||
|
348 | integrations.sort( | |
|
349 | key=lambda x: getattr(x[1], sort_field), reverse=(sort_dir=='desc')) | |
|
350 | ||
|
351 | ||
|
352 | page_url = webhelpers.paginate.PageURL( | |
|
353 | self.request.path, self.request.GET) | |
|
354 | page = safe_int(self.request.GET.get('page', 1), 1) | |
|
355 | ||
|
356 | integrations = Page(integrations, page=page, items_per_page=10, | |
|
357 | url=page_url) | |
|
244 | 358 | |
|
245 | 359 | template_context = { |
|
360 | 'sort_field': sort_field, | |
|
361 | 'rev_sort_dir': sort_dir != 'desc' and 'desc' or 'asc', | |
|
246 | 362 | 'current_IntegrationType': self.IntegrationType, |
|
247 |
' |
|
|
363 | 'integrations_list': integrations, | |
|
248 | 364 | 'available_integrations': integration_type_registry, |
|
249 | 'c': self._template_c_context() | |
|
365 | 'c': self._template_c_context(), | |
|
366 | 'request': self.request, | |
|
250 | 367 | } |
|
368 | return template_context | |
|
251 | 369 | |
|
252 | if self.repo: | |
|
253 | html = render('rhodecode:templates/admin/integrations/list.html', | |
|
254 | template_context, | |
|
255 | request=self.request) | |
|
256 |
|
|
|
257 | html = render('rhodecode:templates/admin/integrations/list.html', | |
|
258 | template_context, | |
|
259 | request=self.request) | |
|
260 | ||
|
261 | return Response(html) | |
|
262 | ||
|
370 | def new_integration(self): | |
|
371 | template_context = { | |
|
372 | 'available_integrations': integration_type_registry, | |
|
373 | 'c': self._template_c_context(), | |
|
374 | } | |
|
375 | return template_context | |
|
263 | 376 | |
|
264 | 377 | class GlobalIntegrationsView(IntegrationSettingsViewBase): |
|
265 | 378 | def perm_check(self, user): |
@@ -270,3 +383,10 b' class RepoIntegrationsView(IntegrationSe' | |||
|
270 | 383 | def perm_check(self, user): |
|
271 | 384 | return auth.HasRepoPermissionAll('repository.admin' |
|
272 | 385 | )(repo_name=self.repo.repo_name, user=user) |
|
386 | ||
|
387 | ||
|
388 | class RepoGroupIntegrationsView(IntegrationSettingsViewBase): | |
|
389 | def perm_check(self, user): | |
|
390 | return auth.HasRepoGroupPermissionAll('group.admin' | |
|
391 | )(group_name=self.repo_group.group_name, user=user) | |
|
392 |
@@ -48,12 +48,12 b' def annotate_highlight(' | |||
|
48 | 48 | :param headers: dictionary with headers (keys are whats in ``order`` |
|
49 | 49 | parameter) |
|
50 | 50 | """ |
|
51 |
from rhodecode.lib. |
|
|
51 | from rhodecode.lib.helpers import get_lexer_for_filenode | |
|
52 | 52 | options['linenos'] = True |
|
53 | 53 | formatter = AnnotateHtmlFormatter( |
|
54 | 54 | filenode=filenode, order=order, headers=headers, |
|
55 | 55 | annotate_from_commit_func=annotate_from_commit_func, **options) |
|
56 | lexer = get_custom_lexer(filenode.extension) or filenode.lexer | |
|
56 | lexer = get_lexer_for_filenode(filenode) | |
|
57 | 57 | highlighted = highlight(filenode.content, lexer, formatter) |
|
58 | 58 | return highlighted |
|
59 | 59 |
@@ -1116,9 +1116,11 b' class CSRFRequired(object):' | |||
|
1116 | 1116 | For use with the ``webhelpers.secure_form`` helper functions. |
|
1117 | 1117 | |
|
1118 | 1118 | """ |
|
1119 |
def __init__(self, token=csrf_token_key, header='X-CSRF-Token' |
|
|
1119 | def __init__(self, token=csrf_token_key, header='X-CSRF-Token', | |
|
1120 | except_methods=None): | |
|
1120 | 1121 | self.token = token |
|
1121 | 1122 | self.header = header |
|
1123 | self.except_methods = except_methods or [] | |
|
1122 | 1124 | |
|
1123 | 1125 | def __call__(self, func): |
|
1124 | 1126 | return get_cython_compat_decorator(self.__wrapper, func) |
@@ -1131,6 +1133,9 b' class CSRFRequired(object):' | |||
|
1131 | 1133 | return supplied_token and supplied_token == cur_token |
|
1132 | 1134 | |
|
1133 | 1135 | def __wrapper(self, func, *fargs, **fkwargs): |
|
1136 | if request.method in self.except_methods: | |
|
1137 | return func(*fargs, **fkwargs) | |
|
1138 | ||
|
1134 | 1139 | cur_token = get_csrf_token(save_if_missing=False) |
|
1135 | 1140 | if self.check_csrf(request, cur_token): |
|
1136 | 1141 | if request.POST.get(self.token): |
@@ -28,6 +28,7 b' import logging' | |||
|
28 | 28 | import socket |
|
29 | 29 | |
|
30 | 30 | import ipaddress |
|
31 | import pyramid.threadlocal | |
|
31 | 32 | |
|
32 | 33 | from paste.auth.basic import AuthBasicAuthenticator |
|
33 | 34 | from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception |
@@ -276,7 +277,7 b' def attach_context_attributes(context, r' | |||
|
276 | 277 | # Visual options |
|
277 | 278 | context.visual = AttributeDict({}) |
|
278 | 279 | |
|
279 | # DB store | |
|
280 | # DB stored Visual Items | |
|
280 | 281 | context.visual.show_public_icon = str2bool( |
|
281 | 282 | rc_config.get('rhodecode_show_public_icon')) |
|
282 | 283 | context.visual.show_private_icon = str2bool( |
@@ -368,6 +369,8 b' def attach_context_attributes(context, r' | |||
|
368 | 369 | context.unread_notifications = NotificationModel().get_unread_cnt_for_user( |
|
369 | 370 | context.rhodecode_user.user_id) |
|
370 | 371 | |
|
372 | context.pyramid_request = pyramid.threadlocal.get_current_request() | |
|
373 | ||
|
371 | 374 | |
|
372 | 375 | def get_auth_user(environ): |
|
373 | 376 | ip_addr = get_ip_addr(environ) |
@@ -84,6 +84,7 b' def get_user_data(user_id):' | |||
|
84 | 84 | 'icon_link': h.gravatar_url(user.email, 14), |
|
85 | 85 | 'display_name': h.person(user, 'username_or_name_or_email'), |
|
86 | 86 | 'display_link': h.link_to_user(user), |
|
87 | 'notifications': user.user_data.get('notification_status', True) | |
|
87 | 88 | } |
|
88 | 89 | |
|
89 | 90 |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: file renamed from rhodecode/templates/admin/integrations/edit.html to rhodecode/templates/admin/integrations/form.html | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: file was removed | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: file was removed | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: file was removed | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: file was removed | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: file was removed | |
The requested commit or file is too big and content was truncated. Show full diff |
General Comments 0
You need to be logged in to leave comments.
Login now