Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-03-29 21:08:04 +00:00
parent 2194dac753
commit ba537a9b5c
41 changed files with 1193 additions and 21 deletions

View File

@ -117,7 +117,7 @@ module Import
error: exception.response_body
)
error(_('Import failed due to a GitHub error: %{original}') % { original: exception.response_body }, :unprocessable_entity)
error(_('Import failed due to a GitHub error: %{original} (HTTP %{code})') % { original: exception.response_body, code: exception.response_status }, :unprocessable_entity)
end
def log_and_return_error(message, translated_message, http_status)

View File

@ -1,11 +1,11 @@
- name: "REST and GraphQL API Runner status will not return `paused`"
announcement_milestone: "14.5" # The milestone when this feature was first announced as deprecated.
announcement_date: "2021-11-22"
removal_milestone: "15.0" # the milestone when this feature is planned to be removed
removal_date: "2022-05-22" # the date of the milestone release when this feature is planned to be removed
removal_milestone: "16.0" # the milestone when this feature is planned to be removed
removal_date: "2023-04-22" # the date of the milestone release when this feature is planned to be removed
breaking_change: true
body: | # Do not modify this line, instead modify the lines below.
The GitLab Runner REST and GraphQL API endpoints will not return `paused` or `active` as a status in GitLab 15.0.
The GitLab Runner REST and GraphQL API endpoints will not return `paused` or `active` as a status in GitLab 16.0.
A runner's status will only relate to runner contact status, such as:
`online`, `offline`, or `not_connected`. Status `paused` or `active` will no longer appear.

View File

@ -1,7 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
info: For assistance with this tutorials page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-other-projects-and-subjects.
---
# Learn GitLab with tutorials

View File

@ -1,7 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
info: For assistance with this tutorial, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-other-projects-and-subjects.
---
# Make your first Git commit

View File

@ -1315,12 +1315,12 @@ In milestone 15.0, we will remove the `pipelines` attribute from the API respons
### REST and GraphQL API Runner status will not return `paused`
WARNING:
This feature will be changed or removed in 15.0
This feature will be changed or removed in 16.0
as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
Before updating GitLab, review the details carefully to determine if you need to make any
changes to your code, settings, or workflow.
The GitLab Runner REST and GraphQL API endpoints will not return `paused` or `active` as a status in GitLab 15.0.
The GitLab Runner REST and GraphQL API endpoints will not return `paused` or `active` as a status in GitLab 16.0.
A runner's status will only relate to runner contact status, such as:
`online`, `offline`, or `not_connected`. Status `paused` or `active` will no longer appear.
@ -1328,7 +1328,7 @@ A runner's status will only relate to runner contact status, such as:
When checking if a runner is `paused`, API users are advised to check the boolean attribute
`paused` to be `true` instead. When checking if a runner is `active`, check if `paused` is `false`.
**Planned removal milestone: 15.0 (2022-05-22)**
**Planned removal milestone: 16.0 (2023-04-22)**
### Support for SLES 12 SP2

View File

@ -36,7 +36,7 @@ To activate your instance with an activation code:
The subscription is activated.
If you have an offline or airgapped environment,
If you have an offline or air gapped environment,
[activate GitLab EE with a license file or key](license_file.md) instead.
If you have questions or need assistance activating your instance,
@ -51,7 +51,19 @@ To verify the edition, sign in to GitLab and select
**Help** (**{question-o}**) > **Help**. The GitLab edition and version are listed
at the top of the page.
If you are running GitLab Community Edition (CE), you can upgrade your installation to GitLab
If you are running GitLab Community Edition, you can upgrade your installation to GitLab
EE. For more details, see [Upgrading between editions](../../update/index.md#upgrading-between-editions).
If you have questions or need assistance upgrading from GitLab CE to EE,
If you have questions or need assistance upgrading from GitLab Community Edition (CE) to EE,
[contact GitLab Support](https://about.gitlab.com/support/#contact-support).
## Troubleshooting
### Cannot activate instance due to connectivity error
This error occurs when you use an activation code to activate your instance, but your instance is unable to connect to the GitLab servers.
You may have connectivity issues due to the following reasons:
- **You have an offline or air gapped environment**: Configure your setup to allow connection to GitLab servers. If connection to GitLab servers is not possible, contact [GitLab support](https://about.gitlab.com/support/#contact-support) to request a license key.
- **Firewall settings**: Enable an encrypted HTTPS connection from your GitLab instance to `customers.gitlab.com` (with IP addresses 104.18.26.123 and 104.18.27.123) on port 443.
- **Customers Portal is not operational**: To check for performance or service disruptions, check the Customers Portal [status](https://status.gitlab.com/).

View File

@ -109,7 +109,7 @@ module.exports = (path, options = {}) => {
return {
clearMocks: true,
testMatch,
moduleFileExtensions: ['js', 'json', 'vue', 'gql', 'graphql'],
moduleFileExtensions: ['js', 'json', 'vue', 'gql', 'graphql', 'yaml'],
moduleNameMapper,
collectCoverageFrom,
coverageDirectory: coverageDirectory(),
@ -127,6 +127,7 @@ module.exports = (path, options = {}) => {
'^.+_worker\\.js$': './spec/frontend/__helpers__/web_worker_transformer.js',
'^.+\\.js$': 'babel-jest',
'^.+\\.vue$': 'vue-jest',
'^.+\\.yml$': './spec/frontend/__helpers__/yaml_transformer.js',
'^.+\\.(md|zip|png)$': 'jest-raw-loader',
},
transformIgnorePatterns: [

View File

@ -389,7 +389,8 @@ module Backup
end
def skipped?(item)
backup_information[:skipped] && backup_information[:skipped].include?(item)
ENV.fetch('SKIP', '').include?(item) ||
backup_information[:skipped] && backup_information[:skipped].include?(item)
end
def enabled_task?(task_name)

View File

@ -18864,7 +18864,7 @@ msgstr ""
msgid "Import and export rate limits"
msgstr ""
msgid "Import failed due to a GitHub error: %{original}"
msgid "Import failed due to a GitHub error: %{original} (HTTP %{code})"
msgstr ""
msgid "Import from"

View File

@ -206,6 +206,8 @@
"@types/jest": "^26.0.24",
"@vue/test-utils": "1.3.0",
"acorn": "^6.3.0",
"ajv": "^8.10.0",
"ajv-formats": "^2.1.1",
"axios-mock-adapter": "^1.15.0",
"babel-jest": "^26.5.2",
"babel-plugin-dynamic-import-node": "^2.3.3",

View File

@ -1,3 +1,4 @@
export * from './to_have_sprite_icon';
export * from './to_have_tracking_attributes';
export * from './to_match_interpolated_text';
export * from './to_validate_json_schema';

View File

@ -0,0 +1,34 @@
// NOTE: Make sure to initialize ajv when using this helper
const getAjvErrorMessage = ({ errors }) => {
return (errors || []).map((error) => {
return `Error with item ${error.instancePath}: ${error.message}`;
});
};
export function toValidateJsonSchema(testData, validator) {
if (!(validator instanceof Function && validator.schema)) {
return {
validator,
message: () =>
'Validator must be a validating function with property "schema", created with `ajv.compile`. See https://ajv.js.org/api.html#ajv-compile-schema-object-data-any-boolean-promise-any.',
pass: false,
};
}
const isValid = validator(testData);
return {
actual: testData,
message: () => {
if (isValid) {
// We can match, but still fail because we're in a `expect...not.` context
return 'Expected the given data not to pass the schema validation, but found that it was considered valid.';
}
const errorMessages = getAjvErrorMessage(validator).join('\n');
return `Expected the given data to pass the schema validation, but found that it was considered invalid. Errors:\n${errorMessages}`;
},
pass: isValid,
};
}

View File

@ -0,0 +1,65 @@
import Ajv from 'ajv';
import AjvFormats from 'ajv-formats';
const JSON_SCHEMA = {
type: 'object',
properties: {
fruit: {
type: 'string',
minLength: 3,
},
},
};
const ajv = new Ajv({
strictTypes: false,
strictTuples: false,
allowMatchingProperties: true,
});
AjvFormats(ajv);
const schema = ajv.compile(JSON_SCHEMA);
describe('custom matcher toValidateJsonSchema', () => {
it('throws error if validator is not compiled correctly', () => {
expect(() => {
expect({}).toValidateJsonSchema({});
}).toThrow(
'Validator must be a validating function with property "schema", created with `ajv.compile`. See https://ajv.js.org/api.html#ajv-compile-schema-object-data-any-boolean-promise-any.',
);
});
describe('positive assertions', () => {
it.each`
description | input
${'valid input'} | ${{ fruit: 'apple' }}
`('schema validation passes for $description', ({ input }) => {
expect(input).toValidateJsonSchema(schema);
});
it('throws if not matching', () => {
expect(() => expect(null).toValidateJsonSchema(schema)).toThrowError(
`Expected the given data to pass the schema validation, but found that it was considered invalid. Errors:
Error with item : must be object`,
);
});
});
describe('negative assertions', () => {
it.each`
description | input
${'no input'} | ${null}
${'input with invalid type'} | ${'banana'}
${'input with invalid length'} | ${{ fruit: 'aa' }}
${'input with invalid type'} | ${{ fruit: 12345 }}
`('schema validation fails for $description', ({ input }) => {
expect(input).not.toValidateJsonSchema(schema);
});
it('throws if matching', () => {
expect(() => expect({ fruit: 'apple' }).not.toValidateJsonSchema(schema)).toThrowError(
'Expected the given data not to pass the schema validation, but found that it was considered valid.',
);
});
});
});

View File

@ -0,0 +1,11 @@
/* eslint-disable import/no-commonjs */
const JsYaml = require('js-yaml');
// This will transform YAML files to JSON strings
module.exports = {
process: (sourceContent) => {
const jsonContent = JsYaml.load(sourceContent);
const json = JSON.stringify(jsonContent);
return `module.exports = ${json}`;
},
};

View File

@ -0,0 +1,90 @@
import Ajv from 'ajv';
import AjvFormats from 'ajv-formats';
import CiSchema from '~/editor/schema/ci.json';
// JSON POSITIVE TESTS
import AllowFailureJson from './json_tests/positive_tests/allow_failure.json';
import EnvironmentJson from './json_tests/positive_tests/environment.json';
import GitlabCiDependenciesJson from './json_tests/positive_tests/gitlab-ci-dependencies.json';
import GitlabCiJson from './json_tests/positive_tests/gitlab-ci.json';
import InheritJson from './json_tests/positive_tests/inherit.json';
import MultipleCachesJson from './json_tests/positive_tests/multiple-caches.json';
import RetryJson from './json_tests/positive_tests/retry.json';
import TerraformReportJson from './json_tests/positive_tests/terraform_report.json';
import VariablesMixStringAndUserInputJson from './json_tests/positive_tests/variables_mix_string_and_user_input.json';
import VariablesJson from './json_tests/positive_tests/variables.json';
// JSON NEGATIVE TESTS
import DefaultNoAdditionalPropertiesJson from './json_tests/negative_tests/default_no_additional_properties.json';
import InheritDefaultNoAdditionalPropertiesJson from './json_tests/negative_tests/inherit_default_no_additional_properties.json';
import JobVariablesMustNotContainObjectsJson from './json_tests/negative_tests/job_variables_must_not_contain_objects.json';
import ReleaseAssetsLinksEmptyJson from './json_tests/negative_tests/release_assets_links_empty.json';
import ReleaseAssetsLinksInvalidLinkTypeJson from './json_tests/negative_tests/release_assets_links_invalid_link_type.json';
import ReleaseAssetsLinksMissingJson from './json_tests/negative_tests/release_assets_links_missing.json';
import RetryUnknownWhenJson from './json_tests/negative_tests/retry_unknown_when.json';
// YAML POSITIVE TEST
import CacheYaml from './yaml_tests/positive_tests/cache.yml';
import FilterYaml from './yaml_tests/positive_tests/filter.yml';
import IncludeYaml from './yaml_tests/positive_tests/include.yml';
import RulesYaml from './yaml_tests/positive_tests/rules.yml';
// YAML NEGATIVE TEST
import CacheNegativeYaml from './yaml_tests/negative_tests/cache.yml';
import IncludeNegativeYaml from './yaml_tests/negative_tests/include.yml';
const ajv = new Ajv({
strictTypes: false,
strictTuples: false,
allowMatchingProperties: true,
});
AjvFormats(ajv);
const schema = ajv.compile(CiSchema);
describe('positive tests', () => {
it.each(
Object.entries({
// JSON
AllowFailureJson,
EnvironmentJson,
GitlabCiDependenciesJson,
GitlabCiJson,
InheritJson,
MultipleCachesJson,
RetryJson,
TerraformReportJson,
VariablesMixStringAndUserInputJson,
VariablesJson,
// YAML
CacheYaml,
FilterYaml,
IncludeYaml,
RulesYaml,
}),
)('schema validates %s', (_, input) => {
expect(input).toValidateJsonSchema(schema);
});
});
describe('negative tests', () => {
it.each(
Object.entries({
// JSON
DefaultNoAdditionalPropertiesJson,
JobVariablesMustNotContainObjectsJson,
InheritDefaultNoAdditionalPropertiesJson,
ReleaseAssetsLinksEmptyJson,
ReleaseAssetsLinksInvalidLinkTypeJson,
ReleaseAssetsLinksMissingJson,
RetryUnknownWhenJson,
// YAML
CacheNegativeYaml,
IncludeNegativeYaml,
}),
)('schema validates %s', (_, input) => {
expect(input).not.toValidateJsonSchema(schema);
});
});

View File

@ -0,0 +1,12 @@
{
"default": {
"secrets": {
"DATABASE_PASSWORD": {
"vault": "production/db/password"
}
},
"environment": {
"name": "test"
}
}
}

View File

@ -0,0 +1,8 @@
{
"karma": {
"inherit": {
"default": ["secrets"]
},
"script": "karma"
}
}

View File

@ -0,0 +1,12 @@
{
"gitlab-ci-variables-object": {
"stage": "test",
"script": ["true"],
"variables": {
"DEPLOY_ENVIRONMENT": {
"value": "staging",
"description": "The deployment target. Change this variable to 'canary' or 'production' if needed."
}
}
}
}

View File

@ -0,0 +1,13 @@
{
"gitlab-ci-release-assets-links-empty": {
"script": "dostuff",
"stage": "deploy",
"release": {
"description": "Created using the release-cli $EXTRA_DESCRIPTION",
"tag_name": "$CI_COMMIT_TAG",
"assets": {
"links": []
}
}
}
}

View File

@ -0,0 +1,24 @@
{
"gitlab-ci-release-assets-links-invalid-link-type": {
"script": "dostuff",
"stage": "deploy",
"release": {
"description": "Created using the release-cli $EXTRA_DESCRIPTION",
"tag_name": "$CI_COMMIT_TAG",
"assets": {
"links": [
{
"name": "asset1",
"url": "https://example.com/assets/1"
},
{
"name": "asset2",
"url": "https://example.com/assets/2",
"filepath": "/pretty/url/1",
"link_type": "invalid"
}
]
}
}
}
}

View File

@ -0,0 +1,11 @@
{
"gitlab-ci-release-assets-links-missing": {
"script": "dostuff",
"stage": "deploy",
"release": {
"description": "Created using the release-cli $EXTRA_DESCRIPTION",
"tag_name": "$CI_COMMIT_TAG",
"assets": {}
}
}
}

View File

@ -0,0 +1,9 @@
{
"gitlab-ci-retry-object-unknown-when": {
"stage": "test",
"script": "rspec",
"retry": {
"when": "gitlab-ci-retry-object-unknown-when"
}
}
}

View File

@ -0,0 +1,19 @@
{
"job1": {
"stage": "test",
"script": ["execute_script_that_will_fail"],
"allow_failure": true
},
"job2": {
"script": ["exit 1"],
"allow_failure": {
"exit_codes": 137
}
},
"job3": {
"script": ["exit 137"],
"allow_failure": {
"exit_codes": [137, 255]
}
}
}

View File

@ -0,0 +1,75 @@
{
"deploy to production 1": {
"stage": "deploy",
"script": "git push production HEAD: master",
"environment": "production"
},
"deploy to production 2": {
"stage": "deploy",
"script": "git push production HEAD:master",
"environment": {
"name": "production"
}
},
"deploy to production 3": {
"stage": "deploy",
"script": "git push production HEAD:master",
"environment": {
"name": "production",
"url": "https://prod.example.com"
}
},
"review_app 1": {
"stage": "deploy",
"script": "make deploy-app",
"environment": {
"name": "review/$CI_COMMIT_REF_NAME",
"url": "https://$CI_ENVIRONMENT_SLUG.example.com",
"on_stop": "stop_review_app"
}
},
"stop_review_app": {
"stage": "deploy",
"variables": {
"GIT_STRATEGY": "none"
},
"script": "make delete-app",
"when": "manual",
"environment": {
"name": "review/$CI_COMMIT_REF_NAME",
"action": "stop"
}
},
"review_app 2": {
"script": "deploy-review-app",
"environment": {
"name": "review/$CI_COMMIT_REF_NAME",
"auto_stop_in": "1 day"
}
},
"deploy 1": {
"stage": "deploy",
"script": "make deploy-app",
"environment": {
"name": "production",
"kubernetes": {
"namespace": "production"
}
}
},
"deploy 2": {
"script": "echo",
"environment": {
"name": "customer-portal",
"deployment_tier": "production"
}
},
"deploy as review app": {
"stage": "deploy",
"script": "make deploy",
"environment": {
"name": "review/$CI_COMMIT_REF_NAME",
"url": "https://$CI_ENVIRONMENT_SLUG.example.com/"
}
}
}

View File

@ -0,0 +1,68 @@
{
".build_config": {
"before_script": ["echo test"]
},
".build_script": "echo build script",
"default": {
"image": "ruby:2.5",
"services": ["docker:dind"],
"cache": {
"paths": ["vendor/"]
},
"before_script": ["bundle install --path vendor/"],
"after_script": ["rm -rf tmp/"]
},
"stages": ["install", "build", "test", "deploy"],
"image": "foo:latest",
"install task1": {
"image": "node:latest",
"stage": "install",
"script": "npm install",
"artifacts": {
"paths": ["node_modules/"]
}
},
"build dev": {
"image": "node:latest",
"stage": "build",
"needs": [
{
"job": "install task1"
}
],
"script": "npm run build:dev"
},
"build prod": {
"image": "node:latest",
"stage": "build",
"needs": ["install task1"],
"script": "npm run build:prod"
},
"test": {
"image": "node:latest",
"stage": "build",
"needs": [
"install task1",
{
"job": "build dev",
"artifacts": true
}
],
"script": "npm run test"
},
"deploy it": {
"image": "node:latest",
"stage": "deploy",
"needs": [
{
"job": "build dev",
"artifacts": false
},
{
"job": "build prod",
"artifacts": true
}
],
"script": "npm run test"
}
}

View File

@ -0,0 +1,350 @@
{
".build_config": {
"before_script": ["echo test"]
},
".build_script": "echo build script",
".example_variables": {
"foo": "hello",
"bar": 42
},
".example_services": [
"docker:dind",
{
"name": "sql:latest",
"command": ["/usr/bin/super-sql", "run"]
}
],
"default": {
"image": "ruby:2.5",
"services": ["docker:dind"],
"cache": {
"paths": ["vendor/"]
},
"before_script": ["bundle install --path vendor/"],
"after_script": ["rm -rf tmp/"],
"tags": ["ruby", "postgres"],
"artifacts": {
"name": "%CI_COMMIT_REF_NAME%",
"expose_as": "artifact 1",
"paths": ["path/to/file.txt", "target/*.war"],
"when": "on_failure"
},
"retry": 2,
"timeout": "3 hours 30 minutes",
"interruptible": true
},
"stages": ["build", "test", "deploy", "random"],
"image": "foo:latest",
"services": ["sql:latest"],
"before_script": ["echo test", "echo test2"],
"after_script": [],
"cache": {
"key": "asd",
"paths": ["dist/", ".foo"],
"untracked": false,
"policy": "pull"
},
"variables": {
"STAGE": "yep",
"PROD": "nope"
},
"include": [
"https://gitlab.com/awesome-project/raw/master/.before-script-template.yml",
"/templates/.after-script-template.yml",
{ "template": "Auto-DevOps.gitlab-ci.yml" },
{
"project": "my-group/my-project",
"ref": "master",
"file": "/templates/.gitlab-ci-template.yml"
},
{
"project": "my-group/my-project",
"ref": "master",
"file": ["/templates/.gitlab-ci-template.yml", "/templates/another-template-to-include.yml"]
}
],
"build": {
"image": {
"name": "node:latest"
},
"services": [],
"stage": "build",
"script": "npm run build",
"before_script": ["npm install"],
"rules": [
{
"if": "moo",
"changes": ["Moofile"],
"exists": ["main.cow"],
"when": "delayed",
"start_in": "3 hours"
}
],
"retry": {
"max": 1,
"when": "stuck_or_timeout_failure"
},
"cache": {
"key": "$CI_COMMIT_REF_NAME",
"paths": ["node_modules/"],
"policy": "pull-push"
},
"artifacts": {
"paths": ["dist/"],
"expose_as": "link_name_in_merge_request",
"name": "bundles",
"when": "on_success",
"expire_in": "1 week",
"reports": {
"junit": "result.xml",
"cobertura": "cobertura-coverage.xml",
"codequality": "codequality.json",
"sast": "sast.json",
"dependency_scanning": "scan.json",
"container_scanning": "scan2.json",
"dast": "dast.json",
"license_management": "license.json",
"performance": "performance.json",
"metrics": "metrics.txt"
}
},
"variables": {
"FOO_BAR": "..."
},
"only": {
"kubernetes": "active",
"variables": ["$FOO_BAR == '...'"],
"changes": ["/path/to/file", "/another/file"]
},
"except": ["master", "tags"],
"tags": ["docker"],
"allow_failure": true,
"when": "manual"
},
"error-report": {
"when": "on_failure",
"script": "report error",
"stage": "test"
},
"test": {
"image": {
"name": "node:latest",
"entrypoint": [""]
},
"stage": "test",
"script": "npm test",
"parallel": 5,
"retry": {
"max": 2,
"when": [
"runner_system_failure",
"stuck_or_timeout_failure",
"script_failure",
"unknown_failure",
"always"
]
},
"artifacts": {
"reports": {
"junit": ["result.xml"],
"cobertura": ["cobertura-coverage.xml"],
"codequality": ["codequality.json"],
"sast": ["sast.json"],
"dependency_scanning": ["scan.json"],
"container_scanning": ["scan2.json"],
"dast": ["dast.json"],
"license_management": ["license.json"],
"performance": ["performance.json"],
"metrics": ["metrics.txt"]
}
},
"coverage": "/Cycles: \\d+\\.\\d+$/",
"dependencies": []
},
"docker": {
"script": "docker build -t foo:latest",
"when": "delayed",
"start_in": "10 min",
"timeout": "1h",
"retry": 1,
"only": {
"changes": ["Dockerfile", "docker/scripts/*"]
}
},
"deploy": {
"services": [
{
"name": "sql:latest",
"entrypoint": [""],
"command": ["/usr/bin/super-sql", "run"],
"alias": "super-sql"
},
"sql:latest",
{
"name": "sql:latest",
"alias": "default-sql"
}
],
"script": "dostuff",
"stage": "deploy",
"environment": {
"name": "prod",
"url": "http://example.com",
"on_stop": "stop-deploy"
},
"only": ["master"],
"release": {
"name": "Release $CI_COMMIT_TAG",
"description": "Created using the release-cli $EXTRA_DESCRIPTION",
"tag_name": "$CI_COMMIT_TAG",
"ref": "$CI_COMMIT_TAG",
"milestones": ["m1", "m2", "m3"],
"released_at": "2020-07-15T08:00:00Z",
"assets": {
"links": [
{
"name": "asset1",
"url": "https://example.com/assets/1"
},
{
"name": "asset2",
"url": "https://example.com/assets/2",
"filepath": "/pretty/url/1",
"link_type": "other"
},
{
"name": "asset3",
"url": "https://example.com/assets/3",
"link_type": "runbook"
},
{
"name": "asset4",
"url": "https://example.com/assets/4",
"link_type": "package"
},
{
"name": "asset5",
"url": "https://example.com/assets/5",
"link_type": "image"
}
]
}
}
},
".performance-tmpl": {
"after_script": ["echo after"],
"before_script": ["echo before"],
"variables": {
"SCRIPT_NOT_REQUIRED": "true"
}
},
"performance-a": {
"extends": ".performance-tmpl",
"script": "echo test"
},
"performance-b": {
"extends": ".performance-tmpl"
},
"workflow": {
"rules": [
{
"if": "$CI_COMMIT_REF_NAME =~ /-wip$/",
"when": "never"
},
{
"if": "$CI_COMMIT_TAG",
"when": "never"
},
{
"when": "always"
}
]
},
"job": {
"script": "echo Hello, Rules!",
"rules": [
{
"if": "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == \"master\"",
"when": "manual",
"allow_failure": true
}
]
},
"microservice_a": {
"trigger": {
"include": "path/to/microservice_a.yml"
}
},
"microservice_b": {
"trigger": {
"include": [{ "local": "path/to/microservice_b.yml" }, { "template": "SAST.gitlab-cy.yml" }],
"strategy": "depend"
}
},
"child-pipeline": {
"stage": "test",
"trigger": {
"include": [
{
"artifact": "generated-config.yml",
"job": "generate-config"
}
]
}
},
"child-pipeline-simple": {
"stage": "test",
"trigger": {
"include": "other/file.yml"
}
},
"complex": {
"stage": "deploy",
"trigger": {
"project": "my/deployment",
"branch": "stable"
}
},
"parallel-integer": {
"stage": "test",
"script": ["echo ${CI_NODE_INDEX} ${CI_NODE_TOTAL}"],
"parallel": 5
},
"parallel-matrix-simple": {
"stage": "test",
"script": ["echo ${MY_VARIABLE}"],
"parallel": {
"matrix": [
{
"MY_VARIABLE": 0
},
{
"MY_VARIABLE": "sample"
},
{
"MY_VARIABLE": ["element0", 1, "element2"]
}
]
}
},
"parallel-matrix-gitlab-docs": {
"stage": "deploy",
"script": ["bin/deploy"],
"parallel": {
"matrix": [
{
"PROVIDER": "aws",
"STACK": ["app1", "app2"]
},
{
"PROVIDER": "ovh",
"STACK": ["monitoring", "backup", "app"]
},
{
"PROVIDER": ["gcp", "vultr"],
"STACK": ["data", "processing"]
}
]
}
}
}

View File

@ -0,0 +1,54 @@
{
"default": {
"image": "ruby:2.4",
"before_script": ["echo Hello World"]
},
"variables": {
"DOMAIN": "example.com",
"WEBHOOK_URL": "https://my-webhook.example.com"
},
"rubocop": {
"inherit": {
"default": false,
"variables": false
},
"script": "bundle exec rubocop"
},
"rspec": {
"inherit": {
"default": ["image"],
"variables": ["WEBHOOK_URL"]
},
"script": "bundle exec rspec"
},
"capybara": {
"inherit": {
"variables": false
},
"script": "bundle exec capybara"
},
"karma": {
"inherit": {
"default": true,
"variables": ["DOMAIN"]
},
"script": "karma"
},
"inherit literally all": {
"inherit": {
"default": [
"after_script",
"artifacts",
"before_script",
"cache",
"image",
"interruptible",
"retry",
"services",
"tags",
"timeout"
]
},
"script": "true"
}
}

View File

@ -0,0 +1,24 @@
{
"test-job": {
"stage": "build",
"cache": [
{
"key": {
"files": ["Gemfile.lock"]
},
"paths": ["vendor/ruby"]
},
{
"key": {
"files": ["yarn.lock"]
},
"paths": [".yarn-cache/"]
}
],
"script": [
"bundle install --path=vendor",
"yarn install --cache-folder .yarn-cache",
"echo Run tests..."
]
}
}

View File

@ -0,0 +1,60 @@
{
"gitlab-ci-retry-int": {
"stage": "test",
"script": "rspec",
"retry": 2
},
"gitlab-ci-retry-object-no-max": {
"stage": "test",
"script": "rspec",
"retry": {
"when": "runner_system_failure"
}
},
"gitlab-ci-retry-object-single-when": {
"stage": "test",
"script": "rspec",
"retry": {
"max": 2,
"when": "runner_system_failure"
}
},
"gitlab-ci-retry-object-multiple-when": {
"stage": "test",
"script": "rspec",
"retry": {
"max": 2,
"when": ["runner_system_failure", "stuck_or_timeout_failure"]
}
},
"gitlab-ci-retry-object-multiple-when-dupes": {
"stage": "test",
"script": "rspec",
"retry": {
"max": 2,
"when": ["runner_system_failure", "runner_system_failure"]
}
},
"gitlab-ci-retry-object-all-when": {
"stage": "test",
"script": "rspec",
"retry": {
"max": 2,
"when": [
"always",
"unknown_failure",
"script_failure",
"api_failure",
"stuck_or_timeout_failure",
"runner_system_failure",
"runner_unsupported",
"stale_schedule",
"job_execution_timeout",
"archived_failure",
"unmet_prerequisites",
"scheduler_failure",
"data_integrity_failure"
]
}
}
}

View File

@ -0,0 +1,50 @@
{
"image": {
"name": "registry.gitlab.com/gitlab-org/gitlab-build-images:terraform",
"entrypoint": [
"/usr/bin/env",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
]
},
"variables": {
"PLAN": "plan.tfplan",
"JSON_PLAN_FILE": "tfplan.json"
},
"cache": {
"paths": [".terraform"]
},
"before_script": [
"alias convert_report=\"jq -r '([.resource_changes[]?.change.actions?]|flatten)|{\"create\":(map(select(.==\"create\"))|length),\"update\":(map(select(.==\"update\"))|length),\"delete\":(map(select(.==\"delete\"))|length)}'\"",
"terraform --version",
"terraform init"
],
"stages": ["validate", "build", "test", "deploy"],
"validate": {
"stage": "validate",
"script": ["terraform validate"]
},
"plan": {
"stage": "build",
"script": [
"terraform plan -out=$PLAN",
"terraform show --json $PLAN | convert_report > $JSON_PLAN_FILE"
],
"artifacts": {
"name": "plan",
"paths": ["$PLAN"],
"reports": {
"terraform": "$JSON_PLAN_FILE"
}
}
},
"apply": {
"stage": "deploy",
"environment": {
"name": "production"
},
"script": ["terraform apply -input=false $PLAN"],
"dependencies": ["plan"],
"when": "manual",
"only": ["master"]
}
}

View File

@ -0,0 +1,22 @@
{
"variables": {
"DEPLOY_ENVIRONMENT": {
"value": "staging",
"description": "The deployment target. Change this variable to 'canary' or 'production' if needed."
}
},
"gitlab-ci-variables-string": {
"stage": "test",
"script": ["true"],
"variables": {
"TEST_VAR": "String variable"
}
},
"gitlab-ci-variables-integer": {
"stage": "test",
"script": ["true"],
"variables": {
"canonical": 685230
}
}
}

View File

@ -0,0 +1,10 @@
{
"variables": {
"SOME_STR": "--batch-mode --errors --fail-at-end --show-version",
"SOME_INT": 10,
"SOME_USER_INPUT_FLAG": {
"value": "flag value",
"description": "Some Flag!"
}
}
}

View File

@ -0,0 +1,15 @@
# Covers https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70779
stages:
- prepare
# invalid cache:when value
job1:
stage: prepare
cache:
when: 0
# invalid cache:when value
job2:
stage: prepare
cache:
when: 'never'

View File

@ -0,0 +1,17 @@
# Covers https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70779
stages:
- prepare
# missing file property
childPipeline:
stage: prepare
trigger:
include:
- project: 'my-group/my-pipeline-library'
# missing project property
childPipeline2:
stage: prepare
trigger:
include:
- file: '.gitlab-ci.yml'

View File

@ -0,0 +1,25 @@
# Covers https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70779
stages:
- prepare
# test for cache:when values
job1:
stage: prepare
script:
- echo 'running job'
cache:
when: 'on_success'
job2:
stage: prepare
script:
- echo 'running job'
cache:
when: 'on_failure'
job3:
stage: prepare
script:
- echo 'running job'
cache:
when: 'always'

View File

@ -0,0 +1,18 @@
# Covers https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79335
deploy-template:
script:
- echo "hello world"
only:
- foo
except:
- bar
# null value allowed
deploy-without-only:
extends: deploy-template
only:
# null value allowed
deploy-without-except:
extends: deploy-template
except:

View File

@ -0,0 +1,32 @@
# Covers https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70779
# test for include:rules
include:
- local: builds.yml
rules:
- if: '$INCLUDE_BUILDS == "true"'
when: always
stages:
- prepare
# test for trigger:include
childPipeline:
stage: prepare
script:
- echo 'creating pipeline...'
trigger:
include:
- project: 'my-group/my-pipeline-library'
file: '.gitlab-ci.yml'
# accepts optional ref property
childPipeline2:
stage: prepare
script:
- echo 'creating pipeline...'
trigger:
include:
- project: 'my-group/my-pipeline-library'
file: '.gitlab-ci.yml'
ref: 'main'

View File

@ -0,0 +1,13 @@
# Covers https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74164
# test for workflow:rules:changes and workflow:rules:exists
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
exists:
- Dockerfile
changes:
- Dockerfile
variables:
IS_A_FEATURE: 'true'
when: always

View File

@ -228,6 +228,20 @@ RSpec.describe Backup::Manager do
end
end
context 'when SKIP env is set' do
let(:expected_backup_contents) { %w{backup_information.yml task1.tar.gz} }
before do
stub_env('SKIP', 'task2')
end
it 'executes tar' do
subject.create # rubocop:disable Rails/SaveBang
expect(Kernel).to have_received(:system).with(*tar_cmdline)
end
end
context 'when the destination is optional' do
let(:expected_backup_contents) { %w{backup_information.yml task1.tar.gz} }
let(:definitions) do

View File

@ -34,11 +34,11 @@ RSpec.describe Import::GithubService do
subject.execute(access_params, :github)
end
it 'returns an error' do
it 'returns an error with message and code' do
result = subject.execute(access_params, :github)
expect(result).to include(
message: 'Import failed due to a GitHub error: Not Found',
message: 'Import failed due to a GitHub error: Not Found (HTTP 404)',
status: :error,
http_status: :unprocessable_entity
)

View File

@ -2516,10 +2516,10 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0:
version "8.9.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18"
integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==
ajv@^8.0.0, ajv@^8.0.1, ajv@^8.10.0, ajv@^8.8.0:
version "8.10.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d"
integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"