Compare commits

...
9 Commits
10 changed files with 72 additions and 24 deletions
+1 -1
View File
@@ -101,7 +101,7 @@ In order to use **semantic-release** you need:
- To host your code in a [Git repository](https://git-scm.com)
- Use a Continuous Integration service that allows you to [securely set up credentials](docs/usage/ci-configuration.md#authentication)
- Git CLI version [2.7.1 or higher](docs/support/FAQ.md#why-does-semantic-release-require-git-version--271) installed in your Continuous Integration environment
- [Node.js](https://nodejs.org) version [8.16.0 or higher](docs/support/FAQ.md#why-does-semantic-release-require-node-version--816) installed in your Continuous Integration environment
- [Node.js](https://nodejs.org) version [10.13 or higher](docs/support/FAQ.md#why-does-semantic-release-require-node-version--1013) installed in your Continuous Integration environment
## Documentation
+4 -4
View File
@@ -65,10 +65,10 @@
- `verifyConditions`: Verify the presence of the authentication (set via environment variables)
- `prepare`: Write the correct version to the `manifest.json` and creates a zip file of the whole dist folder
- `publish`: Uploads the generated zip file to the webstore, and publish the item
- [semantic-release-firefox](https://github.com/felixfbecker/semantic-release-firefox)
- `verifyConditions`: Verify the presence of the authentication (set via environment variables)
- `prepare`: Write the correct version to the `manifest.json`, creates a `xpi` file of the dist folder and a zip of the sources
- `publish`: Submit the generated archives to the webstore for review, and publish the item including release notes
- [semantic-release-firefox-add-on](https://github.com/tophat/semantic-release-firefox-add-on)
- `verifyConditions`: Verify that all required options are present and authentication is set via environment variables
- `prepare`: Write the correct version to the `manifest.json`
- `publish`: Creates an unsigned `.xpi` file, and submits it to the Mozilla Add On store for signing. Once the package is signed, downloads the signed `.xpi` to a local directory
- [semantic-release-gerrit](https://github.com/pascalMN/semantic-release-gerrit)
- `generateNotes`: Generate release notes with Gerrit reviews URL
- [semantic-release-expo](https://github.com/bycedric/semantic-release-expo)
+1 -1
View File
@@ -169,7 +169,7 @@ The Git history of the repository is now:
We can now start to work on a new future major release, version `4.0.0`, on the `@beta` distribution channel.
To do so we fist need to update the `beta` branch with all the changes from `master` (the commits `fix: a fix`). As `beta` and `master` branches have diverged, this merge might require to resolve conflicts.
To do so we first need to update the `beta` branch with all the changes from `master` (the commits `fix: a fix`). As `beta` and `master` branches have diverged, this merge might require to resolve conflicts.
We can now commit our new feature on `beta`. When pushing that commit, **semantic-release** will publish the pre-release version `3.1.0-beta.1` on the dist-tag `@beta`. That allow us to run integration tests by installing our module with `npm install example-module@beta`. Other users installing with `npm install example-module` will still receive the version `3.0.0`.
+2
View File
@@ -92,4 +92,6 @@ jobs:
# Use nvm to install and use the Node LTS version (nvm is installed on all Travis images)
- nvm install lts/*
- npx semantic-release
on:
all_branches: true
```
+1 -1
View File
@@ -65,8 +65,8 @@ For each [release step](../../README.md#release-steps) the plugins that implemen
With this configuration **semantic-release** will:
- execute the `verifyConditions` implementation of `@semantic-release/npm` then `@semantic-release/git`
- execute the `analyzeCommits` implementation of `@semantic-release/commit-analyzer`
- execute the `prepare` implementation of `@semantic-release/npm` then `@semantic-release/git`
- execute the `generateNotes` implementation of `@semantic-release/release-notes-generator`
- execute the `prepare` implementation of `@semantic-release/npm` then `@semantic-release/git`
- execute the `publish` implementation of `@semantic-release/npm`
## Plugin options configuration
+13 -6
View File
@@ -86,15 +86,22 @@ async function isRefExists(ref, execaOpts) {
}
/**
* Unshallow the git repository if necessary and fetch all the tags.
* Fetch all the tags from a branch. Unshallow if necessary.
* This will update the local branch from the latest on the remote if:
* - The branch is not the one that triggered the CI
* - The CI created a detached head
*
* Otherwise it just calls `git fetch` without specifying the `refspec` option to avoid overwritting the head commit set by the CI.
*
* The goal is to retrieve the informations on all the release branches without "disturbing" the CI, leaving the trigger branch or the detached head intact.
*
* @param {String} repositoryUrl The remote repository URL.
* @param {String} branch The repository branch to fetch.
* @param {Object} [execaOpts] Options to pass to `execa`.
*/
async function fetch(repositoryUrl, branch, ciBranch, execaOpts) {
const isLocalExists =
(await execa('git', ['rev-parse', '--verify', branch], {...execaOpts, reject: false})).exitCode === 0;
const isDetachedHead =
(await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {...execaOpts, reject: false})).stdout === 'HEAD';
try {
await execa(
@@ -103,7 +110,7 @@ async function fetch(repositoryUrl, branch, ciBranch, execaOpts) {
'fetch',
'--unshallow',
'--tags',
...(branch === ciBranch && isLocalExists
...(branch === ciBranch && !isDetachedHead
? [repositoryUrl]
: ['--update-head-ok', repositoryUrl, `+refs/heads/${branch}:refs/heads/${branch}`]),
],
@@ -115,7 +122,7 @@ async function fetch(repositoryUrl, branch, ciBranch, execaOpts) {
[
'fetch',
'--tags',
...(branch === ciBranch && isLocalExists
...(branch === ciBranch && !isDetachedHead
? [repositoryUrl]
: ['--update-head-ok', repositoryUrl, `+refs/heads/${branch}:refs/heads/${branch}`]),
],
@@ -197,7 +204,7 @@ async function isGitRepo(execaOpts) {
*/
async function verifyAuth(repositoryUrl, branch, execaOpts) {
try {
await execa('git', ['push', '--dry-run', repositoryUrl, `HEAD:${branch}`], execaOpts);
await execa('git', ['push', '--dry-run', '--no-verify', repositoryUrl, `HEAD:${branch}`], execaOpts);
} catch (error) {
debug(error);
throw error;
+7 -7
View File
@@ -30,8 +30,8 @@
"aggregate-error": "^3.0.0",
"cosmiconfig": "^6.0.0",
"debug": "^4.0.0",
"env-ci": "^4.0.0",
"execa": "^3.2.0",
"env-ci": "^5.0.0",
"execa": "^4.0.0",
"figures": "^3.0.0",
"find-versions": "^3.0.0",
"get-stream": "^5.0.0",
@@ -39,14 +39,14 @@
"hook-std": "^2.0.0",
"hosted-git-info": "^3.0.0",
"lodash": "^4.17.15",
"marked": "^0.7.0",
"marked": "^0.8.0",
"marked-terminal": "^3.2.0",
"micromatch": "^4.0.2",
"p-each-series": "^2.1.0",
"p-reduce": "^2.0.0",
"read-pkg-up": "^7.0.0",
"resolve-from": "^5.0.0",
"semver": "^6.0.0",
"semver": "^7.1.1",
"semver-diff": "^3.1.1",
"signale": "^1.2.1",
"yargs": "^15.0.1"
@@ -59,14 +59,14 @@
"dockerode": "^3.0.0",
"file-url": "^3.0.0",
"fs-extra": "^8.0.0",
"got": "^9.0.0",
"got": "^10.2.1",
"js-yaml": "^3.10.0",
"mockserver-client": "^5.1.1",
"nock": "^11.1.0",
"nyc": "^14.0.0",
"nyc": "^15.0.0",
"p-retry": "^4.0.0",
"proxyquire": "^2.0.0",
"sinon": "^7.2.7",
"sinon": "^8.0.4",
"stream-buffers": "^3.0.2",
"tempy": "^0.3.0",
"xo": "^0.25.0"
+30 -1
View File
@@ -32,6 +32,7 @@ import {
gitDetachedHeadFromBranch,
gitAddNote,
gitGetNote,
gitFetch,
} from './helpers/git-utils';
test('Get the last commit sha', async t => {
@@ -99,7 +100,7 @@ test('Fetch all tags on a detached head repository', async t => {
t.deepEqual((await getTags('master', {cwd})).sort(), ['v1.0.0', 'v1.0.1', 'v1.1.0'].sort());
});
test('Fetch all tags on a repository with a detached head from branch', async t => {
test('Fetch all tags on a repository with a detached head from branch (CircleCI)', async t => {
let {cwd, repositoryUrl} = await gitRepo();
await gitCommits(['First'], {cwd});
@@ -124,6 +125,34 @@ test('Fetch all tags on a repository with a detached head from branch', async t
t.deepEqual((await getTags('master', {cwd})).sort(), ['v1.0.0', 'v1.0.1', 'v1.1.0', 'v2.0.0'].sort());
});
test('Fetch all tags on a detached head repository with outdated cached repo (GitLab CI)', async t => {
const {cwd, repositoryUrl} = await gitRepo();
await gitCommits(['First'], {cwd});
await gitTagVersion('v1.0.0', undefined, {cwd});
await gitCommits(['Second'], {cwd});
await gitTagVersion('v1.0.1', undefined, {cwd});
let [commit] = await gitCommits(['Third'], {cwd});
await gitTagVersion('v1.1.0', undefined, {cwd});
await gitPush(repositoryUrl, 'master', {cwd});
// Create a clone (as first CI run would)
const cloneCwd = await gitShallowClone(repositoryUrl);
await gitFetch(repositoryUrl, {cwd: cloneCwd});
await gitCheckout(commit.hash, false, {cwd: cloneCwd});
// Push tag to remote
[commit] = await gitCommits(['Fourth'], {cwd});
await gitTagVersion('v1.2.0', undefined, {cwd});
await gitPush(repositoryUrl, 'master', {cwd});
// Fetch on the cached repo and make detached head, leaving master outdated
await fetch(repositoryUrl, 'master', 'master', {cwd: cloneCwd});
await gitCheckout(commit.hash, false, {cwd: cloneCwd});
t.deepEqual((await getTags('master', {cwd: cloneCwd})).sort(), ['v1.0.0', 'v1.0.1', 'v1.1.0', 'v1.2.0'].sort());
});
test('Verify if a branch exists', async t => {
// Create a git repository, set the current working directory at the root of the repo
const {cwd} = await gitRepo();
+10
View File
@@ -109,6 +109,16 @@ export async function gitCheckout(branch, create, execaOpts) {
await execa('git', create ? ['checkout', '-b', branch] : ['checkout', branch], execaOpts);
}
/**
* Fetch current git repository.
*
* @param {String} repositoryUrl The repository remote URL.
* @param {Object} [execaOpts] Options to pass to `execa`.
*/
export async function gitFetch(repositoryUrl, execaOpts) {
await execa('git', ['fetch', repositoryUrl], execaOpts);
}
/**
* Get the HEAD sha.
*
+3 -3
View File
@@ -45,10 +45,10 @@ async function start() {
// Create user
await got(`http://${SERVER_HOST}:${SERVER_PORT}/_users/org.couchdb.user:${NPM_USERNAME}`, {
json: true,
auth: `${COUCHDB_USER}:${COUCHDB_PASSWORD}`,
username: COUCHDB_USER,
password: COUCHDB_PASSWORD,
method: 'PUT',
body: {
json: {
_id: `org.couchdb.user:${NPM_USERNAME}`,
name: NPM_USERNAME,
roles: [],