# GitLab CI template for Angular

This project implements a generic GitLab CI template [Angular](https://angular.io/) based projects.

It provides several features, usable in different modes (by configuration).

## Usage

In order to include this template in your project, add the following to your `gitlab-ci.yml`:

```yaml
include:
  - project: 'Orange-OpenSource/tbc/angular'
    ref: '1.0.1'
    file: '/templates/gitlab-ci-angular.yml'
```

## Global configuration

The Angular template uses some global configuration used throughout all jobs.

| Name           | description                                   | default value                                                             |
|----------------|-----------------------------------------------|:--------------------------------------------------------------------------|
| `NG_CLI_IMAGE`        | The Docker image used to run Angular-CLI (ng). **It is highly recommended to set the specific version your project needs** | `trion/ng-cli-karma:latest` |
| `NPM_CONFIG_REGISTRY` | NPM [registry](https://docs.npmjs.com/configuring-your-registry-settings-as-an-npm-enterprise-user)                | _none_ (defaults to `https://registry.npmjs.org`) |
| `NG_WORKSPACE_DIR`    | Angular workspace directory       | `.` |

## Jobs

### `ng-lint` job

The Angular template features a job `ng-lint` that performs Angular source code **lint**.

It is bound to the `check` stage, and uses the following variable:

| Name           | description                                              | default value |
|----------------|----------------------------------------------------------|---------------|
| `NG_LINT_ARGS` | Angular [ng lint](https://angular.io/cli/lint) arguments | `lint`        |

### `ng-build` job

The Angular template features a job `ng-build` that performs **build and tests** all at once.

Those stages are performed in a single job for **optimization** purpose (it saves time) and also
for jobs dependency reasons (some jobs such as SONAR analysis have a dependency on test results).

Those stage are bound to the `build` stage, and uses the following variable:

| Name            | description                                                | default value                            |
|-----------------|------------------------------------------------------------|------------------------------------------|
| `NG_TEST_ARGS`  | Angular [ng test](https://angular.io/cli/test) arguments   | `test --code-coverage --reporters progress,junit` |
| `NG_BUILD_ARGS` | Angular [ng build](https://angular.io/cli/build) arguments | `build --prod`                           |
| `NG_JUNIT_TEST_REPORT_PATH` | Path to JUnit report                           | `reports/junit_test_report.xml`          |

The next chapters presents some requirements related to your unit tests (using Karma).

#### Use a headless browser

To be able to launch unit tests with Angular CLI, the Angular template requires a headless browser within the Docker
image `NG_CLI_IMAGE` (it is the case with the default image, [docker-ng-cli-karma](https://github.com/trion-development/docker-ng-cli-karma)).

#### Code Coverage

In order to be able to compute and enable [GitLab code coverage integration](https://docs.gitlab.com/ee/user/project/merge_requests/test_coverage_visualization.html),
the Angular template expects the following in your `karma.conf.js` (this is done by default if your project was generated with [`ng new`](https://angular.io/cli/new) command).

Add the [karma-coverage](https://www.npmjs.com/package/karma-coverage) package:

```js
  require('karma-coverage'),
```

Add the config section:

```js
  // [to be continuous]: karma-coverage configuration (needs 'text-summary' to let GitLab grab coverage from stdout)
  coverageReporter: {
    dir: require("path").resolve("reports"),
    subdir: ".",
    reporters: [{ type: "lcovonly" }, { type: "text-summary" }],
  },
```

#### JUnit report

In order to be able to [integrate your test reports to GitLab](https://docs.gitlab.com/ee/ci/junit_test_reports.html),
the Angular template expects the following in your `karma.conf.js`.

Add the [karma-junit-reporter](https://github.com/karma-runner/karma-junit-reporter) package as dev dependency:

```shell
npm install --save-dev karma-junit-reporter
```

In your `karma.conf.js`, add the plugin:

```js
  require('karma-junit-reporter'),
```

Add the config section:

```js
  // [to be continuous]: karma-junit-reporter configuration (report needs to be in 'reports/junit_test_report.xml')
  junitReporter: {
    outputDir: require('path').resolve('reports'),
    outputFile: 'junit_test_report.xml',
    useBrowserName: false,
    ...
  }
```

#### SonarQube report

If you're using SonarQube and if you want to generate a test report [compatible with SonarQube](https://docs.sonarqube.org/latest/analysis/generic-test/),
the Angular template expects the following.

By default Angular CLI do not allow to generate test report compatible with Sonar to do so, you need to add [karma-sonarqube-execution-reporter](https://github.com/lisrec/karma-sonarqube-execution-reporter) to your project as a dev dependency:

```shell
npm install --save-dev karma-sonarqube-execution-reporter
```

In your `karma.conf.js`, add the plugin:

```js
  require('karma-sonarqube-execution-reporter')
```

Add the config section:

```js
  sonarQubeExecutionReporter: {
    outputDir: require('path').resolve('reports'),
    outputFile: 'sonar_test_report.xml',
    ...
  }
```

Finally add the `sonarqubeUnit` reporter in the reporters parameter of the `NG_TEST_ARGS` variable :

```yaml
NG_TEST_ARGS:  test --reporters junit,sonarqubeUnit`
```

### `ng-e2e` job

The Angular template features a job `ng-e2e` that performs **protractor tests**
This stage is bound to the `test` stage and uses the following variables :

| Name                 | description                                                | default value                            |
|----------------------|------------------------------------------------------------|------------------------------------------|
| `NG_E2E_ARGS`        | Angular [ng e2e](https://angular.io/cli/e2e) arguments     | `e2e`                                    |
| `NG_E2E_REPORT_PATH` | path where e2e reports are stored                          | `reports/e2e`                            |
| `NG_E2E_ENABLED`     | enable or not the e2e tests execution                      | *none (disabled by default)*             |

Implementation rely on the official [Angular CLI](https://cli.angular.io/) tool (`ng build` and `ng test` commands).

To enable JUnit reporting on this job, you'll need to add [jasmine-reporters](https://www.npmjs.com/package/jasmine-reporters) dependency to your project and add the following snippet to your protractor config file :

```js
const { JUnitXmlReporter } = require('jasmine-reporters');

exports.config = {
  ...
    onPrepare() {
    jasmine.getEnv().addReporter(new JUnitXmlReporter({
      consolidateAll: true,
      savePath: 'reports/e2e'
    }));
  }
  ...
}
```

### `ng-publish` job

The Angular template features a `ng-publish` job to publish the built project.

This job is bound to the `publish` stage, and uses the following variable:

| Name            | description                                                | default value                            |
|-----------------|------------------------------------------------------------|------------------------------------------|
| `NG_PUBLISH_ENABLED`     | Variable to enable the publish job   | none (disabled) |
| `NG_PUBLISH_PROJECTS` | Space separated list of projects to publish | If no project is specified, the value of _angular.json_ `defaultProject` property is used |
| `NG_PUBLISH_ARGS`        | NPM [publish](https://docs.npmjs.com/cli/v6/commands/npm-publish) arguments | `--verbose`          |
| `NPM_PUBLISH_REGISTRY`     | NPM registry to publish to | uses GitLab project npm packages registry  |
| :lock: `NPM_PUBLISH_TOKEN`     | NPM publication registry authentication token | none          |

:warning: When using the gitlab registry (which is the default behavior), your NPM package name must be in the format of `@scope/package-name`:

* The `@scope` is the root namespace of the GitLab project. It must match exactly, including the case.
* The `package-name` can be whatever you want.

For example, if your project is `https://gitlab.example.com/my-org/engineering-group/team-amazing/analytics`, the root namespace is `my-org`. When you publish a package, it must have `my-org` as the scope.
For more details see [Package naming convention](https://docs.gitlab.com/ee/user/packages/npm_registry/#package-naming-convention).

:warning: Don't forget to specify the publication registry in the **project(s)** to publish `package.json` file (not the workspace top-level one).

```json
{
  "name": "@my-org/hello-world",
  "version": "0.0.6",
  "peerDependencies": {
    "@angular/common": "^10.1.6",
    "@angular/core": "^10.1.6"
  },
  "dependencies": {
    "tslib": "^2.0.0"
  },
  "publishConfig": {
    "@my-org:registry": "https://<publication-registry-url>"
  }
}
```

:information_source: When using the GitLab registry, the registry publication url looks like `https://<gitlab-host>/api/v4/projects/<your_project_id>/packages/npm/`, with:

* `<gitlab-host>` is your GitLab host domain name.
* `<your_project_id>` is your project ID, **found on the project’s home page**.

## SonarQube analysis

If you're using the SonarQube template to analyse your Angular code, here is a sample `sonar-project.properties` file:

```properties
# see: https://docs.sonarqube.org/latest/analysis/languages/typescript/
# set your source directory(ies) here (relative to the sonar-project.properties file)
sonar.sources=app
# exclude unwanted directories and files from being analysed
sonar.exclusions=node_modules/**,dist/**,**/*.spec.ts

# set your tests directory(ies) here (relative to the sonar-project.properties file)
sonar.tests=app
sonar.test.inclusions=**/*.spec.ts

# tests report: generic format
# set the path configured with karma-sonarqube-execution-reporter
sonar.testExecutionReportPaths=reports/sonar_test_report.xml
# lint report: TSLint JSON
sonar.typescript.tslint.reportPaths=reports/tslint-report.json
# coverage report: LCOV format
# set the path configured with karma-coverage-istanbul-reporter
sonar.typescript.lcov.reportPaths=reports/lcov.info
```

More info:

* [TypeScript language support](https://docs.sonarqube.org/latest/analysis/languages/typescript/)
* [test coverage & execution parameters](https://docs.sonarqube.org/latest/analysis/coverage/)
* [third-party issues](https://docs.sonarqube.org/latest/analysis/external-issues/)