Fork project into group for a new contributor (API) - gitlab

For the possibility that there is a better approach that I'm thinking about I would like to explain my requirement first (the question starts after the divider line).
Given I have the following GitLab group structure:
- main-group
- sub-group-project-templates
- project-template-1
- sub-group-projects
In main-group/sub-group-project-templates there are multiple projects that function as starter project for a task.
If there is someone who wants to do such a task I want to have a fork of the corresponding project template (e.g. project-template-1) in the group sub-group-projects with the name of the person as project name.
Given the name of the person is John Doe who wants to start the task of project-template-1 there should be a new project main-group/sub-group-projects/john_doe_project-template-1.
John Doe should only be able to see (read / write) the repository john_doe_project-template-1 and NOT the rest of the project (other forks, ...).
My solution would be to fork the template project to the sub group and then add a new contributor.
But I already fail at the first step (forking the project into the sub group with a new name).
My first shot at it was looking at:
POST http://gitlab.com/api/v4/projects/project_id/fork
But I don't know how to define the target directory and set the name of the new fork.
The following isn't working:
POST http://gitlab.com/api/v4/projects/project_id/fork?namespace=main-group%2Fsub-group-projects%2Fjohn_doe_project-template-1
"message": "404 Target Namespace Not Found"
Is something like this even possible or how can I achieve this?

Supposing you have the following configuration with project project-template-1 in subgroup sub-group-project-templates :
It can be done in multiple API requests but there are some work-in-progress for the following features:
(1) forking a project with namespace in a subgroup doesn't work
(2) choosing a custom name when forking is not implemented
But these 2 issues have workarounds eg just perform an additionnal request to get the namespace id (1) and perform an edit project request (2) after forking
The steps are the following :
get namespace id for the subgroup sub-group-projects
fork project main-group/sub-group-project-templates/project-template-1 to namespace with id $namespace_id & get the project id of the created project
rename project with id $project_id from project-template-1 to : johndoe_project-template-1
get user id for user johndoe
add project member for project johndoe_project-template-1 : add user with id $user_id
Note that to add a member, you need the user id which I assume you want to search in the 4th step but you may not need this step if you already have it
Here is a bash script performing all these step, it uses curl & jq :
#!/bin/bash
set -e
gitlab_host=gitlab.your.host
access_token=YOUR_ACCESS_TOKEN
username=johndoe
project=project-template-1
user_access=30
group=main-group
namespace_src=sub-group-project-templates
namespace_dest=sub-group-projects
new_project_name=${username}_${project}
project_src=$group/$namespace_src/$project
encoded_project=$(echo $project_src | sed 's/\//%2F/g')
echo "1 - get namespace id for $namespace_dest"
#https://docs.gitlab.com/ce/api/namespaces.html
namespace_id=$(curl -s "https://$gitlab_host/api/v4/namespaces?search=$namespace_dest" \
-H "Private-Token: $access_token" | jq -r '.[0].id')
echo "2 - fork project $project_src to namespace with id $namespace_id"
#https://docs.gitlab.com/ce/api/projects.html#fork-project
project_id=$(curl -s -X POST "https://$gitlab_host/api/v4/projects/$encoded_project/fork?namespace=$namespace_id" \
-H "Private-Token: $access_token" | jq '.id')
if [ -z $project_id ]; then
echo "fork failed"
exit 1
fi
echo "3 - rename project with id $project_id from $project to : $new_project_name"
#https://docs.gitlab.com/ce/api/projects.html#edit-project
curl -s -X PUT "https://$gitlab_host/api/v4/projects/$project_id" \
-H "Content-Type: application/json" \
-d "{\"path\": \"$new_project_name\",\"name\": \"$new_project_name\" }" \
-H "Private-Token: $access_token" > /dev/null
echo "4 - get user id for : $username"
#https://docs.gitlab.com/ce/api/users.html
user_id=$(curl -s "https://$gitlab_host/api/v4/users?username=johndoe" \
-H "Private-Token: $access_token" | \
jq -r '.[] | select(.name == "johndoe") | .id')
echo "5 - edit project member : add user with id $user_id"
#https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project
curl -s "https://$gitlab_host/api/v4/projects/$project_id/members" \
-H "Private-Token: $access_token" \
-d "user_id=$user_id&access_level=$user_access" > /dev/null
In the 2nd step (fork project), project source namespace is URL encoded so you may want to use a proper manner to encode it (in this case we only have to replace / with %2F)

Related

How can we clone all subgroups under a group in gitlab at one shot [duplicate]

In my GitLab repository, I have a group with 20 projects. I want to clone all projects at once. Is that possible?
One liner with curl, jq, tr:
for repo in $(curl -s --header "PRIVATE-TOKEN: your_private_token" https://<your-host>/api/v4/groups/<group_id> | jq -r ".projects[].ssh_url_to_repo"); do git clone $repo; done;
For Gitlab.com use https://gitlab.com/api/v4/groups/<group_id>
To include subgroups add include_subgroups=true query param like
https://<your-host>/api/v4/groups/<group_id>?include_subgroups=true
Note: To clone with http url use http_url_to_repo instead of ssh_url_to_repo in jq (Thanks #MattVon for the comment)
Update Dec. 2022, use glab repo clone
glab repo clone -g <group> -p --paginate
With:
-p, --preserve-namespace: Clone the repo in a subdirectory based on namespace
--paginate: Make additional HTTP requests to fetch all pages of projects before cloning. Respects --per-page
That does support cloning more than 100 repositories (since MR 1030, and glab v1.24.0, Dec. 2022)
This is for gitlab.com or for a self-managed GitLab instance, provided you set the environment variable GITLAB_URI or GITLAB_HOST: it specifies the URL of the GitLab server if self-managed (eg: https://gitlab.example.com).
Original answer and updates (starting March 2015):
Not really, unless:
you have a 21st project which references the other 20 as submodules.
(in which case a clone followed by a git submodule update --init would be enough to get all 20 projects cloned and checked out)
or you somehow list the projects you have access (GitLab API for projects), and loop on that result to clone each one (meaning that can be scripted, and then executed as "one" command)
Since 2015, Jay Gabez mentions in the comments (August 2019) the tool gabrie30/ghorg
ghorg allows you to quickly clone all of an org's or user's repos into a single directory.
Usage:
$ ghorg clone someorg
$ ghorg clone someuser --clone-type=user --protocol=ssh --branch=develop
$ ghorg clone gitlab-org --scm=gitlab --namespace=gitlab-org/security-products
$ ghorg clone --help
Also (2020): https://github.com/ezbz/gitlabber
usage: gitlabber [-h] [-t token] [-u url] [--debug] [-p]
[--print-format {json,yaml,tree}] [-i csv] [-x csv]
[--version]
[dest]
Gitlabber - clones or pulls entire groups/projects tree from gitlab
Here's an example in Python 3:
from urllib.request import urlopen
import json
import subprocess, shlex
allProjects = urlopen("https://[yourServer:port]/api/v4/projects?private_token=[yourPrivateTokenFromUserProfile]&per_page=100000")
allProjectsDict = json.loads(allProjects.read().decode())
for thisProject in allProjectsDict:
try:
thisProjectURL = thisProject['ssh_url_to_repo']
command = shlex.split('git clone %s' % thisProjectURL)
resultCode = subprocess.Popen(command)
except Exception as e:
print("Error on %s: %s" % (thisProjectURL, e.strerror))
There is a tool called myrepos, which manages multiple version controls repositories. Updating all repositories simply requires one command:
mr update
In order to register all gitlab projects to mr, here is a small python script. It requires the package python-gitlab installed:
import os
from subprocess import call
from gitlab import Gitlab
# Register a connection to a gitlab instance, using its URL and a user private token
gl = Gitlab('http://192.168.123.107', 'JVNSESs8EwWRx5yDxM5q')
groupsToSkip = ['aGroupYouDontWantToBeAdded']
gl.auth() # Connect to get the current user
gitBasePathRelative = "git/"
gitBasePathRelativeAbsolut = os.path.expanduser("~/" + gitBasePathRelative)
os.makedirs(gitBasePathRelativeAbsolut,exist_ok=True)
for p in gl.Project():
if not any(p.namespace.path in s for s in groupsToSkip):
pathToFolder = gitBasePathRelative + p.namespace.name + "/" + p.name
commandArray = ["mr", "config", pathToFolder, "checkout=git clone '" + p.ssh_url_to_repo + "' '" + p.name + "'"]
call(commandArray)
os.chdir(gitBasePathRelativeAbsolut)
call(["mr", "update"])
I built a script (curl, git, jq required) just for that. We use it and it works just fine: https://gist.github.com/JonasGroeger/1b5155e461036b557d0fb4b3307e1e75
To find out your namespace, its best to check the API quick:
curl "https://domain.com/api/v3/projects?private_token=$GITLAB_PRIVATE_TOKEN"
There, use "namespace.name" as NAMESPACE for your group.
The script essentially does:
Get all Projects that match your PROJECT_SEARCH_PARAM
Get their path and ssh_url_to_repo
2.1. If the directory path exists, cd into it and call git pull
2.2. If the directory path does not exist, call git clone
Here is another example of a bash script to clone all the repos in a group. The only dependency you need to install is jq (https://stedolan.github.io/jq/). Simply place the script into the directory you want to clone your projects into. Then run it as follows:
./myscript <group name> <private token> <gitlab url>
i.e.
./myscript group1 abc123tyn234 http://yourserver.git.com
Script:
#!/bin/bash
if command -v jq >/dev/null 2>&1; then
echo "jq parser found";
else
echo "this script requires the 'jq' json parser (https://stedolan.github.io/jq/).";
exit 1;
fi
if [ -z "$1" ]
then
echo "a group name arg is required"
exit 1;
fi
if [ -z "$2" ]
then
echo "an auth token arg is required. See $3/profile/account"
exit 1;
fi
if [ -z "$3" ]
then
echo "a gitlab URL is required."
exit 1;
fi
TOKEN="$2";
URL="$3/api/v3"
PREFIX="ssh_url_to_repo";
echo "Cloning all git projects in group $1";
GROUP_ID=$(curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups?search=$1 | jq '.[].id')
echo "group id was $GROUP_ID";
curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/$GROUP_ID/projects?per_page=100 | jq --arg p "$PREFIX" '.[] | .[$p]' | xargs -L1 git clone
Yep it's possible, here is the code.
prerequisites:
pip install python-gitlab
#!/usr/bin/python3
import os
import sys
import gitlab
import subprocess
glab = gitlab.Gitlab(f'https://{sys.argv[1]}', f'{sys.argv[3]}')
groups = glab.groups.list()
groupname = sys.argv[2]
for group in groups:
if group.name == groupname:
projects = group.projects.list(all=True)
for repo in projects:
command = f'git clone {repo.ssh_url_to_repo}'
process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
output, _ = process.communicate()
process.wait()
Example:
create .py file (ex. gitlab-downloader.py)
copy-paste code from above
on Linux OS (or OSX) do chmod +x on the script file (ex. chmod +x gitlab-downloader.py)
run it with 3 params: Gitlab hostname, groupname, your Personal Access Token(see https://gitlab.exmaple.com/profile/personal_access_tokens)
I created a tool for that: https://github.com/ezbz/gitlabber, you can use glob/regex expressions to select groups/subgroups you'd like to clone.
Say your top-level group is called MyGroup and you want to clone all projects under it to ~/GitlabRoot you can use the following command:
gitlabber -t <personal access token> -u <gitlab url> -i '/MyGroup**' ~/GitlabRoot
Lot of good answers, but here's my take. Use it if you:
want to clone everything in parallel
have your ssh keys configured to clone from the server without entering a password
don't want to bother creating an access token
are using a limited shell like git bash (without jq)
So, using your browser, acess https://gitlab.<gitlabserver>/api/v4/groups/<group name>?per_page=1000 download the json with all projects info and save it as a file named group.json.
Now just run this simple command in the same dir:
egrep -o 'git#[^"]+.git' group.json|xargs -n 1 -P 8 git clone
Increase the number in -P 8 to change the number of parallel processes. If you have more than a thousand repositories, increase the number after the perpage=.
If <group name> has spaces or accented chars, note that it must be url encoded.
If you want to automatize the download, the easiest way to authenticate is to generate a access token in GitLab/GitHub and put it in the url: https://user:access_toke#mygitlab.net/api/v4/groups/<group name>?per_page=1000.
Using curl, jq and tr and the same approach described previously, but for more than 20 projects:
for repo in $(curl --header "PRIVATE-TOKEN:<Private-Token>" -s "https://<your-host>/api/v4/groups/<group-id>/projects?include_subgroups=true&per_page=100&page=n" | jq '.[].ssh_url_to_repo' | tr -d '"'); do git clone $repo; done;
For Gitlab.com use https://gitlab.com/api/v4/groups/[group-id]/projects
Only need to iterate changing page number.
An updated Python 3 script that accomplishes this really effectively using Gitlab's latest api and proper pagination:
import requests
import subprocess, shlex
import os
print('Starting getrepos process..')
key = '12345678901234567890' # your gitlab key
base_url = 'https://your.gitlab.url/api/v4/projects?simple=true&per_page=10&private_token='
url = base_url + key
base_dir = os.getcwd()
while True:
print('\n\nRetrieving from ' + url)
response = requests.get(url, verify = False)
projects = response.json()
for project in projects:
project_name = project['name']
project_path = project['namespace']['full_path']
project_url = project['ssh_url_to_repo']
os.chdir(base_dir)
print('\nProcessing %s...' % project_name)
try:
print('Moving into directory: %s' % project_path)
os.makedirs(project_path, exist_ok = True)
os.chdir(project_path)
cmd = shlex.split('git clone --mirror %s' % project_url)
subprocess.run(cmd)
except Exception as e:
print('Error: ' + e.strerror)
if 'next' not in response.links:
break
url = response.links['next']['url'].replace('127.0.0.1:9999', 'your.gitlab.url')
print('\nDone')
Requires the requests library (for navigating to the page links).
If you are okay with some shell sorcery this will clone all the repos grouped by their group-id (you need jq and parallel)
seq 3 \
| parallel curl -s "'https://[gitlabUrl]/api/v4/projects?page={}&per_page=100&private_token=[privateToken]'
| jq '.[] | .ssh_url_to_repo, .name, .namespace.path'" \
| tr -d '"' \
| awk '{ printf "%s ", $0; if (NR % 3 == 0) print " " }' \
| parallel --colsep ' ' 'mkdir -p {2} && git clone {1} {3}/{2}'
I have written the script to pull the complete code base from gitlab for particular group.
for pag in {1..3} // number of pages projects has span {per page 20 projects so if you have 50 projects loop should be 1..3}
do
curl -s http://gitlink/api/v4/groups/{groupName}/projects?page=$pag > url.txt
grep -o '"ssh_url_to_repo": *"[^"]*"' url.txt | grep -o '"[^"]*"$' | while read -r line ; do
l1=${line%?}
l2=${l1:1}
echo "$l2"
git clone $l2
done
done
Here's a Java version that worked for me using gitlab4j with an access token and git command.
I ran this on Windows and Mac and it works. For Windows, just add 'cmd /c' before 'git clone' inside the .exec()
void doClone() throws Exception {
try (GitLabApi gitLabApi = new GitLabApi("[your-git-host].com/", "[your-access-token]");) {
List<Project> projects = gitLabApi.getGroupApi().getProjects("[your-group-name]");
projects.forEach(p -> {
try {
Runtime.getRuntime().exec("git clone " + p.getSshUrlToRepo(), null, new File("[path-to-folder-to-clone-projects-to]"));
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
You can refer to this ruby script here:
https://gist.github.com/thegauraw/da2a3429f19f603cf1c9b3b09553728b
But you need to make sure that you have the link to the organization gitlab url (which looks like: https://gitlab.example.com/api/v3/ for example organization) and private token (which looks like: QALWKQFAGZDWQYDGHADS and you can get in: https://gitlab.example.com/profile/account once you are logged in). Also do make sure that you have httparty gem installed or gem install httparty
Another way to do it with Windows "Git Bash" that has limited packages installed :
#!/bin/bash
curl -o projects.json https://<GitLabUrl>/api/v4/projects?private_token=<YourToken>
i=0
while : ; do
echo "/$i/namespace/full_path" > jsonpointer
path=$(jsonpointer -f jsonpointer projects.json 2>/dev/null | tr -d '"')
[ -z "$path" ] && break
echo $path
if [ "${path%%/*}" == "<YourProject>" ]; then
[ ! -d "${path#*/}" ] && mkdir -p "${path#*/}"
echo "/$i/ssh_url_to_repo" > jsonpointer
url=$(jsonpointer -f jsonpointer projects.json 2>/dev/null | tr -d '"')
( cd "${path#*/}" ; git clone --mirror "$url" )
fi
let i+=1
done
rm -f projects.json jsonpointer
In response to #Kosrat D. Ahmad as I had the same issue (with nested subgroups - mine actually went as much as 5 deep!)
#!/bin/bash
URL="https://mygitlaburl/api/v4"
TOKEN="mytoken"
function check_subgroup {
echo "checking $gid"
if [[ $(curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/$gid/subgroups/ | jq .[].id -r) != "" ]]; then
for gid in $(curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/$gid/subgroups/ | jq .[].id -r)
do
check_subgroup
done
else
echo $gid >> top_level
fi
}
> top_level #empty file
> repos #empty file
for gid in $(curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/ | jq .[].id -r)
do
check_subgroup
done
# This is necessary because there will be duplicates if each group has multiple nested groups. I'm sure there's a more elegant way to do this though!
for gid in $(sort top_level | uniq)
do
curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/$gid | jq .projects[].http_url_to_repo -r >> repos
done
while read repo; do
git clone $repo
done <repos
rm top_level
rm repos
Note: I use jq .projects[].http_url_to_repo this can be replaced with .ssh_url_to_repo if you'd prefer.
Alternatively strip out the rm's and look at the files individually to check the output etc.
Admittedly this will clone everything, but you can tweak it however you want.
Resources: https://docs.gitlab.com/ee/api/groups.html#list-a-groups-subgroups
This is a bit improved version of the oneliner in #ruben-lohaus post.
it will work for up to 100 repos in the group.
will clone every repository in the group including the path.
requirements:
grep
jq
curl
GITLAB_URL="https://gitlab.mydomain.local/api/v4/groups/1141/projects?include_subgroups=true&per_page=100&page=0"
GITLAB_TOKEN="ABCDEFABCDef_5n"
REPOS=$(curl --header "PRIVATE-TOKEN:${GITLAB_TOKEN}" -s "${GITLAB_URL}" | jq -r '.[].ssh_url_to_repo')
for repo in $(echo -e "$REPOS")
do git clone $repo $(echo $repo | grep -oP '(?<=:).*(?=.git$)')
done
Based on this answer, with personal access token instead of SSH to git clone.
One liner with curl, jq, tr
Without subgroups :
for repo in $(curl -s --header "PRIVATE-TOKEN: <private_token>" https://<your-host>/api/v4/groups/<group-name> | jq ".projects[]".http_url_to_repo | tr -d '"' | cut -c 9-); do git clone https://token:<private_token>#$repo; done;
Including subgroups :
for repo in $(curl -s --header "PRIVATE-TOKEN: <private_token>" "https://<your-host>/api/v4/groups/<group-name>/projects?include_subgroups=true&per_page=1000" | jq ".[]".http_url_to_repo | tr -d '"' | cut -c 9-); do git clone https://token:<private_token>#$repo; done;
Please note that the private_token for the curl must have API rights. The private_token for the git clone must have at least read_repository rights. It can be the same token (if it has API rights), but could also be 2 differents tokens
I know this question is a few years old, but I had problems with awk/sed and the scripts here (macOS).
I wanted to clone a root-group including their subgroups while keeping the tree structure.
My python script:
#!/usr/bin/env python3
import os
import re
import requests
import posixpath
import argparse
from git import Repo
parser = argparse.ArgumentParser('gitlab-clone-group.py')
parser.add_argument('group_id', help='id of group to clone (including subgroups)')
parser.add_argument('directory', help='directory to clone repos into')
parser.add_argument('--token', help='Gitlab private access token with read_api and read_repository rights')
parser.add_argument('--gitlab-domain', help='Domain of Gitlab instance to use, defaults to: gitlab.com', default='gitlab.com')
args = parser.parse_args()
api_url = 'https://' + posixpath.join(args.gitlab_domain, 'api/v4/groups/', args.group_id, 'projects') + '?per_page=9999&page=1&include_subgroups=true'
headers = {'PRIVATE-TOKEN': args.token}
res = requests.get(api_url, headers=headers)
projects = res.json()
base_ns = os.path.commonprefix([p['namespace']['full_path'] for p in projects])
print('Found %d projects in: %s' % (len(projects), base_ns))
abs_dir = os.path.abspath(args.directory)
os.makedirs(abs_dir,exist_ok=True)
def get_rel_path(path):
subpath = path[len(base_ns):]
if (subpath.startswith('/')):
subpath = subpath[1:]
return posixpath.join(args.directory, subpath)
for p in projects:
clone_dir = get_rel_path(p['namespace']['full_path'])
project_path = get_rel_path(p['path_with_namespace'])
print('Cloning project: %s' % project_path)
if os.path.exists(project_path):
print("\tProject folder already exists, skipping")
else:
print("\tGit url: %s" % p['ssh_url_to_repo'])
os.makedirs(clone_dir, exist_ok=True)
Repo.clone_from(p['ssh_url_to_repo'], project_path)
Usage
Download the gitlab-clone-group.py
Generate a private access token with read_api and read_repository rights
Get your group ID (displayed in light gray on below your group name)
Run the script
Example:
python3 gitlab-clone-group.py --token glabc-D-e-llaaabbbbcccccdd 12345678 .
Clones the group 12345678 (and subgroups) into the current working directory, keeping the tree structure.
Help:
usage: gitlab-clone-group.py [-h] [--token TOKEN] [--gitlab-domain GITLAB_DOMAIN] group_id directory
positional arguments:
group_id id of group to clone (including subgroups)
directory directory to clone repos into
options:
-h, --help show this help message and exit
--token TOKEN Gitlab private access token with read_api and read_repository rights
--gitlab-domain GITLAB_DOMAIN
Domain of Gitlab instance to use, defaults to: gitlab.com
Source: https://github.com/adroste/gitlab-clone-group
An alternative based on Dmitriy's answer -- in the case you were to clone repositories in a whole group tree recursively.
#!/usr/bin/python3
import os
import sys
import gitlab
import subprocess
glab = gitlab.Gitlab(f'https://{sys.argv[1]}', f'{sys.argv[3]}')
groups = glab.groups.list()
root = sys.argv[2]
def visit(group):
name = group.name
real_group = glab.groups.get(group.id)
os.mkdir(name)
os.chdir(name)
clone(real_group.projects.list(all=True))
for child in real_group.subgroups.list():
visit(child)
os.chdir("../")
def clone(projects):
for repo in projects:
command = f'git clone {repo.ssh_url_to_repo}'
process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
output, _ = process.communicate()
process.wait()
glab = gitlab.Gitlab(f'https://{sys.argv[1]}', f'{sys.argv[3]}')
groups = glab.groups.list()
root = sys.argv[2]
for group in groups:
if group.name == root:
visit(group)
Modified #Hot Diggity's answer.
import json
import subprocess, shlex
allProjects = urlopen("https://gitlab.com/api/v4/projects?private_token=token&membership=true&per_page=1000")
allProjectsDict = json.loads(allProjects.read().decode())
for thisProject in allProjectsDict:
try:
thisProjectURL = thisProject['ssh_url_to_repo']
path = thisProject['path_with_namespace'].replace('/', '-')
command = shlex.split('git clone %s %s' % (thisProjectURL, path))
p = subprocess.Popen(command)
p_status = p.wait()
except Exception as e:
print("Error on %s: %s" % (thisProjectURL, e.strerror))
For powershell (replace and and pass in a private token from gitlab (or hardcode it)):
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$url="https://<gitlab host>/api/v4/groups/<group>/projects?
simple=1&include_subgroups=true&private_token="+$args[0]
$req = Invoke-WebRequest $url | ConvertFrom-Json
foreach( $project in $req ) {
Start-Process git -ArgumentList "clone", $project.ssh_url_to_repo
}
One liner python3 version of Dinesh Balasubramanian response.
I only made this for lack of jq, only python3 (requests)
import requests,os; [os.system('git clone {[http_url_to_repo]}'.format(p)) for p in requests.get('https://<<REPO_URL>>/api/v4/groups/<<GROUP_ID>>',headers={'PRIVATE-TOKEN':'<<YOUR_PRIVATE_TOKEN>>'},verify=False).json()['projects']]
Replace <<REPO_URL>>, <<GROUP_ID>> and <<YOUR_PRIVATE_TOKEN>>
If you have far more then 20 projects in the group you have to deal with pagination https://docs.gitlab.com/ee/api/#pagination. That is you have to do several requests to clone all projects. The most challenging part is to obtain a full projects list in the group. This is how to do it in bash shell using curl and jq:
for ((i = 1; i <= <NUMBER_OF_ITERATIONS>; i++)); do curl -s --header "PRIVATE-TOKEN: <YOUR_TOKEN>" "https://<YOUR_URL>/api/v4/groups/<YOUR_GROUP_ID>/projects?per_page=100&page=${i}" | jq -r ".[].ssh_url_to_repo"; done | tee log
The number of iterations in a for loop can be obtained from X-Total-Pages response header in a separate request, see Pagination in Gitlab API only returns 100 per_page max.
After projects list is obtained, you can clone projects with:
for i in `cat log`; do git clone $i; done
No need to write code, just be smart
In chrome we have extension that grabs all URL's "Link Klipper"
Extract all the URL's in to an excel file just filter them in excel
create .sh file
#!/bin/bash
git clone https:(url) (command)
run this script, done all the repository's will be cloned to your local machine at once
I was a little unhappy with this pulling in archived and empty repo's, which I accept are not problems everyone has. So I made the following monstrosity from the accepted answer.
for repo in $(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.spokedev.xyz/api/v4/groups/238?include_subgroups=true" | jq '.projects[] | select(.archived == false) | select(.empty_repo == false) | .http_url_to_repo' | sed s"-https://gitlab-https://oauth2:\${GITLAB_TOKEN}#gitlab-g"); do
echo "git clone $repo"
done | bash
This is derived from the top answer to give full credit; but it just demonstrates selecting based on properties (for some reason === does not work). I also have this using HTTPS clone, because we set passwords on our SSH keys and don't want them in key-chain, or to type the password many times.
I was wrestling with issues with the scripts posted here, so I made a dumbed down hybrid version using an API call with PostMan, a JSON Query, and a dumb bash script. Here's the steps in case someone else runs into this.
Get you group id. My group id didn't match what was displayed on my group's page for some reason. Grab it by hitting the api here: https://gitlab.com/api/v4/groups
Use Postman to hit the API to list your projects. URL: https://gitlab.com/api/v4/groups/PROJECT_ID/projects?per_page=100&include_subgroups=true
Set the Auth to use API Key, where the Key is "PRIVATE-TOKEN" and the value is your private API Key
Copy the results and drop them in at: https://www.jsonquerytool.com/
Switch the Transform to JSONata. Change the query to "$.http_url_to_repo" (ssh_url_to_repo if using SSH)
You should now have a JSON array of your git urls to clone. Change the format to match Bash array notation (change [] to () and drop the commas).
Drop your Bash array into the repos variable of the script below.
repos=(
""
)
for repo in ${repos[#]}; do git clone $repo
done
Save your script in the folder where you want your repos checked out.
Run bash {yourscriptname}.sh
That should do it. You should now have a directory with all of your repos checked out for backup purposes.
It's my understanding that all the answers only allow you to clone repos, but not issues, boards, other settings, etc. Please correct me if I am wrong.
I feel if I want to back up all the data from multiple projects, the intention is to include not only repos, but also other data, which could be as important as the repos.
Self-hosted Gitlab instances can achieve this with official support, see backup and restore GitLab.

How to get Gitlab runner registration token from command line?

I'm trying to deploy a Gitlab instance and runners ready with Terraform. The script creates both Gitlab and runners without any problem, but I don't know how to register the runners automatically after the creation.
Is there any way to get the registration token from command line? If it's possible I can register just calling external data source using Terraform.
The projects API endpoint response contains the runners_token key. You can use this to automatically fetch the runner tokens for any project.
You can then use that in a few ways. One way would be to have your runner registration script fetch the runner token itself such as with this example:
curl --fail --silent --header "Private-Token: ${GITLAB_API_TOKEN}" "https://$GITLAB_URL/api/v4/projects/${PROJECT}"
Or you could use the Gitlab Terraform provider's gitlab_project data source to fetch this from whatever is running Terraform and then inject it into the thing that runs the registration script such as a templated file:
data "gitlab_project" "example" {
id = 30
}
locals {
runner_config = {
runner_token = data.gitlab_project.example.runners_token
}
}
output "example" {
value = templatefile("${path.module}/register-runners.sh.tpl", local.runner_config)
}
Yes, you can.
The command has to be run on the server hosting your Gitlab instance. The line below will output the current shared runner token.
sudo gitlab-rails runner -e production "puts Gitlab::CurrentSettings.current_application_settings.runners_registration_token"
As others have mentioned, there is not API endpoint that currently allows this (there has been discussion over this for quite some time here. However, I find this solution satisfactory for my needs.
Credits for this answer go to MxNxPx. This script used to work (for me) two days ago:
GITUSER="root"
GITURL="http://127.0.0.1"
GITROOTPWD="mysupersecretgitlabrootuserpassword"
# 1. curl for the login page to get a session cookie and the sources with the auth tokens
body_header=$(curl -k -c gitlab-cookies.txt -i "${GITURL}/users/sign_in" -sS)
# grep the auth token for the user login for
# not sure whether another token on the page will work, too - there are 3 of them
csrf_token=$(echo $body_header | perl -ne 'print "$1\n" if /new_user.*?authenticity_token"[[:blank:]]value="(.+?)"/' | sed -n 1p)
# 2. send login credentials with curl, using cookies and token from previous request
curl -sS -k -b gitlab-cookies.txt -c gitlab-cookies.txt "${GITURL}/users/sign_in" \
--data "user[login]=${GITUSER}&user[password]=${GITROOTPWD}" \
--data-urlencode "authenticity_token=${csrf_token}" -o /dev/null
# 3. send curl GET request to gitlab runners page to get registration token
body_header=$(curl -sS -k -H 'user-agent: curl' -b gitlab-cookies.txt "${GITURL}/admin/runners" -o gitlab-header.txt)
reg_token=$(cat gitlab-header.txt | perl -ne 'print "$1\n" if /code id="registration_token">(.+?)</' | sed -n 1p)
echo $reg_token
However, as of today it stopped working. I noticed the second body_header variable is empty. Upon inspecting the gitlab-header.txt file, I noticed it contained:
You are being redirected.
Whereas I would expect it to be signed in at that point, with a gitlab-header.txt file that contains the respective runner registration token. I expect I am doing something wrong, however, perhaps there has been an update to the gitlab/gitlab-ce:latest package such that a change to the script is required.
Disclaimer, I am involved in creating that code
Here is a horrible but working Python boiler plate code that gets the runner token and exports it to a parent repository: https://github.com/a-t-0/get-gitlab-runner-registration-token.
Independent usage
It requires a few manual steps to set up, and then gets the GitLab runner registration token automatically (from the CLI with:). It requires Conda and Python however, and downloads a browser controller. So it is most likely wiser to look a bit better into the curl commands instead.
Integrated in parent [bash] repository
First install the conda environment, then activate it. After that, you can execute the function below automatically from the CLI (if you put that function in a file at path parent_repo/src/get_gitlab_server_runner_token.sh, assuming you have the credentials etc as specified in the Readme), with:
cd parent_repo
source src/get_gitlab_server_runner_token.sh && get_registration_token_with_python
This bash function gets the token:
get_registration_token_with_python() {
# delete the runner registration token file if it exist
if [ -f "$RUNNER_REGISTRATION_TOKEN_FILEPATH" ] ; then
rm "$RUNNER_REGISTRATION_TOKEN_FILEPATH"
fi
git clone https://github.com/a-t-0/get-gitlab-runner-registration-token.git &&
set +e
cd get-gitlab-runner-registration-token && python -m code.project1.src
cd ..
}
And here is a BATS test that verifies the token is retrieved:
#!./test/libs/bats/bin/bats
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
load 'libs/bats-file/load'
source src/get_gitlab_server_runner_token.sh
source src/hardcoded_variables.txt
#test "Checking if the gitlab runner registration token is obtained correctly." {
get_registration_token_with_python
actual_result=$(cat $RUNNER_REGISTRATION_TOKEN_FILEPATH)
EXPECTED_OUTPUT="somecode"
assert_file_exist $RUNNER_REGISTRATION_TOKEN_FILEPATH
assert_equal ${#actual_result} 20
}

Collect the basic instace details from puppetdb like the hostname and IP based on some facts value

How can i develop a script which automatically runs and fetches the details from puppetdb ? I am a newbie to puppet .Basically I would like to collect the inventory from puppetdb based on factor values like "web server" ,"app server" etc. I use opensource puppet.
querying puppetdb is as easy as running curl.
For example, if you have a fact named $role and some nodes have the role "web server" you can get an inventory dump of all nodes with that role running:
curl -G -H "Accept: application/json" 'http://localhost:8080/pdb/query/v4/inventory' --data-urlencode 'query=["=",["fact","role"], "web server"]' |jq '.'
Now, maybe you only want to know the hostname of servers and send each inventory to another application, that would be something like this:
#!/bin/bash
# Iterate over nodes if $role 'web server'
curl -s -G -H "Accept: application/json" 'http://localhost:8080/pdb/query/v4/nodes' --data-urlencode 'query=["=",["fact","role"], "web server"]' | jq -r '.[]|[ .certname ]| #tsv' |
while IFS=$'\t' read -r host; do
echo "Do something with $host"
# Save one dump per host
curl -s -G -H "Accept: application/json" 'http://localhost:8080/pdb/query/v4/inventory' --data-urlencode 'query=["=","certname","'${host}'"]' > "node-${host}.inventory.log"
done
This are very basic examples, their api is very powerful and very simple to use, you can query anything (facts, resources, catalogs, inventories) and doing even complex queries like speaking to a MySQL server, check their tutorial here: https://puppet.com/docs/puppetdb/5.1/api/query/tutorial.html .

Setting up Cloudberry Backup for Linux for OracleCloud

I'm trying to add an account for OracleCloud, and I'm not sure I'm setting some of the required parameters correctly. My current command looks like this:
cbb addAccount -st OracleCloud -d OracleCloud -un "storage-a229571:" -kv no -c oracle-data-storagea-1 -ep https://a229571.storage.oraclecloud.com/v1/storage-a229571 -reg "US Commercial 2 us2" -ak https://us2.storage.oraclecloud.com/auth/v1.0
I get this response when I run it:
Can't validate account
Code: get openstack token v1. Message: Can't get token
Code: get openstack token v1. Message: Can't get token
Code: Can't get work url. Message: Can't get work url
Has anyone been able to use Cloudberry Backup for Linux against the OracleCloud?
This due to your -kv flag which you set to "no". You need 2 or 3, which guides Cloudberry Backup to use v2 or v3 Keystone version (consult your Oracle reps). Check this page
The below are full list of flags you may want to use:
[root#localhost]# cbb addAccount -d Display_Name -st OracleCloud -h
CloudBerry Backup Command Line Interface started
addAccount -d Display_Name -st OracleCloud <-un UserName> <-ak ApiKey> <-c BackupContainer> <-ep Endpoint> [-useInternalUrl yes/no(default)] [-reg Region] [-bp BackupPrefix] <-kv no> | <-kv 2 <-tn TenantName | -ti TenantID> > | <-kv 3 [-us < yes | no > <-pn project_name> | <-pi project_id>] <-dn DomainName | -di DomainID> >
-d Display_Name : Display name.
-un UserName : User name.
-ak ApiKey : Api key.
-reg Region : Region. Optional.
-c BackupContainer : Backup container.
-ep Endpoint : Auth endpoint.
-bp BackupPrefix : Backup prefix to differentiate between backups from different computers. Optional, by default is computer name.
-kv Keystone Version: Keystone version. Possible values 2, 3, no.
-pn project_name : Project name. Use only with keystone version 3.
-pi project_id : Project id. Use only with keystone version 3.
-tn TenantName : Tenant name. Use only with keystone version 2.
-ti TenantID : Tenant id. Use only with keystone version 2.
-us Use_scope : Use scope. Use only with keystone version 3. Possilble values yes, no.
-dn DomainName : Domain name. Use only with keystone version 3.
-dn DomainID : Domain id. Use only with keystone version 3.
-useInternalUrl : use internal url. Optional, by default is no. Possilble values yes, no.
OK, I finally had time to work on this again. This is what I figured out:
cbb addAccount -st OracleCloud \
-d <Some Name> \
-un "storage-<identity domain>:<Oracle Cloud User Name>" \
-ak "<Password for -un>" \
-c "<An existing Container>" \
-ep <Authentication Endpoint> \
-kv no
-ep is usually https://<data center>.storage.oraclecloud.com/auth/v1.0
-reg is optional, and I could not get cbb to work if I included it

Acquiring and changing basic data on the Nest thermostat

I've been having trouble acquiring and changing some of the basic data available from the Nest thermostat.
Using a command line, how can I get or change individual settings or values on my thermostat?
This is a compilation from several users explaining how to retrieve or change some basic information with some of my own experiences added in. Wherever I use <VALUE>, replace that with the applicable information in your setup. If you're using Windows, you'll need something like git-scm.
The following a part of the authentication process. You'll need to have a client already made on Nest's developer page and followed the provided authorization URL to get your auth code. Run this line to get an access token:
curl --data 'code=<AUTH CODE>&client_id=<CLIENT ID>&client_secret=<CLIENT SECRET>&grant_type=authorization_code' https://api.home.nest.com/oauth2/access_token
To fetch some information about the thermostats associated with the authorization code:
curl -v -L https://developer-api.nest.com/devices/thermostats?auth=<AUTH CODE>
To fetch some information about a specific thermostat:
curl -v -L https://developer-api.nest.com/devices/thermostats/<THERMOSTAT ID>?auth=<AUTH CODE>
To fetch the target temperature in F from the specified thermostat. You can replace target_temperature_f with any other value listed under thermostat on Nest's API reference:
curl -v -L https://developer-api.nest.com/devices/thermostats/<THERMOSTAT ID>/target_temperature_f?auth=<AUTH CODE>
To change the target_temperature_f:
curl -v -L -X PUT "https://developer-api.nest.com/devices/thermostats/<THERMOSTAT ID>/target_temperature_f?auth=<AUTH CODE>" -H "Content-Type: application/json" -d "65"
To change the specific structure to away. The value here is a string so be sure to include the single quotes:
curl -v -L -X PUT "https://developer-api.nest.com/structures/<STRUCTURE ID>/away?auth=<AUTH_TOKEN>" -H "Content-Type: application/json" -d '"away"'
Credit for this is primarily to the following users:
thesimm, mccv, Nagesh Susarla, and David W. Keith.

Resources