diff --git a/Dockerfile b/Dockerfile
index ff083ed8f6..f3351eb3de 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -41,14 +41,18 @@ COPY . /app
RUN --mount=type=secret,id=GITHUB_PERSONAL_TOKEN export GITHUB_PERSONAL_TOKEN=$(cat /run/secrets/GITHUB_PERSONAL_TOKEN) && git config --global url."https://$GITHUB_PERSONAL_TOKEN@github.com/".insteadOf ssh://git@github.com
-RUN (\
- npm ci; \
+RUN npm ci
+
+RUN \
+ --mount=type=secret,id=GOOGLE_RECAPTCHA_SITE_KEY \
+ sh -c ' \
if test $AIDA_URL; then \
curl -o /app/node_modules/asktravis/dist/aida.js $AIDA_URL; \
curl -o /app/node_modules/asktravis/dist/aida.js.map $AIDA_URL.map || true; \
fi; \
- ember build --environment=production; \
-)
+ export GOOGLE_RECAPTCHA_SITE_KEY=$(cat /run/secrets/GOOGLE_RECAPTCHA_SITE_KEY) && \
+ ember build --environment=production'
+
RUN cp -a public/* dist/
diff --git a/app/components/account-env-var.js b/app/components/account-env-var.js
new file mode 100644
index 0000000000..aa98464b60
--- /dev/null
+++ b/app/components/account-env-var.js
@@ -0,0 +1,38 @@
+import Component from '@ember/component';
+import { inject as service } from '@ember/service';
+import { computed } from '@ember/object';
+import { alias } from '@ember/object/computed';
+import { task } from 'ember-concurrency';
+
+export default Component.extend({
+ flashes: service(),
+ api: service(),
+
+ tagName: 'li',
+ classNames: ['settings-envvar'],
+ classNameBindings: ['envVar.public:is-public', 'envVar.newlyCreated:newly-created'],
+ validates: { name: ['presence'] },
+ actionType: 'Save',
+ showValueField: alias('public'),
+
+ envVarDeleted(key) {},
+
+ value: computed('envVar.{value,public}', function () {
+ let value = this.get('envVar.value');
+ let isPublic = this.get('envVar.public');
+
+ if (isPublic) {
+ return value;
+ }
+ return '••••••••••••••••';
+ }),
+
+
+ delete: task(function* () {
+ try {
+ yield this.api.delete(`/account_env_var/${this.envVar.id}`);
+ } catch (e) {}
+
+ this.envVarDeleted(this.envVar);
+ }).drop()
+});
diff --git a/app/components/add-account-env-var.js b/app/components/add-account-env-var.js
new file mode 100644
index 0000000000..9ae8c65527
--- /dev/null
+++ b/app/components/add-account-env-var.js
@@ -0,0 +1,55 @@
+import Component from '@ember/component';
+import { inject as service } from '@ember/service';
+import { task } from 'ember-concurrency';
+import BranchSearching from 'travis/mixins/branch-searching';
+
+export default Component.extend(BranchSearching, {
+ classNames: ['form--envvar'],
+ classNameBindings: ['valueError:form-error'],
+
+ api: service(),
+ store: service(),
+ raven: service(),
+ flashes: service(),
+
+ init() {
+ this.reset();
+ this._super(...arguments);
+ },
+
+ envVarAdded(envVar) {},
+
+ reset() {
+ return this.setProperties({
+ name: null,
+ value: null,
+ 'public': null
+ });
+ },
+
+ save: task(function* () {
+ this.set('valueError', false);
+
+ try {
+ yield this.api.post(
+ '/account_env_vars',
+ {
+ data: {
+ owner_id: this.owner.id,
+ owner_type: this.ownerType,
+ name: this.name.trim(),
+ value: this.value.trim(),
+ 'public': !!this.public
+ }
+ }
+ ).then((data) => {
+ this.envVarAdded(data);
+ this.reset();
+ });
+ } catch (errors) {
+ errors.clone().json().then((error) => {
+ this.set('valueError', error.error_message);
+ });
+ }
+ }).drop()
+});
diff --git a/app/controllers/account/settings.js b/app/controllers/account/settings.js
index 15c0466bf3..74fde54ac0 100644
--- a/app/controllers/account/settings.js
+++ b/app/controllers/account/settings.js
@@ -58,6 +58,13 @@ export default Controller.extend({
return this.customKeysLoaded;
}),
+ envVarsLoaded: computed('auth.currentUser.accountEnvVars', function () {
+ return this.auth.currentUser.accountEnvVars;
+ }),
+ envVars: computed('envVarsLoaded.[]', function () {
+ return (this.envVarsLoaded || []).sortBy('name');
+ }),
+
isShowingAddKeyModal: false,
userHasNoEmails: computed('auth.currentUser.emails', function () {
@@ -110,6 +117,14 @@ export default Controller.extend({
},
customKeyAdded(key) {
this.get('customKeysLoaded').pushObject(key);
+ },
+ envVarDeleted(envVar) {
+ const envVars = this.auth.currentUser.accountEnvVars;
+ envVars.removeObject(envVar);
+ },
+ envVarAdded(envVar) {
+ const envVars = this.auth.currentUser.accountEnvVars;
+ envVars.pushObject(envVar);
}
},
diff --git a/app/controllers/organization/settings.js b/app/controllers/organization/settings.js
index cd595128a7..ca4a4adb43 100644
--- a/app/controllers/organization/settings.js
+++ b/app/controllers/organization/settings.js
@@ -39,6 +39,13 @@ export default Controller.extend({
return this.model.organization.customKeys;
}),
+ envVarsLoaded: computed('organization.accountEnvVars', function () {
+ return this.organization.accountEnvVars;
+ }),
+ envVars: computed('envVarsLoaded.[]', function () {
+ return (this.envVarsLoaded || []).sortBy('name');
+ }),
+
preferences: computed('model.preferences.@each.{name,value}', function () {
const list = this.model.preferences || [];
return list.reduce((hash, record) => {
@@ -87,6 +94,16 @@ export default Controller.extend({
customKeyAdded(key) {
this.get('model.organization.customKeys').pushObject(key);
+ },
+
+ envVarDeleted(envVar) {
+ const envVars = this.organization.accountEnvVars;
+ envVars.removeObject(envVar);
+ },
+
+ envVarAdded(envVar) {
+ const envVars = this.organization.accountEnvVars;
+ envVars.pushObject(envVar);
}
},
});
diff --git a/app/models/owner.js b/app/models/owner.js
index 1a34dcc21b..59f39fc7c0 100644
--- a/app/models/owner.js
+++ b/app/models/owner.js
@@ -44,6 +44,7 @@ export default VcsEntity.extend({
isOrganization: equal('type', 'organization'),
isAssembla: match('vcsType', /Assembla\S+$/),
trialAllowed: attr('boolean', { defaultValue: false}),
+ accountEnvVars: attr(),
allowance: belongsTo('allowance', { async: true, inverse: 'owner', polymorphic: true, as: 'owner' }),
diff --git a/app/styles/app/layouts/settings.scss b/app/styles/app/layouts/settings.scss
index 7c5b002d26..025fe9ca43 100644
--- a/app/styles/app/layouts/settings.scss
+++ b/app/styles/app/layouts/settings.scss
@@ -159,6 +159,12 @@
}
}
+.account-env-vars-section {
+ .env-var-name, .env-var-value {
+ width: 40% !important;
+ }
+}
+
%settings-value-section {
display: inline-block;
vertical-align: middle;
diff --git a/app/styles/app/modules/forms.scss b/app/styles/app/modules/forms.scss
index 150b47a519..e06a172d25 100644
--- a/app/styles/app/modules/forms.scss
+++ b/app/styles/app/modules/forms.scss
@@ -166,9 +166,9 @@ textarea {
display: flex;
justify-content: left;
width: auto;
- height: 80px;
align-items: center;
margin-left: 1px;
+ height: 80px;
button {
order: 1;
@@ -212,6 +212,19 @@ textarea {
}
}
+.add-account-env-var-form-elem {
+ width: 40% !important;
+
+ .display-value-switch {
+ height: auto !important;
+ }
+}
+
+.add-var-btn {
+ text-align: left !important;
+ margin-bottom: 28px !important;
+}
+
.form--envvar {
.switch {
.label {
diff --git a/app/templates/account/settings.hbs b/app/templates/account/settings.hbs
index f5e1d2bf51..29b5373211 100644
--- a/app/templates/account/settings.hbs
+++ b/app/templates/account/settings.hbs
@@ -146,4 +146,31 @@
+ Customize your build using environment variables. For secure tips on generating private keys
+
+
+ If your secret variable has special characters like
+ Account Environment Variables
+
+ &
,
+ escape them by adding \
in front of each special character.
+ For example, ma&w!doc
would be entered as ma\&w\!doc
.
+
+
+ {{#each this.envVars as |envVar|}}
+
+
+ Customize your build using environment variables. For secure tips on generating private keys
+
+
+ If your secret variable has special characters like &
,
+ escape them by adding \
in front of each special character.
+ For example, ma&w!doc
would be entered as ma\&w\!doc
.
+
+