Skip to content

Commit ba75444

Browse files
pvdlggr2m
authored andcommitted
feat: initial release
1 parent 7378d8f commit ba75444

File tree

15 files changed

+926
-2
lines changed

15 files changed

+926
-2
lines changed

.gitignore

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
2+
# Created by https://www.gitignore.io/api/macos,windows,linux,node
3+
4+
### Linux ###
5+
*~
6+
7+
# temporary files which can be created if a process still has a handle open of a deleted file
8+
.fuse_hidden*
9+
10+
# KDE directory preferences
11+
.directory
12+
13+
# Linux trash folder which might appear on any partition or disk
14+
.Trash-*
15+
16+
# .nfs files are created when an open file is removed but is still being accessed
17+
.nfs*
18+
19+
### macOS ###
20+
*.DS_Store
21+
.AppleDouble
22+
.LSOverride
23+
24+
# Icon must end with two \r
25+
Icon
26+
27+
# Thumbnails
28+
._*
29+
30+
# Files that might appear in the root of a volume
31+
.DocumentRevisions-V100
32+
.fseventsd
33+
.Spotlight-V100
34+
.TemporaryItems
35+
.Trashes
36+
.VolumeIcon.icns
37+
.com.apple.timemachine.donotpresent
38+
39+
# Directories potentially created on remote AFP share
40+
.AppleDB
41+
.AppleDesktop
42+
Network Trash Folder
43+
Temporary Items
44+
.apdisk
45+
46+
### Node ###
47+
# Logs
48+
logs
49+
*.log
50+
npm-debug.log*
51+
yarn-debug.log*
52+
yarn-error.log*
53+
54+
# Runtime data
55+
pids
56+
*.pid
57+
*.seed
58+
*.pid.lock
59+
60+
# Directory for instrumented libs generated by jscoverage/JSCover
61+
lib-cov
62+
63+
# Coverage directory used by tools like istanbul
64+
coverage
65+
66+
# nyc test coverage
67+
.nyc_output
68+
69+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
70+
.grunt
71+
72+
# Bower dependency directory (https://bower.io/)
73+
bower_components
74+
75+
# node-waf configuration
76+
.lock-wscript
77+
78+
# Compiled binary addons (http://nodejs.org/api/addons.html)
79+
build/Release
80+
81+
# Dependency directories
82+
node_modules/
83+
jspm_packages/
84+
85+
# Typescript v1 declaration files
86+
typings/
87+
88+
# Optional npm cache directory
89+
.npm
90+
91+
# Optional eslint cache
92+
.eslintcache
93+
94+
# Optional REPL history
95+
.node_repl_history
96+
97+
# Output of 'npm pack'
98+
*.tgz
99+
100+
# Yarn Integrity file
101+
.yarn-integrity
102+
103+
# dotenv environment variables file
104+
.env
105+
106+
107+
### Windows ###
108+
# Windows thumbnail cache files
109+
Thumbs.db
110+
ehthumbs.db
111+
ehthumbs_vista.db
112+
113+
# Folder config file
114+
Desktop.ini
115+
116+
# Recycle Bin used on file shares
117+
$RECYCLE.BIN/
118+
119+
# Windows Installer files
120+
*.cab
121+
*.msi
122+
*.msm
123+
*.msp
124+
125+
# Windows shortcuts
126+
*.lnk
127+
128+
# End of https://www.gitignore.io/api/macos,windows,linux,node
129+
130+
package-lock.json
131+
yarn.lock

.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

.travis.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
language: node_js
2+
services:
3+
- docker
4+
notifications:
5+
email: false
6+
node_js:
7+
- 9
8+
- 8
9+
10+
# Trigger a push build on master and greenkeeper branches + PRs build on every branches
11+
# Avoid double build on PRs (See https://github.com/travis-ci/travis-ci/issues/1147)
12+
branches:
13+
only:
14+
- master
15+
- /^greenkeeper.*$/
16+
17+
# Retry install on fail to avoid failing a build on network/disk/external errors
18+
install:
19+
- travis_retry npm install
20+
21+
script:
22+
- npm run test
23+
24+
after_success:
25+
- npm run codecov
26+
- npm run semantic-release

.yarnrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--install.no-lockfile true

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2017 Contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,68 @@
1-
# gitlab
2-
:fox_face: Set of Semantic-release plugins for publishing a GitLab release
1+
# @semantic-release/gitlab
2+
3+
Set of [Semantic-release](https://github.com/semantic-release/semantic-release) plugins for publishing a
4+
[GitLab release](https://docs.gitlab.com/ce/workflow/releases.html).
5+
6+
[![Travis](https://img.shields.io/travis/semantic-release/gitlab.svg)](https://travis-ci.org/semantic-release/gitlab)
7+
[![Codecov](https://img.shields.io/codecov/c/github/semantic-release/gitlab.svg)](https://codecov.io/gh/semantic-release/gitlab)
8+
[![Greenkeeper badge](https://badges.greenkeeper.io/semantic-release/gitlab.svg)](https://greenkeeper.io/)
9+
10+
## verifyConditions
11+
12+
Verify the presence and the validity of the authentication (set via [environment variables](#environment-variables)).
13+
14+
## publish
15+
16+
Publish a [GitLab release](https://docs.gitlab.com/ce/workflow/releases.html).
17+
18+
## Configuration
19+
20+
### GitLab authentication
21+
22+
The GitLab authentication configuration is **required** and can be set via
23+
[environment variables](#environment-variables).
24+
25+
Only the [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html)
26+
authentication is supported.
27+
28+
### Environment variables
29+
30+
| Variable | Description |
31+
|--------------------------------|-----------------------------------------------------------|
32+
| `GL_TOKEN` or `GITLAB_TOKEN` | **Required.** The token used to authenticate with GitLab. |
33+
| `GL_URL` or `GITLAB_URL` | The GitLab endpoint. |
34+
| `GL_PREFIX` or `GITLAB_PREFIX` | The GitLab API prefix. |
35+
36+
### Options
37+
38+
| Option | Description | Default |
39+
|-----------------------|------------------------|------------------------------------------------------------------------|
40+
| `gitlabUrl` | The GitLab endpoint. | `GL_URL` or `GITLAB_URL` environment variable or `https://gitlab.com`. |
41+
| `gitlabApiPathPrefix` | The GitLab API prefix. | `GL_PREFIX` or `GITLAB_PREFIX` environment variable or `/api/v4`. |
42+
43+
### Usage
44+
45+
Options can be set within the plugin definition in the Semantic-release configuration file:
46+
47+
```json
48+
{
49+
"release": {
50+
"verifyConditions": [
51+
"@semantic-release/npm",
52+
"@semantic-release/git",
53+
{
54+
"path": "@semantic-release/gitlab",
55+
"gitlabUrl": "https://custom.gitlab.com"
56+
}
57+
],
58+
"publish": [
59+
"@semantic-release/npm",
60+
"@semantic-release/git",
61+
{
62+
"path": "@semantic-release/gitlab",
63+
"gitlabUrl": "https://custom.gitlab.com"
64+
}
65+
]
66+
}
67+
}
68+
```

index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const verifyGitLab = require('./lib/verify');
2+
const publishGitLab = require('./lib/publish');
3+
4+
let verified;
5+
6+
async function verifyConditions(pluginConfig, {options, logger}) {
7+
await verifyGitLab(pluginConfig, options, logger);
8+
verified = true;
9+
}
10+
11+
async function publish(pluginConfig, {nextRelease, options, logger}) {
12+
if (!verified) {
13+
await verifyGitLab(pluginConfig, options, logger);
14+
verified = true;
15+
}
16+
await publishGitLab(pluginConfig, options, nextRelease, logger);
17+
}
18+
19+
module.exports = {verifyConditions, publish};

lib/publish.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const parseGithubUrl = require('parse-github-url');
2+
const urlJoin = require('url-join');
3+
const got = require('got');
4+
const debug = require('debug')('semantic-release:github');
5+
const resolveConfig = require('./resolve-config');
6+
7+
module.exports = async (pluginConfig, {repositoryUrl}, {gitHead, gitTag, notes}, logger) => {
8+
const {gitlabToken, gitlabUrl, gitlabApiPathPrefix} = resolveConfig(pluginConfig);
9+
const {name: repo, owner} = parseGithubUrl(repositoryUrl);
10+
11+
debug('release name: %o', gitTag);
12+
debug('release ref: %o', gitHead);
13+
14+
try {
15+
// Test if the tag already exists
16+
await got.get(urlJoin(gitlabUrl, gitlabApiPathPrefix, `/projects/${owner}%2F${repo}/repository/tags/${gitTag}`), {
17+
json: true,
18+
headers: {'Private-Token': gitlabToken},
19+
});
20+
debug('The git tag %o already exists, update the release description', gitTag);
21+
// Update the release notes
22+
await got.post(
23+
urlJoin(gitlabUrl, gitlabApiPathPrefix, `/projects/${owner}%2F${repo}/repository/tags/${gitTag}/release`),
24+
{json: true, headers: {'Private-Token': gitlabToken}, body: {tag_name: gitTag, description: notes}} // eslint-disable-line camelcase
25+
);
26+
} catch (err) {
27+
// If the error is 404, the tag doesn't exist, otherwise it's an error
28+
if (err.statusCode !== 404) {
29+
throw err;
30+
}
31+
debug('Create git tag %o with commit %o and release description', gitTag, gitHead);
32+
await got.post(
33+
urlJoin(gitlabUrl, gitlabApiPathPrefix, `/projects/${owner}%2F${repo}/repository/tags/${gitTag}/release`),
34+
{
35+
json: true,
36+
headers: {'PRIVATE-TOKEN': gitlabToken},
37+
body: {tag_name: gitTag, ref: gitHead, release_description: notes}, // eslint-disable-line camelcase
38+
}
39+
);
40+
}
41+
42+
logger.log('Published GitLab release: %s', gitTag);
43+
};

lib/resolve-config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = ({gitlabUrl, gitlabApiPathPrefix}) => ({
2+
gitlabToken: process.env.GL_TOKEN || process.env.GITLAB_TOKEN,
3+
gitlabUrl: gitlabUrl || process.env.GL_URL || process.env.GITLAB_URL || 'https://gitlab.com',
4+
gitlabApiPathPrefix:
5+
typeof gitlabApiPathPrefix === 'string'
6+
? gitlabApiPathPrefix
7+
: null || typeof process.env.GL_PREFIX === 'string'
8+
? process.env.GL_PREFIX
9+
: null || typeof process.env.GITLAB_PREFIX === 'string' ? process.env.GITLAB_PREFIX : null || '/api/v4',
10+
});

lib/verify.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const parseGithubUrl = require('parse-github-url');
2+
const urlJoin = require('url-join');
3+
const got = require('got');
4+
const SemanticReleaseError = require('@semantic-release/error');
5+
const resolveConfig = require('./resolve-config');
6+
7+
module.exports = async (pluginConfig, {repositoryUrl}, logger) => {
8+
const {gitlabToken, gitlabUrl, gitlabApiPathPrefix} = resolveConfig(pluginConfig);
9+
10+
if (!gitlabToken) {
11+
throw new SemanticReleaseError('No GitLab token specified.', 'ENOGLTOKEN');
12+
}
13+
14+
const {name: repo, owner} = parseGithubUrl(repositoryUrl);
15+
if (!owner || !repo) {
16+
throw new SemanticReleaseError(
17+
`The git repository URL ${repositoryUrl} is not a valid GitLab URL.`,
18+
'EINVALIDGITURL'
19+
);
20+
}
21+
22+
logger.log('Verify GitLab authentication (%s)', urlJoin(gitlabUrl, gitlabApiPathPrefix));
23+
24+
let projectAccess;
25+
let groupAccess;
26+
27+
try {
28+
({body: {permissions: {project_access: projectAccess, group_access: groupAccess}}} = await got.get(
29+
urlJoin(gitlabUrl, gitlabApiPathPrefix, `/projects/${owner}%2F${repo}`),
30+
{json: true, headers: {'Private-Token': gitlabToken}}
31+
));
32+
} catch (err) {
33+
if (err.statusCode === 401) {
34+
throw new SemanticReleaseError('Invalid GitLab token.', 'EINVALIDGLTOKEN');
35+
} else if (err.statusCode === 404) {
36+
throw new SemanticReleaseError(`The repository ${owner}/${repo} doesn't exist.`, 'EMISSINGREPO');
37+
}
38+
throw err;
39+
}
40+
41+
if (!((projectAccess && projectAccess.access_level >= 30) || (groupAccess && groupAccess.access_level >= 30))) {
42+
throw new SemanticReleaseError(
43+
`The GitLab token doesn't allow to push on the repository ${owner}/${repo}.`,
44+
'EGHNOPERMISSION'
45+
);
46+
}
47+
};

0 commit comments

Comments
 (0)