Skip to content

Commit

Permalink
chore(core): add unit tests for not connected to nx cloud (nrwl#26885)
Browse files Browse the repository at this point in the history
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
xiongemi authored Jul 12, 2024
1 parent adacd98 commit aa7c5dc
Showing 12 changed files with 1,597 additions and 338 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ci-workflow generator circleci pipeline should match snapshot 1`] = `
exports[`ci-workflow generator connected to nxCloud circleci pipeline should match snapshot 1`] = `
"version: 2.1
orbs:
@@ -25,6 +25,7 @@ jobs:
- nx/set-shas:
main-branch-name: 'main'
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- run: ./nx affected --base=$NX_BASE --head=$NX_HEAD -t test build
workflows:
@@ -36,7 +37,7 @@ workflows:
"
`;

exports[`ci-workflow generator github pipeline should match snapshot 1`] = `
exports[`ci-workflow generator connected to nxCloud github pipeline should match snapshot 1`] = `
"name: CI
on:
@@ -74,6 +75,89 @@ jobs:
- uses: nrwl/nx-set-shas@v4
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- run: ./nx affected -t test build
"
`;

exports[`ci-workflow generator not connected to nxCloud circleci pipeline should match snapshot 1`] = `
"version: 2.1
orbs:
nx: nrwl/[email protected]
jobs:
main:
environment:
# Configure the JVM and Gradle to avoid OOM errors
_JAVA_OPTIONS: '-Xmx3g'
GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2'
docker:
- image: cimg/openjdk:17.0-node
steps:
- checkout
# This enables task distribution via Nx Cloud
# Run this command as early as possible, before dependencies are installed
# Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
# Connect your workspace by running "nx connect" and uncomment this
# - run: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-jvm" --stop-agents-after="build"
- nx/set-shas:
main-branch-name: 'main'
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- run: ./nx affected --base=$NX_BASE --head=$NX_HEAD -t test build
workflows:
version: 2
ci:
jobs:
- main
"
`;

exports[`ci-workflow generator not connected to nxCloud github pipeline should match snapshot 1`] = `
"name: CI
on:
push:
branches:
- main
pull_request:
permissions:
actions: read
contents: read
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# This enables task distribution via Nx Cloud
# Run this command as early as possible, before dependencies are installed
# Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
# Connect your workspace by running "nx connect" and uncomment this
# - run: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-jvm" --stop-agents-after="build"
- name: Set up JDK 17 for x64
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
architecture: x64
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- uses: nrwl/nx-set-shas@v4
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- run: ./nx affected -t test build
"
`;
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ jobs:
main-branch-name: '<%= mainBranch %>'

<% for (const command of commands) { %>
- run: <%= command %><% } %>
<% if (command.command) { %>- run: <%= command.command %><% } else if (command.comment) { %><%= command.comment %><% } else {%>- run: <%= command %><% } %><% } %>

workflows:
version: 2
Original file line number Diff line number Diff line change
@@ -39,4 +39,4 @@ jobs:
- uses: nrwl/nx-set-shas@v4

<% for (const command of commands) { %>
- run: <%= command %><% } %>
<% if (command.command) { %>- run: <%= command.command %><% } else if (command.comment) { %><%= command.comment %><% } else {%>- run: <%= command %><% } %><% } %>
46 changes: 35 additions & 11 deletions packages/gradle/src/generators/ci-workflow/generator.spec.ts
Original file line number Diff line number Diff line change
@@ -8,21 +8,45 @@ describe('ci-workflow generator', () => {

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
const nxJson = readNxJson(tree);
nxJson.nxCloudAccessToken = 'test';
updateNxJson(tree, nxJson);
});

describe.each([
['github', '.github/workflows/ci.yml'],
['circleci', '.circleci/config.yml'],
] as const)(`%s pipeline`, (ciProvider, output) => {
it('should match snapshot', async () => {
await ciWorkflowGenerator(tree, {
name: 'CI',
ci: ciProvider,
['connected to nxCloud', true],
['not connected to nxCloud', false],
] as const)(`%s`, (_, connectedToCloud) => {
let nxCloudAccessToken: string;

beforeEach(() => {
if (connectedToCloud) {
const nxJson = readNxJson(tree);
nxJson.nxCloudAccessToken = 'test';
updateNxJson(tree, nxJson);
} else {
nxCloudAccessToken = process.env.NX_CLOUD_ACCESS_TOKEN;
delete process.env.NX_CLOUD_ACCESS_TOKEN;
}
});

afterEach(() => {
if (connectedToCloud) {
const nxJson = readNxJson(tree);
delete nxJson.nxCloudAccessToken;
updateNxJson(tree, nxJson);
} else {
process.env.NX_CLOUD_ACCESS_TOKEN = nxCloudAccessToken;
}
});
describe.each([
['github', '.github/workflows/ci.yml'],
['circleci', '.circleci/config.yml'],
] as const)(`%s pipeline`, (ciProvider, output) => {
it('should match snapshot', async () => {
await ciWorkflowGenerator(tree, {
name: 'CI',
ci: ciProvider,
});
expect(tree.read(output, 'utf-8')).toMatchSnapshot();
});
expect(tree.read(output, 'utf-8')).toMatchSnapshot();
});
});
});
26 changes: 20 additions & 6 deletions packages/gradle/src/generators/ci-workflow/generator.ts
Original file line number Diff line number Diff line change
@@ -11,22 +11,36 @@ import { join } from 'path';
import { getNxCloudUrl, isNxCloudUsed } from 'nx/src/utils/nx-cloud-utils';
import { deduceDefaultBase } from 'nx/src/utils/default-base';

function getCiCommands(ci: Schema['ci'], mainBranch: string): string[] {
function getCiCommands(ci: Schema['ci']): Command[] {
switch (ci) {
case 'circleci': {
return [`./nx affected --base=$NX_BASE --head=$NX_HEAD -t test build`];
return [
{
comment: `# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected`,
},
{
command: `./nx affected --base=$NX_BASE --head=$NX_HEAD -t test build`,
},
];
}
default: {
return [`./nx affected -t test build`];
return [
{
comment: `# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected`,
},
{ command: `./nx affected -t test build` },
];
}
}
}

export type Command = { command: string } | { comment: string } | string;

export interface Schema {
name: string;
ci: 'github' | 'circleci';
packageManager?: null;
commands?: string[];
commands?: Command[];
}

export async function ciWorkflowGenerator(tree: Tree, schema: Schema) {
@@ -43,7 +57,7 @@ interface Substitutes {
workflowFileName: string;
packageManager: string;
packageManagerPrefix: string;
commands: string[];
commands: Command[];
nxCloudHost: string;
connectedToCloud: boolean;
}
@@ -64,7 +78,7 @@ function getTemplateData(tree: Tree, options: Schema): Substitutes {

const mainBranch = deduceDefaultBase();

const commands = options.commands ?? getCiCommands(options.ci, mainBranch);
const commands = options.commands ?? getCiCommands(options.ci);

const connectedToCloud = isNxCloudUsed(readNxJson(tree));

Large diffs are not rendered by default.

165 changes: 96 additions & 69 deletions packages/workspace/src/generators/ci-workflow/ci-workflow.spec.ts
Original file line number Diff line number Diff line change
@@ -35,103 +35,130 @@ describe('CI Workflow generator', () => {

beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
const nxJson = readNxJson(tree);
nxJson.nxCloudAccessToken = 'test';
updateNxJson(tree, nxJson);
});

afterEach(() => {
vol.reset();
});

['npm', 'yarn', 'pnpm', 'bun'].forEach((packageManager: PackageManager) => {
describe(`with ${packageManager}`, () => {
beforeEach(() => {
let fileSys;
if (packageManager === 'bun') {
fileSys = { 'bun.lockb': '' };
} else if (packageManager === 'yarn') {
fileSys = { 'yarn.lock': '' };
} else if (packageManager === 'pnpm') {
fileSys = { 'pnpm-lock.yaml': '' };
} else {
fileSys = { 'package-lock.json': '' };
}
vol.fromJSON(fileSys, '');
});
describe.each([
['connected to nxCloud', true],
['not connected to nxCloud', false],
] as const)(`%s`, (_, connectedToCloud) => {
let nxCloudAccessToken: string;

it('should generate github CI config', async () => {
await ciWorkflowGenerator(tree, { ci: 'github', name: 'CI' });
beforeEach(() => {
if (connectedToCloud) {
const nxJson = readNxJson(tree);
nxJson.nxCloudAccessToken = 'test';
updateNxJson(tree, nxJson);
} else {
nxCloudAccessToken = process.env.NX_CLOUD_ACCESS_TOKEN;
delete process.env.NX_CLOUD_ACCESS_TOKEN;
}
});

expect(
tree.read('.github/workflows/ci.yml', 'utf-8')
).toMatchSnapshot();
});
afterEach(() => {
if (connectedToCloud) {
const nxJson = readNxJson(tree);
delete nxJson.nxCloudAccessToken;
updateNxJson(tree, nxJson);
} else {
process.env.NX_CLOUD_ACCESS_TOKEN = nxCloudAccessToken;
}
});

it('should generate circleci CI config', async () => {
await ciWorkflowGenerator(tree, { ci: 'circleci', name: 'CI' });
['npm', 'yarn', 'pnpm', 'bun'].forEach((packageManager: PackageManager) => {
describe(`with ${packageManager}`, () => {
beforeEach(() => {
let fileSys;
if (packageManager === 'bun') {
fileSys = { 'bun.lockb': '' };
} else if (packageManager === 'yarn') {
fileSys = { 'yarn.lock': '' };
} else if (packageManager === 'pnpm') {
fileSys = { 'pnpm-lock.yaml': '' };
} else {
fileSys = { 'package-lock.json': '' };
}
vol.fromJSON(fileSys, '');
});

expect(tree.read('.circleci/config.yml', 'utf-8')).toMatchSnapshot();
});
it('should generate github CI config', async () => {
await ciWorkflowGenerator(tree, { ci: 'github', name: 'CI' });

it('should generate azure CI config', async () => {
await ciWorkflowGenerator(tree, { ci: 'azure', name: 'CI' });
expect(
tree.read('.github/workflows/ci.yml', 'utf-8')
).toMatchSnapshot();
});

expect(tree.read('azure-pipelines.yml', 'utf-8')).toMatchSnapshot();
});
it('should generate circleci CI config', async () => {
await ciWorkflowGenerator(tree, { ci: 'circleci', name: 'CI' });

it('should generate github CI config with custom name', async () => {
await ciWorkflowGenerator(tree, {
ci: 'github',
name: 'My custom-workflow',
expect(tree.read('.circleci/config.yml', 'utf-8')).toMatchSnapshot();
});

expect(
tree.read('.github/workflows/my-custom-workflow.yml', 'utf-8')
).toMatchSnapshot();
});
it('should generate azure CI config', async () => {
await ciWorkflowGenerator(tree, { ci: 'azure', name: 'CI' });

it('should generate bitbucket pipelines config', async () => {
await ciWorkflowGenerator(tree, {
ci: 'bitbucket-pipelines',
name: 'CI',
expect(tree.read('azure-pipelines.yml', 'utf-8')).toMatchSnapshot();
});

expect(tree.read('bitbucket-pipelines.yml', 'utf-8')).toMatchSnapshot();
});
it('should generate github CI config with custom name', async () => {
await ciWorkflowGenerator(tree, {
ci: 'github',
name: 'My custom-workflow',
});

expect(
tree.read('.github/workflows/my-custom-workflow.yml', 'utf-8')
).toMatchSnapshot();
});

it('should prefix nx.json affected defaultBase with origin/ if ci is bitbucket-pipelines', async () => {
const nxJson = readJson(tree, 'nx.json');
nxJson.affected.defaultBase = 'my-branch';
writeJson(tree, 'nx.json', nxJson);
it('should generate bitbucket pipelines config', async () => {
await ciWorkflowGenerator(tree, {
ci: 'bitbucket-pipelines',
name: 'CI',
});

await ciWorkflowGenerator(tree, {
ci: 'bitbucket-pipelines',
name: 'CI',
expect(
tree.read('bitbucket-pipelines.yml', 'utf-8')
).toMatchSnapshot();
});

expect(readJson(tree, 'nx.json').affected.defaultBase).toEqual(
'origin/my-branch'
);
});
it('should prefix nx.json affected defaultBase with origin/ if ci is bitbucket-pipelines', async () => {
const nxJson = readJson(tree, 'nx.json');
nxJson.affected.defaultBase = 'my-branch';
writeJson(tree, 'nx.json', nxJson);

it('should prefix nx.json base with origin/ if ci is bitbucket-pipelines', async () => {
const nxJson = readNxJson(tree);
nxJson.defaultBase = 'my-branch';
writeJson(tree, 'nx.json', nxJson);
await ciWorkflowGenerator(tree, {
ci: 'bitbucket-pipelines',
name: 'CI',
});

await ciWorkflowGenerator(tree, {
ci: 'bitbucket-pipelines',
name: 'CI',
expect(readJson(tree, 'nx.json').affected.defaultBase).toEqual(
'origin/my-branch'
);
});

expect(readNxJson(tree).defaultBase).toEqual('origin/my-branch');
});
it('should prefix nx.json base with origin/ if ci is bitbucket-pipelines', async () => {
const nxJson = readNxJson(tree);
nxJson.defaultBase = 'my-branch';
writeJson(tree, 'nx.json', nxJson);

await ciWorkflowGenerator(tree, {
ci: 'bitbucket-pipelines',
name: 'CI',
});

it('should generate gitlab config', async () => {
await ciWorkflowGenerator(tree, { ci: 'gitlab', name: 'CI' });
expect(readNxJson(tree).defaultBase).toEqual('origin/my-branch');
});

expect(tree.read('.gitlab-ci.yml', 'utf-8')).toMatchSnapshot();
it('should generate gitlab config', async () => {
await ciWorkflowGenerator(tree, { ci: 'gitlab', name: 'CI' });

expect(tree.read('.gitlab-ci.yml', 'utf-8')).toMatchSnapshot();
});
});
});
});
Original file line number Diff line number Diff line change
@@ -65,5 +65,6 @@ jobs:

# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - script: <%= packageManagerPrefix %> nx-cloud record -- echo Hello World
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- script: <%= packageManagerPrefix %> nx affected --base=$(BASE_SHA) --head=$(HEAD_SHA) lint test build<% if(hasE2E){ %>
- script: <%= packageManagerPrefix %> nx affected --base=$(BASE_SHA) --head=$(HEAD_SHA) --parallel 1 e2e-ci<% } %>
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ pipelines:
- <%= packageManagerInstall %>

- <%= packageManagerPrefix %> nx-cloud record -- nx format:check
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- <%= packageManagerPrefix %> nx affected --base=origin/<%= mainBranch %> -t lint test build<% if(hasE2E){ %>
- <%= packageManagerPrefix %> nx affected --base=origin/<%= mainBranch %> --parallel 1 -t e2e-ci<% } %>

@@ -55,4 +56,5 @@ pipelines:

# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - <%= packageManagerPrefix %> nx-cloud record -- echo Hello World
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- <%= packageManagerPrefix %> nx affected -t lint test build<% if(hasE2E){ %> e2e-ci<% } %> --base=HEAD~1
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ jobs:

# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - run: <%= packageManagerPrefix %> nx-cloud record -- echo Hello World
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- run: <%= packageManagerPrefix %> nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build<% if(hasE2E){ %>
- run: <%= packageManagerPrefix %> nx affected --base=$NX_BASE --head=$NX_HEAD --parallel 1 -t e2e-ci<% } %>

Original file line number Diff line number Diff line change
@@ -47,5 +47,6 @@ jobs:

# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - run: <%= packageManagerPrefix %> nx-cloud record -- echo Hello World
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- run: <%= packageManagerPrefix %> nx affected -t lint test build<% if(hasE2E){ %>
- run: <%= packageManagerPrefix %> nx affected --parallel 1 -t e2e-ci<% } %>
Original file line number Diff line number Diff line change
@@ -28,5 +28,6 @@ variables:

# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - <%= packageManagerPrefix %> nx-cloud record -- echo Hello World
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
- <%= packageManagerPrefix %> nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build<% if(hasE2E){ %>
- <%= packageManagerPrefix %> nx affected --base=$NX_BASE --head=$NX_HEAD --parallel 1 -t e2e-ci<% } %>

0 comments on commit aa7c5dc

Please sign in to comment.