[!NOTE|label:references:]

.gitconfig

$ git config --global gitreview.username <UserName>
$ git config --global gitreview.remote origin

default groups

[!TIP]

Special references

  • refs/changes/*
  • refs/meta/config
  • refs/meta/dashboards/*
  • refs/notes/review

Magic references

  • refs/for/<branch ref>

refs/meta/config

get project.config

  • clone the repo

    $ git clone <repo url>
    # or update the local repo to HEAD
    $ git pull [--rebase]
    
  • checkout meta/config

    $ git fetch origin refs/meta/config:refs/remotes/origin/meta/config
    $ git checkout meta/config
    

    or

    $ git fetch ssh://localhost:29418/project refs/meta/config
    $ git checkout FETCH_HEAD
    

publish to remote

$ git add --all .
$ git commit -m "<add your comments here>"
  • submit directly

    $ git push origin meta/config:meta/config
    

    or

    $ git push origin HEAD:refs/meta/config
    
  • submit review

    [!NOTE|label:references:]

    $ git push origin HEAD:refs/for/refs/meta/config
    
    • or
      $ git push origin meta/config:refs/for/refs/meta/config
      

update meta/config if remotes update

$ git fetch origin --force refs/meta/config:refs/remotes/origin/meta/config

$ git pull origin refs/meta/config
# or
$ git merge meta/config

reset to remotes

$ git fetch origin --force refs/meta/config:refs/remotes/origin/meta/config
$ git reset --hard remotes/origin/meta/config

useful refs

sandbox:

refs/heads/sandbox/${username}/*

its-jira:

  • for project specific

    [commentlink "its-jira"]
      match = ^[ \\t]*PROJECT-([0-9]{1,5}):
      link = https://<jira-domain>:<jira-port>/browse/PROJECT-$1
    
  • for common setup

    [plugin "its-jira"]
      association = OPTIONAL
      branch = ^refs/heads/.*
      branch = ^refs/heads/stable-.*
      commentOnChangeAbandoned = false
      commentOnChangeCreated = true
      commentOnChangeMerged = true
      commentOnChangeRestored = false
      commentOnCommentAdded = false
      commentOnFirstLinkedPatchSetCreated = true
      commentOnPatchSetCreated = false
      commentOnRefUpdatedGitWeb = true
      enabled = enforced
    [commentlink "its-jira"]
      match = ^[ \\t]*([A-Za-z]*-[0-9]{1,5}):
      link = https://<jira-domain>:<jira-port>/browse/$1
    [commentlink "changeid"]
      match = (I[0-9a-f]{8,40})
      link = "#/q/$1"
    

verified label

[label "Verified"]
    function = MaxWithBlock
    defaultValue = 0
    copyAllScoresIfNoCodeChange = true
    value = -1 Fails
    value =  0 No score
    value = +1 Verified

change-id

[receive]
  requireChangeId = true
  createNewChangeForAllNotInTarget = false
  maxObjectSizeLimit = 6m
  maxBatchChanges = 1
[commentlink "changeid"]
  match = (I[0-9a-f]{8,40})
  link = "#/q/$1"

freeze master branch

[!TIP] One quirk is that the shortest possible pattern expansion must be a valid ref name
thus ^refs/heads/.*/name will fail because refs/heads//name is not a valid reference
but ^refs/heads/.+/name will work.

About the refs/for namespace

[!TIP] references:

  • project.config

    [access "refs/for/refs/heads/master"]
      push = block group user/Marslo Jiao (marslo)
      push = block group Registered Users
      submit = block group Registered Users
      submit = block group group user/Marslo Jiao (marslo)
      addPatchSet = block group user/Marslo Jiao (marslo)
      addPatchSet = block group Registered Users
      pushMerge = block group user/Marslo Jiao (marslo)
      pushMerge = block group Registered Users
    
  • groups

    ...
    global:Project-Owners      Project Owners
    global:Registered-Users    Registered Users
    ...
    user:marslo                user/Marslo Jiao(marslo)
    ...
    

freeze multiple branches (stable & release) for the specific account

  • project.config

    [access "^refs/for/refs/heads/(stable|release)$"]
      push = block group Registered Users
      submit = block group Registered Users
      addPatchSet = block group Registered Users
      pushMerge = block group Registered Users
    [access "^refs/heads/(stable|release)$"]
      read = group user/Marslo Jiao (marslo)
      push = +force group user/Marslo Jiao (marslo)
      pushMerge = group user/Marslo Jiao (marslo)
    
    • or using exclusiveGroupPermissions
      [access "^refs/heads/backup/(master|dev|staging|stable)/.+$"]
             exclusiveGroupPermissions = create delete push pushMerge
             create = group Project Owners
             create = block group Registered Users
             delete = block group Registered Users
             push = block group Registered Users
             pushMerge = block group Registered Users
      [access "^refs/for/refs/heads/backup/(master|dev|staging|stable)/.+$"]
             exclusiveGroupPermissions = addPatchSet create push pushMerge submit
             addPatchSet = block group Registered Users
             create = block group Registered Users
             push = block group Registered Users
             pushMerge = block group Registered Users
             submit = block group Registered Users
      
  • groups

    ...
    global:Project-Owners      Project Owners
    global:Registered-Users    Registered Users
    ...
    user:marslo                user/Marslo Jiao(marslo)
    ...
    

restriction for branches (feature1, feature2 and master) for only allow code review merge, forbidden code push

  • project.config

    [access "refs/*"]
      read = group Project Owners
      read = group user/Marslo Jiao (marslo)
    [access "refs/for/*"]
      addPatchSet = group Project Owners
      addPatchSet = group user/Marslo Jiao (marslo)
      push = group Project Owners
      push = group user/Marslo Jiao (marslo)
      pushMerge = group Project Owners
      pushMerge = group user/Marslo Jiao (marslo)
    [access "^refs/heads/(feature1|feature2|master)$"]
      push = block group Registered Users
      pushMerge = block group Registered Users
      submit = group Change Owner
    
  • groups

    ...
    global:Project-Owners      Project Owners
    global:Registered-Users    Registered Users
    ...
    user:marslo                user/Marslo Jiao(marslo)
    ...
    

example of project.config

  • project.config
    [project]
      description = Gerrit Code Review
    [access "refs/*"]
      owner = group google/gerritcodereview-maintainers@googlegroups.com
    [access "refs/heads/*"]
      label-Code-Review = -2..+2 group google/gerritcodereview-maintainers@googlegroups.com
      label-Code-Review = -2..+2 group polygerrit-maintainers
      label-Verified = -1..+1 group Change Owner
      label-Verified = -1..+1 group gerrit-verifiers
      label-Code-Style = -1..+1 group gerrit-verifiers
      label-Verified-Notedb = -1..+1 group gerrit-verifiers
      label-Library-Compliance = -1..+1 group gerrit-lib
      label-Library-Compliance = -1..+0 group google/gerritcodereview-maintainers@googlegroups.com
      submit = group Change Owner
      submit = group google/gerritcodereview-maintainers@googlegroups.com
      create = group google/gerritcodereview-maintainers@googlegroups.com
      abandon = group gerrit-verifiers
      editTopicName = +force group google/gerritcodereview-maintainers@googlegroups.com
      removeReviewer = group google/gerritcodereview-maintainers@googlegroups.com
      publishDrafts = group google/gerritcodereview-maintainers@googlegroups.com
    [access "refs/tags/*"]
      create = group gerrit-release-creators
      create = group google/gerritcodereview-maintainers@googlegroups.com
      createTag = group gerrit-release-creators
      createTag = group google/gerritcodereview-maintainers@googlegroups.com
      createSignedTag = group gerrit-release-creators
      createSignedTag = group google/gerritcodereview-maintainers@googlegroups.com
    [access]
      inheritFrom = Public-Projects
    [receive]
      rejectImplicitMerges = true
    [reviewer]
      enableByEmail = true
    [label "Verified"]
      function = MaxNoBlock
      copyAllScoresIfNoCodeChange = true
      value = -1 Fails
      value = 0 No score
      value = +1 Verified
      defaultValue = 0
    [label "Code-Style"]
      function = MaxWithBlock
      copyAllScoresIfNoCodeChange = true
      value = -1 Wrong Style or Formatting
      value = 0 No score
      value = +1 Style Verified
      defaultValue = 0
    [label "Library-Compliance"]
      function = MaxWithBlock
      copyAllScoresIfNoCodeChange = true
      copyAllScoresOnTrivialRebase = true
      value = -1 Do not submit
      value = 0 No score
      value = +1 Approved
      defaultValue = 0
    [access "refs/for/refs/meta/dashboards/*"]
      push = group google/gerritcodereview-maintainers@googlegroups.com
    [access "refs/meta/dashboards/*"]
      label-Code-Review = -2..+2 group google/gerritcodereview-maintainers@googlegroups.com
      label-Code-Review = -1..+1 group Registered Users
      label-Verified = -1..+1 group gerrit-verifiers
      label-Verified = -1..+1 group google/gerritcodereview-maintainers@googlegroups.com
      submit = group google/gerritcodereview-maintainers@googlegroups.com
      forgeAuthor = group google/gerritcodereview-maintainers@googlegroups.com
      label-Code-Style = -1..+1 group google/gerritcodereview-maintainers@googlegroups.com
    [access "refs/for/refs/meta/config"]
      push = group gerrit-verifiers
    [notify "polygerrit-reviews"]
      email = polygerrit-reviews@google.com
      type = all_comments
      type = submitted_changes
      header = cc
      filter = file:polygerrit-ui
    [access "refs/heads/infra/config"]
      push = group gerrit-tricium-admins
    

rules.pl

submit by a non author

[!TIP] check also:

submit_rule(S) :-
    gerrit:default_submit(X),
    X =.. [submit | Ls],
    add_non_author_approval(Ls, R),
    S =.. [submit | R].

add_non_author_approval(S1, S2) :-
    gerrit:commit_author(A),
    gerrit:commit_label(label('Code-Review', 2), R),
    R \= A, !,
    S2 = [label('Non-Author-Code-Review', ok(R)) | S1].
add_non_author_approval(S1, [label('Non-Author-Code-Review', need(_)) | S1]).
non author cr
1.4.3.6.1 -- non author cr
  • by project.config
    [access "refs/*"]
      label-Code-Review = block -2..+2 group Change Owner
      exclusiveGroupPermissions = label-Code-Review
    

ticket check

[!TIP] check also:

  • optional validation

    submit_rule(S) :-
        gerrit:default_submit(X),
        X =.. [submit | Ls],
        require_ticket_check_for_ticket(Ls, Nls),
        S =.. [submit | Nls].
    
    require_ticket_check_for_ticket(S1, S2) :-
        gerrit:commit_message_matches('^issue-[\\d]+\\s?:\\s?[\\w\\W]+'),
        !,
        S2 = [label('Ticket-Checked', need(_)) | S1].
    
    require_ticket_check_for_ticket(S1, S2) :-
        !, S2 = S1.
    
optional-check
1.4.3.6.2 -- optional-check
  • optional validation with auto vote

    submit_rule(S) :-
        gerrit:default_submit(X),
        X =.. [submit | Ls],
        require_ticket_check_for_ticket(Ls, Nls),
        S =.. [submit | Nls].
    
    require_ticket_check_for_ticket(S1, S2) :-
        gerrit:commit_message_matches('\\[issue-[\\d]{2}\\]\\s?:\\s?[\\w\\W]+'),
        !,
        S2 = [label('Ticket-Checked', ok(user(824))) | S1].
    
    require_ticket_check_for_ticket(S1, S2) :-
        !, S2 = S1.
    
optional-check-autovote
1.4.3.6.3 -- optional-check-autovote
optional-check-autovote
1.4.3.6.4 -- optional-check-autovote
  • mandatory validation

    submit_rule(S) :-
      gerrit:default_submit(X), % get the current submit structure
      X=.. [submit | Ls],
      require_ticket_check_for_ticket(Ls, Nls),
      S=.. [submit | Nls].
    
    require_ticket_check_for_ticket(S1, S2) :-
       gerrit:commit_message_matches('\\[issue-[\\d]{2}\\][\\s\\S]+'),
       !,
       S2 = [label('Ticket-Checked', ok(user(790))) | S1]. % Add the label and automatically approval by user-id: 790
    
    require_ticket_check_for_ticket(S1, [label('Ticket-Checked', need(_)) | S1]).
    
mandatory check
1.4.3.6.5 -- mandatory check
mandatory check
1.4.3.6.6 -- mandatory check

api

basic usage

regular options

                                  a might means [a]pi
                                    ⇡
$ curl -X PUT    http://domain.name/a/path/to/api/
$ curl -X POST   http://domain.name/a/path/to/api/
$ curl -X DELETE http://domain.name/a/path/to/api/

sending data

  • json with file

    $ curl -X PUT \
           -d@testdata.json \
           --header "Content-Type: application/json" \
           http://domain.name/a/path/to/api/
    
  • json with string

    $ curl -X POST \
           -H "Content-Type: application/json" https://domain.name/a/changes/<number>/move \
           -d '{ "destination_branch" : "target/branch/name" }'
    )]}'
    {
      "id": "marslo-project~target%2Fbranch%2Fname~Id90057ab632eb93be2fa9128a9d624664008cb4a",
      "project": "marslo-project",
      "branch": "target/branch/name",
      "hashtags": [],
      "change_id": "Id90057ab632eb93be2fa9128a9d624664008cb4a",
      "subject": "marslo: testing api move",
      "status": "NEW",
      "created": "2022-01-21 05:21:25.000000000",
      "updated": "2022-05-17 06:56:37.000000000",
      "submit_type": "FAST_FORWARD_ONLY",
      "mergeable": false,
      "insertions": 8,
      "deletions": 8,
      "unresolved_comment_count": 0,
      "has_review_started": true,
      "_number": 94490,
      "owner": {
        "_account_id": 790
      },
      "requirements": []
    }
    
    # or
    $ curl -X POST \
           -H "Content-Type: application/json" https://domain.name/a/changes/<number>/move \
           -d '{
                "destination_branch" : "target/branch/name"
           }' |
      tail -n +2 |
      jq -r .branch
    
  • txt

    $ curl -X PUT \
           --data-binary @testdata.txt \
           --header "Content-Type: text/plain" \
           http://domain.name/a/path/to/api/
    

verifying header content

  $ curl -v -n -X DELETE http://domain.name/a/path/to/api/

change

  • get change via change-id

    $ curl -X GET 'https://domina.name/a/changes/<change-id>'
    
  • get change via commit-id

    $ changeid=$(git show <commit-id> --no-patch --format="%s%n%n%b" | sed -nre 's!Change-Id: (.*$)!\1!p')
    $ curl -X GET "https://domina.name/a/changes/${changeid}"
    

    or

    $ project=$(echo 'path/to/project' | sed 's:/:%2F:g')
    $ branch='dev'
    $ changeid=$(git show <commit-id> --no-patch --format="%s%n%n%b" | sed -nre 's!Change-Id: (.*$)!\1!p')
    $ curl -X GET "https://domina.name/a/changes/${project}~${branch}~${changeid}"
    

who approval the CR+2

$ curl -s -X GET https://domain.name/a/changes/${changeid}/detail |
       tail -n +2 |
       jq -r '.labels."Code-Review".approved.name'

get all vote CR-2

  • example output for .labels.<tag>.all[]
    {
    "value": -2,
    "date": "2021-05-31 07:57:14.000000000",
    "permitted_voting_range": {
      "min": -2,
      "max": 2
    },
    "_account_id": 790,
    "name": "Marslo Jiao",
    "email": "marslo.jiao@gmail.com",
    "username": "marslo"
    }
    {
    "value": 0,
    "permitted_voting_range": {
      "min": -2,
      "max": 2
    },
    "_account_id": 124,
    "name": "John Doe",
    "email": "john@gmail.com",
    "username": "john"
    }
    

reference:

$ curl -s -X GET https://domain.name/a/changes/${changeid}/detail |
       tail -n +2 |
       jq -r '.labels."Code-Review".all[] | select ( .value == -2 ) | .username'
#                                         : |⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂| :
#                                         :           ⇣             :
#                                         :  select ".value"== -2   :
#                                         :                         :
#                                         ⇣                         ⇣
#                                        pipe                     pipe

# or
$ curl -s -X GET https://domain.name/a/changes/${changeid}/detail |
       tail -n +2 |
      jq -r '( .labels."Code-Review".all[] | select ( .value == -2 ) ).username'
             :                                                       :
             ⇣                                                       ⇣
         expression                                              expression

# or
$ curl -s -X GET https://domain.name/a/changes/${changeid}/detail |
       tail -n +2 |
      jq -r '[ .labels."Code-Review".all[] | select ( .value == -2 ) ][].username'
             :                                                       :
             ⇣                                                       ⇣
         expression                                              expression

# or
$ curl -s -X GET https://domain.name/a/changes/${changeid}/detail |
       tail -n +2 |
      jq -r '.labels."Code-Review".all[] | select ( .value == -2 )' |
      jq -r .username                                               :
                                                                    ⇣
                                                                   pipe

who approval the V+1

$ curl -s -X GET https://domain.name/a/changes/${changeid}/detail |
       tail -n +2 |
       jq -r .labels.Verified.approved.username

access list contains account

[!NOTE]

# i.e. : check all repos who contains account marslo@sample.com
$ while read -r _proj; do
    output=$( curl -fsSL https://gerrit.sample.com/a/projects/"${_proj}"/access |
              tail -n+2 |
              jq -r '.. | .rules? | select(. != null) | keys[] | ascii_downcase | select(contains("marslo@sample.com"))';
            )
    [[ -z "${output}" ]] || echo ">> https://gerrit.sample.com/admin/repos/$(sed 's:%2F:/:g' <<< "${_proj}")"
  done < <( curl -fsSL https://gerrit.sample.com/a/projects/?d |
                  tail -n+2 |
                  jq -r '.[].id' |
                  grep --color=never -E 'keyword|keyword'
          )

all reviews at a certain time

[!NOTE|label:references:]

project='PROJECT'
branch='BRANCH'
start='2023-01-01'
end='2024-01-01'
curlOpt='--silent --insecure --globoff --netrc-file ~/.netrc'
query="project:${project}+branch:${branch}+after:${start}+before:${end}"
filter by status if necessary
query="${query}+is:closed+-is:abandoned"

echo ">> ${project} ~ ${branch}"
while IFS='|' read -r _change_id _id; do
  echo -e "\t- [${_id}] [_change_id]"
$( eval "curl ${curlOpt} 'https://gerrit.sample.com/a/changes/?q=${query}'" |
         tail -n +2 |
         jq -r '.[] | .change_id + "|" + .id'
 )

get review rate in certain time

sum=0
rnum=0
onum=0
echo ">> ${project} ~ ${branch}"
while IFS='|' read -r _change_id _id; do
  sum=$(( sum+1 ))
  output=$( eval "curl ${curlOpt} 'https://gerrit.sample.com/a/changes/${_id}/detail' | tail -n+2" )
  reviewed=$( jq -r '.labels."Code-Review".all[] | select(.value != null) | select( .value | contains(2) ) | .username' <<< "${output}" )
  owned=$( jq -r '.owner.username' <<< "${output}" )
  if grep 'marslo' <<< "${reviewed}" >/dev/null; then rnum=$(( rnum+1 )); fi
  if grep 'marslo' <<< "${owned}"    >/dev/null; then onum=$(( onum+1 )); fi
$( eval "curl ${curlOpt} 'https://gerrit.sample.com/a/changes/?q=${query}'" |
         tail -n +2 |
         jq -r '.[] | .change_id + "|" + .id'
 )
echo "${sum} ${rnum} ${onum} $(( sum-onum ))" |
      awk '{ sum=$1; reviewed=$2; owned=$3; rsum=$4; rate=$2*100/$4 } END { printf("\t- gerrit review: %s/(%s-%s) ( %s% )\n", reviewed, sum, owned, rate) }'

list gerrit projects with certain account

$ account='marslo'
$ id=1
$ gerritUrl='https://gerrit.sample.com'

$ while read -r _proj; do
    output=$( curl -fsSL "${gerritUrl}"/a/projects/"${_proj}"/access |
              tail -n+2 |
              jq -r --arg ACCOUNT "${account}" '.. | ."rules"? | select(. != null) | keys[] | ascii_downcase | select(contains($ACCOUNT))';
            )
    [[ -n "${output}" ]] && echo "[${id}] >> "${gerritUrl}"/admin/repos/$(sed 's:%2F:/:g' <<< "${_proj}")" && ((id++));
  done < <( curl -fsSL "${gerritUrl}"/a/projects/?d | tail -n+2 | jq -r '.[].id' )

reference

integrate in Jenkins

[!NOTE|label:references:]

  • stream-events

    # permission requires
    $ ssh -i id_rsa jenkins@gerrit.domain.com -p 29418 gerrit stream-events
    stream events not permitted
    
    # verify
    $ ssh -i id_rsa jenkins@gerrit.domain.com -p 29418 gerrit stream-events | jq -r .type
    ref-updated
    comment-added
    
  • build current patches only

    [!NOTE] Warning: The current implementation takes into account that 'Build Current Patches Only' with 'Abort new patch sets' and 'Abort patch sets with same topic' are enabled (see help for more).

    gerrit trigger
    1.4.3.6.7 -- gerrit trigger
  • generate ssh-key

    $ keyname='devops@jenkins'
    $ ssh-keygen -m PEM -t rsa -f ~/.ssh/${keyname} -C "${keyname}" -P '' -q
    

css for code block

.gr-formatted-text-0 gr-linked-text.pre.gr-formatted-text,
gr-linked-text[class*="pre"], gr-linked-text[class*="pre"] #output {
  font-family: "Comic Mono", "Monaco", "Menlo", "Andale Mono", "Ubuntu Mono", "monofur" !important;
  font-size: 16px !important;
}
.gr-formatted-text-0 gr-linked-text.pre.gr-formatted-text,
gr-linked-text[class*="pre"] {
  color: #c8c8c8 !important;
  background: #272727 !important;
  border-radius: .75em !important;
  box-shadow: 0 4px 8px 0 rgb(0 0 0 / 20%), 0 6px 20px 0 rgb(0 0 0 / 19%);
  overflow: auto;
  display: block;
  padding: 12px 12px 1px 12px;
  margin: 0px;
}
  • gruvbox

    • background : #272727
    • front-color: #e8dbb6
    gruvbox code block
    1.4.3.6.8 -- gruvbox code block
  • ubunut

    • background : #3a122e
    • front-color: #eee
    ubuntu code block
    1.4.3.6.9 -- ubuntu code block
  • solarized

    • background : #0d2a34
    • front-color: #869395
    solarized code block
    1.4.3.6.10 -- solarized code block
Copyright © marslo 2020-2023 all right reserved,powered by GitbookLast Modified: 2024-05-01 13:19:23

results matching ""

    No results matching ""