Allow commit API to create an empty commit

What does this MR do and why?

It allows commit API, REST & GraphQL, to create an empty commit when:

  • actions argument is not present
  • actions is present and empty

Similiar to git cli, this Merge Request enforces that allow_empty/allowEmpty argument must be provided to allow this behavior.

References

#18601 (closed)
#512660 (closed)
#584164

Screenshots or screen recordings

Before After

How to set up and validate locally

GitLab GDK

Mandatory REST & GraphQL: create `allow_empty` branch
# Create allow_empty branch
curl --request POST "http://127.0.0.1:3000/api/v4/projects/gitlab-org%2fgitlab-test/repository/branches" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
    "branch": "allow_empty",
    "ref": "master"
  }'
REST empty commit OK without actions
# REST empty commit OK without actions
curl --request POST "http://127.0.0.1:3000/api/v4/projects/gitlab-org%2fgitlab-test/repository/commits" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
    "branch": "allow_empty",
    "commit_message": "REST empty commit OK without actions",
    "allow_empty": true
  }'
REST empty commit OK with empty actions
# REST empty commit OK with empty actions
curl --request POST "http://127.0.0.1:3000/api/v4/projects/gitlab-org%2fgitlab-test/repository/commits" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
    "branch": "allow_empty",
    "commit_message": "REST empty commit OK with empty actions",
    "allow_empty": true,
    "actions": []
  }'
REST empty commit KO with empty actions (allow_empty false)
# REST empty commit KO with empty actions (allow_empty false)
curl --request POST "http://127.0.0.1:3000/api/v4/projects/gitlab-org%2fgitlab-test/repository/commits" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
    "branch": "allow_empty",
    "commit_message": "REST empty commit KO with empty actions (allow_empty false)",
    "allow_empty": false,
    "actions": []
  }'
REST empty commit KO without actions (missing allow_empty)
# REST empty commit KO without actions (missing allow_empty)
curl --request POST "http://127.0.0.1:3000/api/v4/projects/gitlab-org%2fgitlab-test/repository/commits" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
    "branch": "allow_empty",
    "commit_message": "REST empty commit KO without actions (missing allow_empty)"
  }'
REST empty commit KO without actions (allow_empty false)
# REST empty commit KO without actions (allow_empty false)
curl --request POST "http://127.0.0.1:3000/api/v4/projects/gitlab-org%2fgitlab-test/repository/commits" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
    "branch": "allow_empty",
    "commit_message": "REST empty commit KO without actions (allow_empty false)",
    "allow_empty": false
  }'
REST empty commit KO without actions (allow_empty not a boolean)
# REST empty commit KO without actions (allow_empty not a boolean)
curl --request POST "http://127.0.0.1:3000/api/v4/projects/gitlab-org%2fgitlab-test/repository/commits" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
    "branch": "allow_empty",
    "commit_message": "REST empty commit KO without actions (allow_empty not a boolean)",
    "allow_empty": 1
  }'
REST commit OK with actions (allow_empty true)
# REST commit OK with actions (allow_empty true)
curl --request POST "http://127.0.0.1:3000/api/v4/projects/gitlab-org%2fgitlab-test/repository/commits" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
    "branch": "new-file-rest-allow-empty-not-boolean",
    "start_branch": "master",
    "commit_message": "REST commit OK with actions (allow_empty true)",
    "actions": [
      {
        "action": "create",
        "file_path": "new-file-rest-allow-empty-not-boolean.md",
        "content": "REST commit OK with actions (allow_empty true)"
      }
    ],
    "allow_empty": true
  }'
GraphQL empty commit OK without actions
# GraphQL empty commit OK without actions
curl --request POST "http://127.0.0.1:3000/api/graphql" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
  "query": "mutation Create($project: ID!, $branch: String!, $message: String!, $allowEmpty: Boolean!) { commitCreate(input: { projectPath: $project, branch: $branch, message: $message, allowEmpty: $allowEmpty }) { commit { sha title } errors }}",
  "variables": {
    "project": "gitlab-org/gitlab-test",
    "branch": "allow_empty",
    "message": "GraphQL empty commit OK without actions",
    "allowEmpty": true
  }
}'
GraphQL empty commit OK with empty actions
# GraphQL empty commit OK with empty actions
curl --request POST "http://127.0.0.1:3000/api/graphql" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
  "query": "mutation Create($project: ID!, $branch: String!, $message: String!, $actions: [CommitAction!]!, $allowEmpty: Boolean!) { commitCreate(input: { projectPath: $project, branch: $branch, message: $message, actions: $actions, allowEmpty: $allowEmpty }) { commit { sha title } errors }}",
  "variables": {
    "project": "gitlab-org/gitlab-test",
    "branch": "allow_empty",
    "message": "GraphQL empty commit OK with empty actions",
    "actions": [],
    "allowEmpty": true
  }
}'
GraphQL empty commit KO with empty actions (allow_empty false)
# GraphQL empty commit KO with empty actions (allow_empty false)
curl --request POST "http://127.0.0.1:3000/api/graphql" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
  "query": "mutation Create($project: ID!, $branch: String!, $startBranch: String!, $message: String!, $actions: [CommitAction!]!, $allowEmpty: Boolean!) { commitCreate(input: { projectPath: $project, branch: $branch, startBranch: $startBranch, message: $message, actions: $actions, allowEmpty: $allowEmpty }) { commit { sha title } errors }}",
  "variables": {
    "project": "gitlab-org/gitlab-test",
    "branch": "allow-empty-false",
    "startBranch": "master",
    "message": "GraphQL empty commit KO with empty actions (allow_empty false)",
    "actions": [],
    "allowEmpty": false
  }
}'
GraphQL empty commit KO without actions (missing allow_empty)
# GraphQL empty commit KO without actions (missing allow_empty)
curl --request POST "http://127.0.0.1:3000/api/graphql" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
  "query": "mutation Create($project: ID!, $branch: String!, $message: String!) { commitCreate(input: { projectPath: $project, branch: $branch, message: $message }) { commit { sha title } errors }}",
  "variables": {
    "project": "gitlab-org/gitlab-test",
    "branch": "allow_empty",
    "message": "GraphQL empty commit KO without actions (missing allow_empty)"
  }
}'
GraphQL empty commit KO without actions (allow_empty false)
# GraphQL empty commit KO without actions (allow_empty false)
curl --request POST "http://127.0.0.1:3000/api/graphql" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
  "query": "mutation Create($project: ID!, $branch: String!, $message: String!, $allowEmpty: Boolean!) { commitCreate(input: { projectPath: $project, branch: $branch, message: $message, allowEmpty: $allowEmpty }) { commit { sha title } errors }}",
  "variables": {
    "project": "gitlab-org/gitlab-test",
    "branch": "allow_empty",
    "message": "GraphQL empty commit KO without actions (allow_empty false)",
    "allowEmpty": false
  }
}'
GraphQL empty commit KO without actions (allow_empty not a boolean)
# GraphQL empty commit KO without actions (allow_empty not a boolean)
curl --request POST "http://127.0.0.1:3000/api/graphql" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
  "query": "mutation Create($project: ID!, $branch: String!, $message: String!, $allowEmpty: Int!) { commitCreate(input: { projectPath: $project, branch: $branch, message: $message, allowEmpty: $allowEmpty }) { commit { sha title } errors }}",
  "variables": {
    "project": "gitlab-org/gitlab-test",
    "branch": "allow_empty",
    "message": "GraphQL empty commit KO without actions (allow_empty not a boolean)",
    "allowEmpty": 2
  }
}'
GraphQL commit OK with actions (allow_empty true)
# GraphQL commit OK with actions (allow_empty true)
curl --request POST "http://127.0.0.1:3000/api/graphql" \
  --header "PRIVATE-TOKEN: ypCa3Dzb23o5nvsixwPA" \
  --header "Content-Type: application/json" \
  --data '{
  "query": "mutation Create($project: ID!, $branch: String!, $startBranch: String!, $message: String!, $actions: [CommitAction!]!) { commitCreate(input: { projectPath: $project, branch: $branch, startBranch: $startBranch, message: $message, actions: $actions }) { commit { sha title } errors }}",
  "variables": {
    "project": "gitlab-org/gitlab-test",
    "branch": "new-file-graphql-allow-empty",
    "startBranch": "master",
    "message": "GraphQL commit OK with actions (allow_empty true)",
    "actions": [
      { "action": "CREATE", "filePath": "new-file-graphql-allow-empty.md", "content": "Hello from GraphQL" }
    ],
    "allowEmpty": true
  }
}'

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Guillaume Chauvel

Merge request reports

Loading