Skip to content

Commit 6df64b0

Browse files
authored
Merge pull request #26 from paleite/check-for-ci
Check for CI
2 parents 2db4474 + 6eff482 commit 6df64b0

18 files changed

+622
-72
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const typescriptProjects = ["./tsconfig.json", "./tsconfig.eslint.json"];
33
/** @type import("eslint").Linter.Config */
44
module.exports = {
55
root: true,
6-
extends: ["@paleite", "plugin:diff/diff"],
6+
extends: ["@paleite", "plugin:diff/ci"],
77
parserOptions: { project: typescriptProjects, tsconfigRootDir: __dirname },
88
overrides: [
99
{

.github/workflows/eslint-plugin-diff.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,5 @@ jobs:
1212
run: |
1313
yarn link
1414
yarn link "eslint-plugin-diff"
15-
- name: Fetch the base branch
16-
run: git fetch origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }}
1715
- name: Run ESLint on your changes only
18-
env:
19-
ESLINT_PLUGIN_DIFF_COMMIT: ${{ github.event.pull_request.base.ref }}
20-
run: npx --no-install eslint --ext .js,.jsx,.ts,.tsx .
16+
run: yarn run lint

README.md

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,47 @@ yarn add -D eslint eslint-plugin-diff
3636

3737
### Extend config
3838

39-
Extend your ESLint config with `"plugin:diff/diff"`:
39+
Extend your ESLint config with one of our configs.
40+
41+
#### `"plugin:diff/diff"` (recommended)
42+
43+
Only lint changes
4044

4145
```json
4246
{
4347
"extends": ["plugin:diff/diff"]
4448
}
4549
```
4650

47-
You can also choose `"plugin:diff/staged"` if you prefer to lint only staged
48-
files.
51+
#### `"plugin:diff/ci"`
52+
53+
In a CI-environment, only lint changes. Locally, skip the plugin (i.e. lint everything).
54+
55+
> NOTE: This requires the environment variable `CI` to be defined, which most CI-provides set automatically.
56+
57+
```json
58+
{
59+
"extends": ["plugin:diff/ci"]
60+
}
61+
```
62+
63+
#### `"plugin:diff/staged"`
64+
65+
Only lint the changes you've staged for an upcoming commit.
66+
67+
```json
68+
{
69+
"extends": ["plugin:diff/staged"]
70+
}
71+
```
72+
73+
## Enable the plugin in CI only
74+
75+
If you want to enable the plugin in CI only, you can use extend the config with the the plugin locally, but enable it
4976

5077
## CI Setup
5178

52-
To lint all the changes of a PR, you only have to set
79+
To lint all the changes of a pull-request, you only have to set
5380
`ESLINT_PLUGIN_DIFF_COMMIT` before running ESLint.
5481

5582
### For GitHub Actions
@@ -65,7 +92,7 @@ jobs:
6592
- uses: actions/checkout@v3
6693
- name: Install modules
6794
run: npm install
68-
- name: Fetch the base branch
95+
- name: Fetch the base branch, so we can use `git diff`
6996
run: git fetch origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }}
7097
- name: Run ESLint on your changes only
7198
env:

jest.config.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ const { base } = require("@paleite/jest-config");
44
/** @type {import('@jest/types').Config.InitialOptions} */
55
module.exports = {
66
...base,
7+
coveragePathIgnorePatterns: [".test-d.ts"],
78
coverageThreshold: {
89
global: {
9-
branches: 75,
10-
functions: 80,
11-
lines: 80,
12-
statements: 80,
10+
statements: 90,
11+
branches: 90,
12+
functions: 90,
13+
lines: 90,
1314
},
1415
},
1516
};

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"@typescript-eslint/parser": "^5.27.0",
5757
"eslint": "^8.17.0",
5858
"eslint-config-prettier": "^8.5.0",
59+
"eslint-import-resolver-typescript": "^3.3.0",
5960
"eslint-plugin-import": "^2.26.0",
6061
"eslint-plugin-promise": "^6.0.0",
6162
"husky": "^8.0.1",
@@ -69,6 +70,7 @@
6970
"size-limit": "^7.0.8",
7071
"terser": "^5.14.2",
7172
"ts-jest": "^28.0.4",
73+
"tsd": "^0.22.0",
7274
"typescript": "^4.7.3"
7375
},
7476
"peerDependencies": {

src/__fixtures__/diff.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,12 @@ index cb3c131..874b8f9 100644
4646
-import { b } from "../context/b";
4747
-import { c } from "../context/c";`;
4848

49-
const filenamesAB = `a/dirty.js
50-
b/dirty.js
51-
`;
52-
53-
const filenamesA = `a/dirty.js
54-
`;
55-
5649
const diffFileList = "file1\nfile2\nfile3\n";
5750

5851
export {
5952
diff,
6053
staged,
6154
hunks,
6255
includingOnlyRemovals,
63-
filenamesAB,
64-
filenamesA,
6556
diffFileList,
6657
};

src/__snapshots__/index.test.ts.snap

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
exports[`plugin should match expected export 1`] = `
44
Object {
5+
"ci": Object {
6+
"overrides": Array [
7+
Object {
8+
"files": Array [
9+
"*",
10+
],
11+
"processor": "diff/ci",
12+
},
13+
],
14+
"plugins": Array [
15+
"diff",
16+
],
17+
},
518
"diff": Object {
619
"overrides": Array [
720
Object {
@@ -33,6 +46,11 @@ Object {
3346

3447
exports[`plugin should match expected export 2`] = `
3548
Object {
49+
"ci": Object {
50+
"postprocess": [Function],
51+
"preprocess": [Function],
52+
"supportsAutofix": true,
53+
},
3654
"diff": Object {
3755
"postprocess": [Function],
3856
"preprocess": [Function],

src/ci.test-d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { expectType } from "tsd";
2+
import type { CiProvider, CiProviderName } from "./ci";
3+
import { PROVIDERS } from "./ci";
4+
5+
expectType<Record<CiProviderName, CiProvider>>(PROVIDERS);

src/ci.test.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
const OLD_ENV = process.env;
2+
3+
beforeEach(() => {
4+
jest.resetModules(); // Most important - it clears the cache
5+
process.env = { ...OLD_ENV }; // Make a copy
6+
});
7+
8+
describe("guessBranch", () => {
9+
it("ensure the branch is guessed if ESLINT_PLUGIN_COMMIT is not already set", async () => {
10+
delete process.env.ESLINT_PLUGIN_COMMIT;
11+
const { guessBranch } = await import("./ci");
12+
expect(() => guessBranch()).not.toThrowError(/ESLINT_PLUGIN_COMMIT/u);
13+
});
14+
15+
it("ensure the branch is not guessed if ESLINT_PLUGIN_COMMIT is already set", async () => {
16+
process.env.ESLINT_PLUGIN_COMMIT = "origin/main";
17+
const { guessBranch } = await import("./ci");
18+
expect(() => guessBranch()).toThrowError(/ESLINT_PLUGIN_COMMIT/u);
19+
});
20+
21+
it("fails when too many providers were found as candidates", async () => {
22+
process.env.SYSTEM_PULLREQUEST_TARGETBRANCH = "CORRECT";
23+
process.env.bamboo_repository_pr_targetBranch = "CORRECT";
24+
process.env.BITBUCKET_PR_DESTINATION_BRANCH = "CORRECT";
25+
process.env.BUDDY_EXECUTION_PULL_REQUEST_BASE_BRANCH = "CORRECT";
26+
process.env.DRONE_TARGET_BRANCH = "CORRECT";
27+
process.env.GITHUB_BASE_REF = "CORRECT";
28+
process.env.APPVEYOR_PULL_REQUEST_NUMBER = "0";
29+
process.env.APPVEYOR_REPO_BRANCH = "CORRECT";
30+
process.env.CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME = "CORRECT";
31+
process.env.TRAVIS_BRANCH = "CORRECT";
32+
const { guessBranch } = await import("./ci");
33+
expect(() => guessBranch()).toThrowError(/Too many CI providers found/u);
34+
});
35+
});
36+
37+
describe("simple supported providers", () => {
38+
it("AzurePipelines", async () => {
39+
process.env.SYSTEM_PULLREQUEST_TARGETBRANCH = "CORRECT";
40+
const { guessBranch } = await import("./ci");
41+
expect(guessBranch()).toBe("CORRECT");
42+
});
43+
44+
it("Bamboo", async () => {
45+
process.env.bamboo_repository_pr_targetBranch = "CORRECT";
46+
const { guessBranch } = await import("./ci");
47+
expect(guessBranch()).toBe("CORRECT");
48+
});
49+
50+
it("BitbucketPipelines", async () => {
51+
process.env.BITBUCKET_PR_DESTINATION_BRANCH = "CORRECT";
52+
const { guessBranch } = await import("./ci");
53+
expect(guessBranch()).toBe("CORRECT");
54+
});
55+
56+
it("Buddy", async () => {
57+
process.env.BUDDY_EXECUTION_PULL_REQUEST_BASE_BRANCH = "CORRECT";
58+
const { guessBranch } = await import("./ci");
59+
expect(guessBranch()).toBe("CORRECT");
60+
});
61+
62+
it("Drone", async () => {
63+
process.env.DRONE_TARGET_BRANCH = "CORRECT";
64+
const { guessBranch } = await import("./ci");
65+
expect(guessBranch()).toBe("CORRECT");
66+
});
67+
68+
it("GitHubActions", async () => {
69+
process.env.GITHUB_BASE_REF = "CORRECT";
70+
const { guessBranch } = await import("./ci");
71+
expect(guessBranch()).toBe("CORRECT");
72+
});
73+
});
74+
75+
describe("complex supported providers", () => {
76+
it("AppVeyor", async () => {
77+
// APPVEYOR_PULL_REQUEST_NUMBER is non-empty, so we can find the repo in
78+
// APPVEYOR_REPO_BRANCH
79+
process.env.APPVEYOR_PULL_REQUEST_NUMBER = "0";
80+
process.env.APPVEYOR_REPO_BRANCH = "CORRECT";
81+
82+
const { guessBranch } = await import("./ci");
83+
expect(guessBranch()).toBe("CORRECT");
84+
});
85+
86+
it("doesn't return the guessed branch when APPVEYOR_PULL_REQUEST_NUMBER is empty", async () => {
87+
// APPVEYOR_PULL_REQUEST_NUMBER is non-empty iff we're in a pull-request.
88+
delete process.env.APPVEYOR_PULL_REQUEST_NUMBER;
89+
// Scenario: A regular commit to main, not a pull-request.
90+
process.env.APPVEYOR_REPO_BRANCH = "main";
91+
92+
const { guessBranch } = await import("./ci");
93+
expect(guessBranch()).toBe(undefined);
94+
});
95+
96+
it("GitLab with CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME", async () => {
97+
delete process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
98+
process.env.CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME = "CORRECT";
99+
const { guessBranch } = await import("./ci");
100+
expect(guessBranch()).toBe("CORRECT");
101+
});
102+
103+
it("GitLab with CI_MERGE_REQUEST_TARGET_BRANCH_NAME", async () => {
104+
delete process.env.CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME;
105+
process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME = "CORRECT";
106+
const { guessBranch } = await import("./ci");
107+
expect(guessBranch()).toBe("CORRECT");
108+
});
109+
110+
it("Travis", async () => {
111+
delete process.env.TRAVIS_PULL_REQUEST;
112+
process.env.TRAVIS_BRANCH = "CORRECT";
113+
const { guessBranch } = await import("./ci");
114+
expect(guessBranch()).toBe("CORRECT");
115+
});
116+
117+
it("doesn't return the guessed branch when TRAVIS_PULL_REQUEST is explicitly 'false'", async () => {
118+
process.env.TRAVIS_PULL_REQUEST = "false";
119+
process.env.TRAVIS_BRANCH = "CORRECT";
120+
const { guessBranch } = await import("./ci");
121+
expect(guessBranch()).toBe(undefined);
122+
});
123+
});
124+
125+
export {};

0 commit comments

Comments
 (0)