Node.js package for extracting branch name from git ref - node.js

I am running my CI on GitHub Actions, and I am using the GITHUB_REF default environment variable as a part of a download URL.
GitHub sets the GITHUB_REF to:
refs/heads/staging
I understand from git: difference between "branchname" and "refs/heads/branchname" that the refs/heads/ prefix is needed so that git has the "full path" to the branch.
Now, I am wondering if anyone knows of an off-the-shelf node.js package deployed to a registry like npmjs that I could use to extract the branch name from the long ref string? It seems like there could be many different prefixes: refs/tags/, refs/remotes, etc., and I would prefer not to write my custom script if there is another solution available.

Thanks to Lawrence Cherone's comment, I found this GitHub gist:
const { execSync } = require('child_process');
function executeGitCommand(command) {
return execSync(command)
.toString('utf8')
.replace(/[\n\r\s]+$/, '');
}
const BRANCH = executeGitCommand('git rev-parse --abbrev-ref HEAD');
const COMMIT_SHA = executeGitCommand('git rev-parse HEAD');
It's not an npm package but it is good enough for now.

Related

How to get the latest commit hash on remote using gitpython?

Is there a way that I can get the most recent commit on a remote repository using gitpython?
I do not want to perform operations like a pull or merge on my local branch. I also do not want to depend on the master branch on my local to get this information. All I have is a valid repo out there, and I am using repo.remotes.origin.url to get the information.
With just the repo URL, can I get the most recent commit on that repository?
Using gitpython, you can't do this without a local clone. Git is a distributed system, so it's designed for users to operate on their local repos. These answer gives some decent explanations and alternatives:
https://stackoverflow.com/a/28524371/5752730
https://stackoverflow.com/a/19391097/5752730
https://stackoverflow.com/a/16579859/5752730
Using gitpython - requires local repo
You can do a shallow clone (for speed), get latest commit SHA using git rev-parse or git ls-remote, then delete the local repo.
import git
from pathlib import Path
repo_url = 'https://github.com/path/to/your/repo.git'
local_repo_dir = Path('/path/to/your/repo')
# delete the repo if it exists, perform shallow clone, get SHA, delete repo
local_repo_dir.unlink(missing_ok=True)
repo = git.Repo.clone_from(repo_url, local_repo_dir, depth=1)
sha = repo.rev_parse('origin/master')
local_repo_dir.unlink()
print(sha)
Using python subprocess - does not require local repo
This simpler solution uses git ls-remote, which does not require a local clone. The following uses subprocess to get the SHA-1 of the given branch from the remote repo without a local clone. Note that the SHA needs to be extracted from the output response by splitting at the first tab.
import subprocess
import re
repo_url = 'https://github.com/path/to/your/repo.git'
process = subprocess.Popen(["git", "ls-remote", repo_url], stdout=subprocess.PIPE)
stdout, stderr = process.communicate()
sha = re.split(r'\t+', stdout.decode('ascii'))[0]
print(sha)
You can do it with gitpython without creating a local repository first:
remote_heads = git.cmd.Git().ls_remote(repo_url, heads=True)

How to delete a remote branch using Node.js?

I'm currently using nodegit to run my git commands and it has worked for everything so far except for deleting a remote branch. I don't mind using another npm package to do this if needed but I would prefer to use nodegit.
Basically, I want a function which can do the same as this command in the terminal
$ git push -d <branch_name>
I want to be able to write something like the following:
function delete_remote_branch(repo, branch_name, callback) {
repo.getRemote('origin').then(function(remote) {
repo.getBranch(branch_name).then(function(reference) {
// delete the branch
repo.push("-d :"+reference, branch_name).then(function(error_code) {
if(error_code) {
return callback(error_code)
}
return callback(null)
})
})
})
}
The documentation for remote.push is here: http://www.nodegit.org/api/remote/#push
Any help would be appreciated. Thanks!
Push an empty src reference to the origin branch.
remote.push(':refs/heads/my-branch');

GitLab CI test differences between master and branch with Node

Currently I am trying to test the differences between master and a branch on GitLab CI.
var branch = require('git-branch'),
gitDiffTree = require('git-diff-tree'),
path = require('path');
var branch = process.env.CI_BUILD_REF_NAME || branch.sync();
var repoPath = path.resolve(process.env.REPO || (__dirname + '/../.git'));
{
repoPath: repoPath,
gitDiffTreeOptions: {
rev: 'master..' + branch
}
}
Here is the important bits of code that I'm using. This works great locally, but when ran on GitLab CI it says fatal: bad revision 'master.. branch' both times the branch variable was populated with the same value. Any advice how to get this to work? It previously used to do rev: HEAD which didn't work great because it only tested the most recent commit in the branch not all of them together.
I had a similar issue (bad revision 'master' when running git diff master -- . and similar commands), and got it working as follows:
run git fetch origin master (from the pipeline)
when referring to the master branch, use origin/master rather than master
I suppose the way gitlab fetches the repository contents does not cause master to be a valid branch name locally. I'm not familiar enough with the guts of git to pinpoint exactly why.

Get git remote info using NodeJS

I have to get remote git information using NodeJS. I have managed to get info from a cloned repo using simple-git. The code I have test is the following:
require('simple-git')('/my/local/git/repo/path')
.pull()
.tags(function(err, tags) {
console.log("These are my tags: %s", tags.all);
});
However, it requires the repo to be locally cloned. Is there any way (using this or another module) to connect the remote git to get this info?
You need to specify the path to any valid repo or leave it empty considered git repo is under current directory. That's just required to make commands worked.
After that you can use listRemote method in the following way:
require('simple-git')([optional path])
// .init() - in case it's totally empty folder
.addRemote('remote_repo_alias', 'path/to/remote/repo')
.listRemote(['--tags', 'remote_repo_alias'], function(err, tags) {
// ...
});

How to create a GitLab merge request via command line

We are working on integrating GitLab (enterprise edition) in our tooling, but one thing that is still on our wishlist is to create a merge request in GitLab via a command line (or batchfile or similar, for that matter). We would like to integrate this in our tooling. Searching here and on the web lead me to believe that this is not possible with native GitLab, but that we need additional tooling for that.
Am I correct? And what kind of tooling would I want to use for this?
As of GitLab 11.10, if you're using git 2.10 or newer, you can automatically create a merge request from the command line like this:
git push -o merge_request.create
More information can be found in the docs.
It's not natively supported, but it's not hard to throw together. The gitlab API has support for opening MR: https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/merge_requests.md#create-mr
You can use following utility.
Disclosure : I developed it.
https://github.com/vishwanatharondekar/gitlab-cli
You can create merge request using this.
Some of the features it has are.
Base branch is optional. If base branch is not provided. Current branch is used as base branch.
target branch is optional. If target branch is not provided, default branch of the repo in gitlab will be used.
Created pull request page will be opened automatically after successful creation.
If title is not supported with -m option value. It will be taken from in place editor opened. First line is taken as title.
In the editor opened third line onwards takes as description.
Comma separated list of labels can be provided with its option.
Supports CI.
Repository specific configs can be given.
squash option is available.
remove source branch option is available.
If you push your branch before this command (git push -o merge_request.create) it will not work. Git will response with Everything up-to-date and merge request will not be created (gitlab 12.3).
When I tried to remove my branch from a server (do not remove your local branch!!!) then it worked for me in this form.
git push --set-upstream origin your-branch-name -o merge_request.create
In addition to answering of #AhmadSherif, You can use merge_request.target=<branch_name> for declaring the target branch.
sample usage:
git push -o merge_request.create -o merge_request.target=develop origin feature
Simple This:
According to the Gitlab documents, you can define an alias for this command to simpler usage.
git config --global alias.mwps "push -o merge_request.create -o
merge_request.target=master -o merge_request.merge_when_pipeline_succeeds"
I made a shell function which opens up the GitLab MR web page with desired parameters.
Based on the directory with the git repo you are currently in, it:
Finds the correct URL to your repo.
Sets the source branch to the branch you're currently on.
As a optional first argument you can provide the target branch. Otherwise, GitLab defaults to your default branch, which is typically master.
gmr() {
# A quick way to open a GitLab merge request URL for the current git branch
# you're on. The optional first argument is the target branch.
repo_path=$(git remote get-url origin --push | sed 's/^.*://g' | sed 's/.git$//g')
current_branch=$(git rev-parse --abbrev-ref HEAD)
if [[ -n $1 ]]; then
target_branch="&merge_request[target_branch]=$1"
else
target_branch=""
fi
xdg-open "https://gitlab.com/$repo_path/merge_requests/new?merge_request[source_branch]=$current_branch$target_branch"
}
You can set more default values in the URL, like removing the source branch after merge:
&merge_request[force_remove_source_branch]=true
Or assignee to someone:
&merge_request[assignee_ids][]=12345
Or add a reviewer:
&merge_request[reviewer_ids][]=54321
You can easily find the possible query string parameters by searching the source of the GitLab MR webpage for merge_request[.
As of now, GitLab sadly does not support this, however I recently saw it on their issue tracker. It appears one can expect a 'native tool' in the upcoming months.
GitLab tweeted out about numa08/git-gitlab some time ago, so I guess this would be worth a try.
In our build script we just pop up the browser with the correct URL and let the developer write his comments in the form hit save to create the merge request. You get this url with the correct parameters by creating a merge request manually and copying the url of the form.
#!/bin/bash
set -e
set -o pipefail
BRANCH=${2}
....
git push -f origin-gitlab $BRANCH
open "https://gitlab.com/**username**/**project-name**/merge_requests/new?merge_request%5Bsource_branch%5D=$BRANCH&merge_request%5Bsource_project_id%5D=99999&merge_request%5Btarget_branch%5D=master&merge_request%5Btarget_project_id%5D=99999"
You can write a local git alias to open a Gitlab Merge Request creation page in the default browser for the currently checked-out branch.
[alias]
lab = "!start https://gitlab.com/path/to/repo/-/merge_requests/new?merge_request%5Bsource_branch%5D=\"$(git rev-parse --abbrev-ref HEAD)\""
(this is a very simple alias for windows; I guess there are equivalent replacements for "start" on linux and fancier aliases that work with github and bitbucket too)
As well as being able to immediately see&modify the details of the MR, the advantage of this over using the merge_request.create push option is that you don't need your local branch to be behind the remote for it to work.
You might additionally want to store the alias in the repo itself.
I use https://github.com/mdsb100/cli-gitlab
I am creating the MR from inside of a gitlab CI docker container based on alpine linux, so I include the install command in before-script (that could also be included in your image). All commands in the following .gitlab-ci.yml file, are also relevant for normal command line usage (as long as you have the cli-gitlab npm installed).
variables:
TARGET_BRANCH: 'live'
GITLAB_URL: 'https://your.gitlab.net'
GITLAB_TOKEN: $PRIVATE_TOKEN #created in user profile & added in project settings
before-script:
-apk update && apk add nodejs && npm install cli-gitlab -g
script:
- gitlab url $GITLAB_URL && gitlab token $GITLAB_TOKEN
- 'echo "gitlab addMergeRequest $CI_PROJECT_ID $CI_COMMIT_REF_NAME \"$TARGET_BRANCH\" 13 `date +%Y%m%d%H%M%S`"'
- 'gitlab addMergeRequest $CI_PROJECT_ID $CI_COMMIT_REF_NAME "$TARGET_BRANCH" 13 `date +%Y%m%d%H%M%S` 2> ./mr.json'
- cat ./mr.json
This will echo true if the merge request already exists, and echo the json result of the new MR if it succeeds to create one (also saving to a mr.json file).
Since GitLab 15.7 (Dec. 2022), the GitLab CLI glab is officially integrated to GitLab.
Introducing the GitLab CLI
The command line is one of the most important tools in a software engineer’s toolkit and the majority of their process and work revolve around tools available there. They customize their CLI with styles and extend it through applications to ensure maximum efficiency while performing tasks. The CLI is the backbone of scripts and workflows developers depend on to complete their work.
To support more developers where they’re already working, we’ve adopted the open source project glab, which will form the foundation of GitLab’s native CLI experience.
The GitLab CLI brings GitLab together with Git and your code, with no application or tab switching required.
You can read about our adoption of glab, our partnership with 1Password, and how to contribute to the project in our blog post.
A special thank you to Clement Sam for creating glab and trusting us with its future.
That means you can create a MR with glab mr create:
glab mr create -a username -t "fix annoying bug"

Resources