diff options
24 files changed, 280 insertions, 18 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 36108d04e9c..6b76853f56f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,6 +9,7 @@ stages: - review - qa - post-test + - notification - pages variables: @@ -33,6 +34,7 @@ include: - local: .gitlab/ci/frontend.gitlab-ci.yml - local: .gitlab/ci/global.gitlab-ci.yml - local: .gitlab/ci/memory.gitlab-ci.yml + - local: .gitlab/ci/notifications.gitlab-ci.yml - local: .gitlab/ci/pages.gitlab-ci.yml - local: .gitlab/ci/qa.gitlab-ci.yml - local: .gitlab/ci/reports.gitlab-ci.yml diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index d746d8fe030..c1cab844ca6 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -93,7 +93,7 @@ - "config.ru" - "{package.json,yarn.lock}" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - - "doc/api/graphql/**/*" + - "doc/api/graphql/reference/*" # Files in this folder are auto-generated .backstage-patterns: &backstage-patterns - "Dangerfile" @@ -139,7 +139,7 @@ - "config.ru" - "{package.json,yarn.lock}" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - - "doc/api/graphql/**/*" + - "doc/api/graphql/reference/*" # Files in this folder are auto-generated # Backstage changes - "Dangerfile" - "danger/**/*" @@ -163,7 +163,7 @@ - "config.ru" - "{package.json,yarn.lock}" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - - "doc/api/graphql/**/*" + - "doc/api/graphql/reference/*" # Files in this folder are auto-generated # QA changes - ".dockerignore" - "qa/**/*" @@ -183,7 +183,7 @@ - "config.ru" - "{package.json,yarn.lock}" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - - "doc/api/graphql/**/*" + - "doc/api/graphql/reference/*" # Files in this folder are auto-generated # Backstage changes - "Dangerfile" - "danger/**/*" diff --git a/.gitlab/ci/notifications.gitlab-ci.yml b/.gitlab/ci/notifications.gitlab-ci.yml new file mode 100644 index 00000000000..8e2574fad4c --- /dev/null +++ b/.gitlab/ci/notifications.gitlab-ci.yml @@ -0,0 +1,18 @@ +.notify: + image: alpine + stage: notification + dependencies: [] + cache: {} + before_script: + - apk update && apk add git curl bash + variables: + COMMIT_NOTES_URL: "https://$CI_SERVER_HOST/$CI_PROJECT_PATH/commit/$CI_COMMIT_SHA#notes-list" + +schedule:package-and-qa:notify-failure: + extends: + - .only:variables_refs-canonical-dot-com-schedules + - .notify + script: + - 'scripts/notify-slack qa-master ":skull_and_crossbones: Scheduled QA against master failed! :skull_and_crossbones: See $CI_PIPELINE_URL. For downstream pipelines, see $COMMIT_NOTES_URL" ci_failing' + needs: ["schedule:package-and-qa"] + when: on_failure diff --git a/app/assets/javascripts/frequent_items/store/mutations.js b/app/assets/javascripts/frequent_items/store/mutations.js index 92ac3a2c94d..78ccef7f253 100644 --- a/app/assets/javascripts/frequent_items/store/mutations.js +++ b/app/assets/javascripts/frequent_items/store/mutations.js @@ -48,7 +48,7 @@ export default { }); }, [types.RECEIVE_SEARCHED_ITEMS_SUCCESS](state, results) { - const rawItems = results.data; + const rawItems = results.data ? results.data : results; // Api.groups returns array, Api.projects returns object Object.assign(state, { items: rawItems.map(rawItem => ({ id: rawItem.id, diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index 28143859e4c..1ab11892f61 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -602,3 +602,19 @@ export const getDatesInRange = (d1, d2, formatter = x => x) => { * @return {Number} number of milliseconds */ export const secondsToMilliseconds = seconds => seconds * 1000; + +/** + * Converts the supplied number of seconds to days. + * + * @param {Number} seconds + * @return {Number} number of days + */ +export const secondsToDays = seconds => Math.round(seconds / 86400); + +/** + * Returns the date after the date provided + * + * @param {Date} date the initial date + * @return {Date} the date following the date provided + */ +export const dayAfter = date => new Date(newDate(date).setDate(date.getDate() + 1)); diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js index 87e94311176..e3300967022 100644 --- a/app/assets/javascripts/monitoring/stores/state.js +++ b/app/assets/javascripts/monitoring/stores/state.js @@ -1,8 +1,6 @@ import invalidUrl from '~/lib/utils/invalid_url'; export default () => ({ - hasMetrics: false, - showPanels: true, metricsEndpoint: null, environmentsEndpoint: null, deploymentsEndpoint: null, diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb index 37ba8a7c97e..fd05fd6bab9 100644 --- a/app/models/clusters/applications/runner.rb +++ b/app/models/clusters/applications/runner.rb @@ -3,7 +3,7 @@ module Clusters module Applications class Runner < ApplicationRecord - VERSION = '0.10.1' + VERSION = '0.11.0' self.table_name = 'clusters_applications_runners' diff --git a/changelogs/unreleased/27630-specify-kubernetes-namespace-in-ci-template.yml b/changelogs/unreleased/27630-specify-kubernetes-namespace-in-ci-template.yml new file mode 100644 index 00000000000..5ec5cb2015d --- /dev/null +++ b/changelogs/unreleased/27630-specify-kubernetes-namespace-in-ci-template.yml @@ -0,0 +1,5 @@ +--- +title: Allow specifying Kubernetes namespace for an environment in gitlab-ci.yml +merge_request: 20270 +author: +type: added diff --git a/changelogs/unreleased/fix-groups-search-dropdown.yml b/changelogs/unreleased/fix-groups-search-dropdown.yml new file mode 100644 index 00000000000..7dd1a5a1d4f --- /dev/null +++ b/changelogs/unreleased/fix-groups-search-dropdown.yml @@ -0,0 +1,5 @@ +--- +title: Fix group search in groups dropdown +merge_request: 20535 +author: +type: fixed diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-11-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-11-0.yml new file mode 100644 index 00000000000..a6a22b8f55f --- /dev/null +++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-11-0.yml @@ -0,0 +1,5 @@ +--- +title: Update GitLab Runner Helm Chart to 0.11.0 +merge_request: 20461 +author: +type: other diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index ca04bbd0444..05b660ccdf6 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -135,6 +135,7 @@ The following job parameters can be defined inside a `default:` block: - [`before_script`](#before_script-and-after_script) - [`after_script`](#before_script-and-after_script) - [`cache`](#cache) +- [`retry`](#retry) - [`timeout`](#timeout) - [`interruptible`](#interruptible) diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md index 7ec76f61e42..39384f9bcbe 100644 --- a/doc/development/pipelines.md +++ b/doc/development/pipelines.md @@ -29,6 +29,7 @@ The current stages are: - `review`: This stage includes jobs that deploy the GitLab and Docs Review Apps. - `qa`: This stage includes jobs that perform QA tasks against the Review App that is deployed in the previous stage. +- `notification`: This stage includes jobs that sends notifications about pipeline status. - `post-test`: This stage includes jobs that build reports or gather data from the previous stages' jobs (e.g. coverage, Knapsack metadata etc.). - `pages`: This stage includes a job that deploys the various reports as @@ -209,6 +210,11 @@ subgraph "`qa` stage" dast -.-> |needs and depends on| G; end +subgraph "`notification` stage" + NOTIFICATION1["schedule:package-and-qa:notify-success<br>(on_success)"] -.-> |needs| P; + NOTIFICATION2["schedule:package-and-qa:notify-failure<br>(on_failure)"] -.-> |needs| P; + end + subgraph "`post-test` stage" M end diff --git a/lib/gitlab/ci/config/entry/default.rb b/lib/gitlab/ci/config/entry/default.rb index 646f06a60a9..b84ae53a514 100644 --- a/lib/gitlab/ci/config/entry/default.rb +++ b/lib/gitlab/ci/config/entry/default.rb @@ -15,7 +15,7 @@ module Gitlab ALLOWED_KEYS = %i[before_script image services after_script cache interruptible - timeout].freeze + timeout retry].freeze validations do validates :config, allowed_keys: ALLOWED_KEYS @@ -49,7 +49,11 @@ module Gitlab description: 'Set jobs default timeout.', inherit: false - helpers :before_script, :image, :services, :after_script, :cache, :interruptible, :timeout + entry :retry, Entry::Retry, + description: 'Set retry default value.', + inherit: false + + helpers :before_script, :image, :services, :after_script, :cache, :interruptible, :timeout, :retry private diff --git a/lib/gitlab/ci/config/entry/environment.rb b/lib/gitlab/ci/config/entry/environment.rb index 5a13fd18504..68254552f82 100644 --- a/lib/gitlab/ci/config/entry/environment.rb +++ b/lib/gitlab/ci/config/entry/environment.rb @@ -8,9 +8,11 @@ module Gitlab # Entry that represents an environment. # class Environment < ::Gitlab::Config::Entry::Node - include ::Gitlab::Config::Entry::Validatable + include ::Gitlab::Config::Entry::Configurable - ALLOWED_KEYS = %i[name url action on_stop].freeze + ALLOWED_KEYS = %i[name url action on_stop kubernetes].freeze + + entry :kubernetes, Entry::Kubernetes, description: 'Kubernetes deployment configuration.' validations do validate do @@ -46,6 +48,7 @@ module Gitlab allow_nil: true validates :on_stop, type: String, allow_nil: true + validates :kubernetes, type: Hash, allow_nil: true end end @@ -73,6 +76,10 @@ module Gitlab value[:on_stop] end + def kubernetes + value[:kubernetes] + end + def value case @config when String then { name: @config, action: 'start' } @@ -80,6 +87,10 @@ module Gitlab else {} end end + + def skip_config_hash_validation? + true + end end end end diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index a109265f2a7..7c01e6ffbe8 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -105,6 +105,10 @@ module Gitlab description: 'Timeout duration of this job.', inherit: true + entry :retry, Entry::Retry, + description: 'Retry configuration for this job.', + inherit: true + entry :only, Entry::Policy, description: 'Refs policy this job will be executed for.', default: Entry::Policy::DEFAULT_ONLY, @@ -142,10 +146,6 @@ module Gitlab description: 'Coverage configuration for this job.', inherit: false - entry :retry, Entry::Retry, - description: 'Retry configuration for this job.', - inherit: false - helpers :before_script, :script, :stage, :type, :after_script, :cache, :image, :services, :only, :except, :variables, :artifacts, :environment, :coverage, :retry, :rules, diff --git a/lib/gitlab/ci/config/entry/kubernetes.rb b/lib/gitlab/ci/config/entry/kubernetes.rb new file mode 100644 index 00000000000..2f1595d4437 --- /dev/null +++ b/lib/gitlab/ci/config/entry/kubernetes.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + class Config + module Entry + class Kubernetes < ::Gitlab::Config::Entry::Node + include ::Gitlab::Config::Entry::Validatable + include ::Gitlab::Config::Entry::Attributable + + ALLOWED_KEYS = %i[namespace].freeze + + attributes ALLOWED_KEYS + + validations do + validates :config, type: Hash + validates :config, allowed_keys: ALLOWED_KEYS + + validates :namespace, type: String, presence: true + end + end + end + end + end +end diff --git a/scripts/notify-slack b/scripts/notify-slack new file mode 100755 index 00000000000..5907fd8b986 --- /dev/null +++ b/scripts/notify-slack @@ -0,0 +1,14 @@ +#!/bin/bash +# Sends Slack notification MSG to CI_SLACK_WEBHOOK_URL (which needs to be set). +# ICON_EMOJI needs to be set to an icon emoji name (without the `:` around it). + +CHANNEL=$1 +MSG=$2 +ICON_EMOJI=$3 + +if [ -z "$CHANNEL" ] || [ -z "$CI_SLACK_WEBHOOK_URL" ] || [ -z "$MSG" ] || [ -z "$ICON_EMOJI" ]; then + echo "Missing argument(s) - Use: $0 channel message icon_emoji" + echo "and set CI_SLACK_WEBHOOK_URL environment variable." +else + curl -X POST --data-urlencode 'payload={"channel": "#'"$CHANNEL"'", "username": "GitLab QA Bot", "text": "'"$MSG"'", "icon_emoji": "'":$ICON_EMOJI:"'"}' "$CI_SLACK_WEBHOOK_URL" +fi diff --git a/spec/frontend/lib/utils/datetime_utility_spec.js b/spec/frontend/lib/utils/datetime_utility_spec.js index ee27789b6b9..fd75c9aa0cd 100644 --- a/spec/frontend/lib/utils/datetime_utility_spec.js +++ b/spec/frontend/lib/utils/datetime_utility_spec.js @@ -482,3 +482,27 @@ describe('secondsToMilliseconds', () => { expect(datetimeUtility.secondsToMilliseconds(123)).toBe(123000); }); }); + +describe('dayAfter', () => { + const date = new Date('2019-07-16T00:00:00.000Z'); + + it('returns the following date', () => { + const nextDay = datetimeUtility.dayAfter(date); + const expectedNextDate = new Date('2019-07-17T00:00:00.000Z'); + + expect(nextDay).toStrictEqual(expectedNextDate); + }); + + it('does not modifiy the original date', () => { + datetimeUtility.dayAfter(date); + expect(date).toStrictEqual(new Date('2019-07-16T00:00:00.000Z')); + }); +}); + +describe('secondsToDays', () => { + it('converts seconds to days correctly', () => { + expect(datetimeUtility.secondsToDays(0)).toBe(0); + expect(datetimeUtility.secondsToDays(90000)).toBe(1); + expect(datetimeUtility.secondsToDays(270000)).toBe(3); + }); +}); diff --git a/spec/javascripts/frequent_items/mock_data.js b/spec/javascripts/frequent_items/mock_data.js index 7f7d7b1cdbf..419f70e41af 100644 --- a/spec/javascripts/frequent_items/mock_data.js +++ b/spec/javascripts/frequent_items/mock_data.js @@ -68,7 +68,7 @@ export const mockFrequentGroups = [ }, ]; -export const mockSearchedGroups = { data: [mockRawGroup] }; +export const mockSearchedGroups = [mockRawGroup]; export const mockProcessedSearchedGroups = [mockGroup]; export const mockProject = { diff --git a/spec/lib/gitlab/ci/config/entry/default_spec.rb b/spec/lib/gitlab/ci/config/entry/default_spec.rb index 0366a63ef05..ffd24aa56b9 100644 --- a/spec/lib/gitlab/ci/config/entry/default_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/default_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::Ci::Config::Entry::Default do expect(described_class.nodes.keys) .to match_array(%i[before_script image services after_script cache interruptible - timeout]) + timeout retry]) end end end diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb index 7b72b45fd8d..c80b54bd6be 100644 --- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb @@ -241,4 +241,28 @@ describe Gitlab::Ci::Config::Entry::Environment do end end end + + describe 'kubernetes' do + let(:config) do + { name: 'production', kubernetes: kubernetes_config } + end + + context 'is a string' do + let(:kubernetes_config) { 'production' } + + it { expect(entry).not_to be_valid } + end + + context 'is a hash' do + let(:kubernetes_config) { Hash(namespace: 'production') } + + it { expect(entry).to be_valid } + end + + context 'is nil' do + let(:kubernetes_config) { nil } + + it { expect(entry).to be_valid } + end + end end diff --git a/spec/lib/gitlab/ci/config/entry/kubernetes_spec.rb b/spec/lib/gitlab/ci/config/entry/kubernetes_spec.rb new file mode 100644 index 00000000000..468e83ec506 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/kubernetes_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Ci::Config::Entry::Kubernetes do + subject { described_class.new(config) } + + describe 'attributes' do + it { is_expected.to respond_to(:namespace) } + it { is_expected.to respond_to(:has_namespace?) } + end + + describe 'validations' do + describe 'config' do + context 'is a hash containing known keys' do + let(:config) { Hash(namespace: 'namespace') } + + it { is_expected.to be_valid } + end + + context 'is a hash containing an unknown key' do + let(:config) { Hash(unknown: 'attribute') } + + it { is_expected.not_to be_valid } + end + + context 'is a string' do + let(:config) { 'config' } + + it { is_expected.not_to be_valid } + end + end + + describe 'namespace' do + let(:config) { Hash(namespace: namespace) } + + context 'is a string' do + let(:namespace) { 'namespace' } + + it { is_expected.to be_valid } + end + + context 'is a hash' do + let(:namespace) { Hash(key: 'namespace') } + + it { is_expected.not_to be_valid } + end + + context 'is not present' do + let(:namespace) { '' } + + it { is_expected.not_to be_valid } + end + end + end +end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 66f6402b9a2..5dc51f83b3c 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -149,6 +149,28 @@ module Gitlab expect(subject[:options]).not_to have_key(:retry) end end + + context 'when retry count is specified by default' do + let(:config) do + YAML.dump(default: { retry: { max: 1 } }, + rspec: { script: 'rspec' }) + end + + it 'does use the default value' do + expect(subject[:options]).to include(retry: { max: 1 }) + end + end + + context 'when retry count default value is overridden' do + let(:config) do + YAML.dump(default: { retry: { max: 1 } }, + rspec: { script: 'rspec', retry: { max: 2 } }) + end + + it 'does use the job value' do + expect(subject[:options]).to include(retry: { max: 2 }) + end + end end describe 'allow failure entry' do diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index de0f4841215..8f16d375f03 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -801,6 +801,32 @@ describe Ci::CreatePipelineService do end end + context 'environment with Kubernetes configuration' do + let(:kubernetes_namespace) { 'custom-namespace' } + + before do + config = YAML.dump( + deploy: { + environment: { + name: "environment-name", + kubernetes: { namespace: kubernetes_namespace } + }, + script: 'ls' + } + ) + + stub_ci_pipeline_yaml_file(config) + end + + it 'stores the requested namespace' do + result = execute_service + build = result.builds.first + + expect(result).to be_persisted + expect(build.options.dig(:environment, :kubernetes, :namespace)).to eq(kubernetes_namespace) + end + end + context 'when environment with invalid name' do before do config = YAML.dump(deploy: { environment: { name: 'name,with,commas' }, script: 'ls' }) |