@applitools/core 4.61.0 → 4.61.1-debug.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/dist/classic/utils/extract-default-environments.js +2 -2
- package/dist/cli/cli.js +160 -0
- package/dist/open-eyes.js +16 -11
- package/dist/ufg/check.js +1 -0
- package/dist/ufg/create-render-target-from-snapshot.js +1 -0
- package/dist/universal/core-server-process.js +31 -0
- package/dist/universal/core-server.js +216 -0
- package/dist/universal/history.js +90 -0
- package/dist/universal/refer.js +67 -0
- package/dist/universal/spec-driver.js +189 -0
- package/dist/universal/types.js +2 -0
- package/dist/universal/ws-server.js +66 -0
- package/dist/utils/extract-git-info.js +738 -140
- package/package.json +15 -12
- package/types/automation/types.d.ts +1 -0
- package/types/cli/cli.d.ts +2 -0
- package/types/universal/core-server-process.d.ts +9 -0
- package/types/universal/core-server.d.ts +18 -0
- package/types/universal/history.d.ts +2 -0
- package/types/universal/refer.d.ts +8 -0
- package/types/universal/spec-driver.d.ts +15 -0
- package/types/universal/types.d.ts +205 -0
- package/types/universal/ws-server.d.ts +15 -0
- package/types/utils/extract-git-info.d.ts +146 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applitools/core",
|
|
3
|
-
"version": "4.61.0",
|
|
3
|
+
"version": "4.61.1-debug.0",
|
|
4
4
|
"homepage": "https://applitools.com",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/applitools/eyes.sdk.javascript1/issues"
|
|
@@ -56,20 +56,21 @@
|
|
|
56
56
|
"test:it": "MOCHA_GROUP=it run --top-level mocha './test/it/**/*.spec.ts' --require ./test/mocha-global-setup.js",
|
|
57
57
|
"test:e2e:sync": "MOCHA_GROUP=e2e SYNC=true run --top-level mocha './test/e2e/mocha-sync/**/*.spec.ts' --exit --require ./test/mocha-global-setup.js",
|
|
58
58
|
"test:unit": "MOCHA_GROUP=unit run --top-level mocha './test/unit/**/*.spec.ts' --require ./test/mocha-global-setup.js",
|
|
59
|
-
"setup": "run --top-level browsers:setup && run --top-level xvfb:setup",
|
|
59
|
+
"setup": "run --top-level browsers:setup && run --top-level xvfb:setup && run playwright:setup",
|
|
60
|
+
"playwright:setup": "node -e \"var v=parseInt(process.version.slice(1));if(v>=18){require('child_process').execSync('yarn playwright install --with-deps firefox',{stdio:'inherit'})}else{console.log('Skipping playwright install (Node '+process.version+')')}\"",
|
|
60
61
|
"setup:standalone": "sh -c 'yarn chromedriver --port=4444 --verbose &'"
|
|
61
62
|
},
|
|
62
63
|
"dependencies": {
|
|
63
64
|
"@applitools/core-base": "1.33.0",
|
|
64
|
-
"@applitools/dom-capture": "11.
|
|
65
|
-
"@applitools/dom-snapshot": "4.
|
|
66
|
-
"@applitools/driver": "1.
|
|
67
|
-
"@applitools/ec-client": "1.12.
|
|
65
|
+
"@applitools/dom-capture": "11.8.0",
|
|
66
|
+
"@applitools/dom-snapshot": "4.17.0",
|
|
67
|
+
"@applitools/driver": "1.26.0",
|
|
68
|
+
"@applitools/ec-client": "1.12.28",
|
|
68
69
|
"@applitools/logger": "2.2.11",
|
|
69
|
-
"@applitools/nml-client": "1.11.
|
|
70
|
+
"@applitools/nml-client": "1.11.26",
|
|
70
71
|
"@applitools/req": "1.10.0",
|
|
71
|
-
"@applitools/screenshoter": "3.12.
|
|
72
|
-
"@applitools/snippets": "2.
|
|
72
|
+
"@applitools/screenshoter": "3.12.19",
|
|
73
|
+
"@applitools/snippets": "2.9.0",
|
|
73
74
|
"@applitools/socket": "1.3.12",
|
|
74
75
|
"@applitools/ufg-client": "1.22.0",
|
|
75
76
|
"@applitools/utils": "1.14.4",
|
|
@@ -81,11 +82,12 @@
|
|
|
81
82
|
},
|
|
82
83
|
"devDependencies": {
|
|
83
84
|
"@applitools/bongo": "^5.10.0",
|
|
84
|
-
"@applitools/spec-driver-
|
|
85
|
-
"@applitools/spec-driver-
|
|
85
|
+
"@applitools/spec-driver-playwright": "^1.9.0",
|
|
86
|
+
"@applitools/spec-driver-puppeteer": "^1.8.0",
|
|
87
|
+
"@applitools/spec-driver-selenium": "^1.8.0",
|
|
86
88
|
"@applitools/test-server": "^1.4.3",
|
|
87
89
|
"@applitools/test-utils": "^1.5.17",
|
|
88
|
-
"@applitools/tunnel-client": "^1.11.
|
|
90
|
+
"@applitools/tunnel-client": "^1.11.12",
|
|
89
91
|
"@types/mocha": "^10.0.7",
|
|
90
92
|
"@types/node": "^12.20.55",
|
|
91
93
|
"@types/selenium-webdriver": "^4.1.2",
|
|
@@ -93,6 +95,7 @@
|
|
|
93
95
|
"chromedriver": "^131.0.5",
|
|
94
96
|
"crypto": "^1.0.1",
|
|
95
97
|
"nock": "^13.3.2",
|
|
98
|
+
"playwright": "1.47.0",
|
|
96
99
|
"png-async": "^0.9.4",
|
|
97
100
|
"puppeteer": "^24.11.1",
|
|
98
101
|
"selenium-webdriver": "^4.15.0"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { type Options } from './core-server';
|
|
3
|
+
import { type ForkOptions } from 'child_process';
|
|
4
|
+
export declare function makeCoreServerProcess(options: Options & {
|
|
5
|
+
forkOptions?: ForkOptions;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
port: number;
|
|
8
|
+
close: () => void;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ServerOptions } from './ws-server';
|
|
2
|
+
import { type Logger } from '@applitools/logger';
|
|
3
|
+
export type Options = ServerOptions & {
|
|
4
|
+
environment?: Record<string, any>;
|
|
5
|
+
agentIdPrefix?: string;
|
|
6
|
+
debug?: boolean;
|
|
7
|
+
shutdownMode?: 'lazy' | 'stdin';
|
|
8
|
+
idleTimeout?: number;
|
|
9
|
+
printStdout?: boolean;
|
|
10
|
+
isProcess?: boolean;
|
|
11
|
+
maskLog?: boolean;
|
|
12
|
+
logger?: Logger;
|
|
13
|
+
};
|
|
14
|
+
export declare function makeCoreServer({ environment: defaultEnvironment, agentIdPrefix, debug, shutdownMode, idleTimeout, // 15min
|
|
15
|
+
printStdout, isProcess, maskLog, logger, ...handlerOptions }?: Options): Promise<{
|
|
16
|
+
port: number;
|
|
17
|
+
close?: () => void;
|
|
18
|
+
}>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Ref } from './types';
|
|
2
|
+
export interface Refer {
|
|
3
|
+
isRef<TValue = any>(ref: any): ref is Ref<TValue>;
|
|
4
|
+
ref<TValue>(value: TValue, parentRef?: Ref<unknown>): Ref<TValue>;
|
|
5
|
+
deref<TValue>(ref: Ref<TValue>): TValue;
|
|
6
|
+
destroy(ref: Ref<any>): void;
|
|
7
|
+
}
|
|
8
|
+
export declare function makeRefer(): Refer;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Ref, ServerSocket, UniversalSpecDriver } from './types';
|
|
2
|
+
import type { SpecType, SpecDriver as BaseSpecDriver, CommonSelector } from '@applitools/driver';
|
|
3
|
+
export type Driver = Ref;
|
|
4
|
+
export type Context = Ref;
|
|
5
|
+
export type Element = Ref;
|
|
6
|
+
export type Selector = string | CommonSelector | Ref;
|
|
7
|
+
export type UserFunction = Ref;
|
|
8
|
+
export type PrimarySpecType = SpecType<Driver, Context, Element, Selector, never, UserFunction>;
|
|
9
|
+
export type SpecDriver = BaseSpecDriver<PrimarySpecType>;
|
|
10
|
+
type CommandName = keyof UniversalSpecDriver<PrimarySpecType>;
|
|
11
|
+
export declare function makeSpec({ socket, spec, }: {
|
|
12
|
+
socket: ServerSocket<PrimarySpecType, any>;
|
|
13
|
+
spec: CommandName[];
|
|
14
|
+
}): SpecDriver;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type { Size, Region } from '@applitools/utils';
|
|
2
|
+
import type { Emitter, Listener, Client, Server } from '@applitools/socket';
|
|
3
|
+
import type { SpecType, DriverInfo, Cookie, WaitOptions } from '@applitools/driver';
|
|
4
|
+
import type * as MainCore from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Wraps the type with a ref if it vas to be refed
|
|
7
|
+
*/
|
|
8
|
+
type Refify<TValue> = TValue extends string | number | boolean | null | undefined ? TValue : TValue extends Array<infer TItem> ? Refify<TItem>[] : Extract<TValue[keyof TValue], (...args: any) => any> extends never ? TValue : Ref<TValue>;
|
|
9
|
+
/**
|
|
10
|
+
* Creates universalized object out of an ordinary interface:
|
|
11
|
+
* - Filters out properties that are not of async function type
|
|
12
|
+
* - Adds domain to the method names (`Domain.methodName`)
|
|
13
|
+
* - Keep only first (`options`) argument of the methods
|
|
14
|
+
* - Introduces additional option to the methods with a ref of the current instance
|
|
15
|
+
* - Refifies return values of the methods
|
|
16
|
+
*/
|
|
17
|
+
type Universalize<TTarget extends Record<string, any>, TDomain extends string, TRefKey extends string = never> = {
|
|
18
|
+
[TKey in keyof TTarget as NonNullable<TTarget[TKey]> extends (...args: any[]) => Promise<any> ? `${TDomain}.${TKey & string}` : never]: NonNullable<TTarget[TKey]> extends (options: infer TOptions) => Promise<infer TResult> ? (options: TOptions & {
|
|
19
|
+
[TKey in TRefKey]: Ref<TTarget>;
|
|
20
|
+
}) => Promise<Refify<TResult>> : never;
|
|
21
|
+
};
|
|
22
|
+
export type Ref<TValue = never> = {
|
|
23
|
+
'applitools-ref-id': string;
|
|
24
|
+
type?: string;
|
|
25
|
+
};
|
|
26
|
+
export type ClientSocket<TSpec extends SpecType, TType extends 'classic' | 'ufg'> = unknown & Emitter<Universalize<UniversalCore<TSpec, TType>, 'Core'>> & Client<Universalize<MainCore.Core<TSpec, TType>, 'Core'>> & Client<Universalize<MainCore.EyesManager<TSpec, TType>, 'EyesManager', 'manager'>> & Client<Universalize<MainCore.Eyes<TSpec, TType>, 'Eyes', 'eyes'>> & Client<Universalize<UniversalDebug<TSpec>, 'Debug'>> & Server<Universalize<UniversalSpecDriver<TSpec>, 'Driver'>>;
|
|
27
|
+
export type ServerSocket<TSpec extends SpecType, TType extends 'classic' | 'ufg'> = unknown & Listener<Universalize<UniversalCore<TSpec, TType>, 'Core'>> & Emitter<Universalize<UniversalLogger, 'Logger'>> & Server<Universalize<MainCore.Core<TSpec, TType>, 'Core'>> & Server<Universalize<MainCore.EyesManager<TSpec, TType>, 'EyesManager', 'manager'>> & Server<Universalize<MainCore.Eyes<TSpec, TType>, 'Eyes', 'eyes'>> & Server<Universalize<UniversalDebug<TSpec>, 'Debug'>> & Client<Universalize<UniversalSpecDriver<TSpec>, 'Driver'>>;
|
|
28
|
+
export interface UniversalCore<TSpec extends SpecType, TType extends 'classic' | 'ufg'> {
|
|
29
|
+
makeCore(options: {
|
|
30
|
+
spec: 'webdriver' | (keyof UniversalSpecDriver<TSpec>)[];
|
|
31
|
+
agentId: string;
|
|
32
|
+
environment?: Record<string, any>;
|
|
33
|
+
cwd: string;
|
|
34
|
+
}): Promise<MainCore.Core<TSpec, TType>>;
|
|
35
|
+
}
|
|
36
|
+
export interface UniversalLogger {
|
|
37
|
+
log(options: {
|
|
38
|
+
level: string;
|
|
39
|
+
message: string;
|
|
40
|
+
}): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
export interface UniversalDebug<TSpec extends SpecType> {
|
|
43
|
+
getHistory(): Promise<any>;
|
|
44
|
+
checkSpecDriver(options: {
|
|
45
|
+
driver: TSpec['driver'];
|
|
46
|
+
commands: (keyof UniversalSpecDriver<TSpec>)[];
|
|
47
|
+
}): Promise<any>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Ideally would be transform SpecDriver type to the type with single object argument
|
|
51
|
+
* but typescript doesn't have a possibility to convert named tuples to object types at the moment
|
|
52
|
+
*/
|
|
53
|
+
export interface UniversalSpecDriver<T extends SpecType> {
|
|
54
|
+
isEqualElements(options: {
|
|
55
|
+
context: T['context'];
|
|
56
|
+
element1: T['element'];
|
|
57
|
+
element2: T['element'];
|
|
58
|
+
}): Promise<boolean>;
|
|
59
|
+
executeScript(options: {
|
|
60
|
+
context: T['context'];
|
|
61
|
+
script: string;
|
|
62
|
+
arg?: any;
|
|
63
|
+
}): Promise<any>;
|
|
64
|
+
findElement(options: {
|
|
65
|
+
context: T['context'];
|
|
66
|
+
selector: T['selector'];
|
|
67
|
+
parent?: T['element'];
|
|
68
|
+
}): Promise<T['element'] | null>;
|
|
69
|
+
findElements(options: {
|
|
70
|
+
context: T['context'];
|
|
71
|
+
selector: T['selector'];
|
|
72
|
+
parent?: T['element'];
|
|
73
|
+
}): Promise<T['element'][]>;
|
|
74
|
+
waitForSelector(options: {
|
|
75
|
+
context: T['context'];
|
|
76
|
+
selector: T['selector'];
|
|
77
|
+
parent?: T['element'];
|
|
78
|
+
options?: WaitOptions;
|
|
79
|
+
}): Promise<T['element'] | null>;
|
|
80
|
+
getElementRegion(options: {
|
|
81
|
+
context: T['context'];
|
|
82
|
+
element: T['element'];
|
|
83
|
+
}): Promise<Region>;
|
|
84
|
+
getElementAttribute(options: {
|
|
85
|
+
context: T['context'];
|
|
86
|
+
element: T['element'];
|
|
87
|
+
attr: string;
|
|
88
|
+
}): Promise<string>;
|
|
89
|
+
setElementText(options: {
|
|
90
|
+
context: T['context'];
|
|
91
|
+
element: T['element'];
|
|
92
|
+
text: string;
|
|
93
|
+
}): Promise<void>;
|
|
94
|
+
getElementText(options: {
|
|
95
|
+
context: T['context'];
|
|
96
|
+
element: T['element'];
|
|
97
|
+
}): Promise<string>;
|
|
98
|
+
hover(options: {
|
|
99
|
+
context: T['context'];
|
|
100
|
+
element: T['element'];
|
|
101
|
+
}): Promise<void>;
|
|
102
|
+
click(options: {
|
|
103
|
+
context: T['context'];
|
|
104
|
+
element: T['element'];
|
|
105
|
+
}): Promise<void>;
|
|
106
|
+
mainContext(options: {
|
|
107
|
+
context: T['context'];
|
|
108
|
+
}): Promise<T['context']>;
|
|
109
|
+
parentContext(options: {
|
|
110
|
+
context: T['context'];
|
|
111
|
+
}): Promise<T['context']>;
|
|
112
|
+
childContext(options: {
|
|
113
|
+
context: T['context'];
|
|
114
|
+
element: T['element'];
|
|
115
|
+
}): Promise<T['context']>;
|
|
116
|
+
getDriverInfo(options: {
|
|
117
|
+
driver: T['driver'];
|
|
118
|
+
}): Promise<DriverInfo>;
|
|
119
|
+
getCapabilities(options: {
|
|
120
|
+
driver: T['driver'];
|
|
121
|
+
}): Promise<Record<string, any>>;
|
|
122
|
+
setWindowSize(options: {
|
|
123
|
+
driver: T['driver'];
|
|
124
|
+
size: Size;
|
|
125
|
+
}): Promise<void>;
|
|
126
|
+
getWindowSize(options: {
|
|
127
|
+
driver: T['driver'];
|
|
128
|
+
}): Promise<Size>;
|
|
129
|
+
setViewportSize(options: {
|
|
130
|
+
driver: T['driver'];
|
|
131
|
+
size: Size;
|
|
132
|
+
}): Promise<void>;
|
|
133
|
+
getViewportSize(options: {
|
|
134
|
+
driver: T['driver'];
|
|
135
|
+
}): Promise<Size>;
|
|
136
|
+
getSystemBars(options: {
|
|
137
|
+
driver: T['driver'];
|
|
138
|
+
}): Promise<{
|
|
139
|
+
statusBar: {
|
|
140
|
+
visible: boolean;
|
|
141
|
+
x: number;
|
|
142
|
+
y: number;
|
|
143
|
+
height: number;
|
|
144
|
+
width: number;
|
|
145
|
+
};
|
|
146
|
+
navigationBar: {
|
|
147
|
+
visible: boolean;
|
|
148
|
+
x: number;
|
|
149
|
+
y: number;
|
|
150
|
+
height: number;
|
|
151
|
+
width: number;
|
|
152
|
+
};
|
|
153
|
+
}>;
|
|
154
|
+
getOrientation(options: {
|
|
155
|
+
driver: T['driver'];
|
|
156
|
+
}): Promise<'portrait' | 'landscape' | 'portrait-secondary' | 'landscape-secondary'>;
|
|
157
|
+
setOrientation(options: {
|
|
158
|
+
driver: T['driver'];
|
|
159
|
+
orientation: 'portrait' | 'landscape' | 'portrait-secondary' | 'landscape-secondary';
|
|
160
|
+
}): Promise<void>;
|
|
161
|
+
getCookies(options: {
|
|
162
|
+
driver: T['driver'] | T['context'];
|
|
163
|
+
context?: boolean;
|
|
164
|
+
}): Promise<Cookie[]>;
|
|
165
|
+
getTitle(options: {
|
|
166
|
+
driver: T['driver'];
|
|
167
|
+
}): Promise<string>;
|
|
168
|
+
getUrl(options: {
|
|
169
|
+
driver: T['driver'];
|
|
170
|
+
}): Promise<string>;
|
|
171
|
+
takeScreenshot(options: {
|
|
172
|
+
driver: T['driver'];
|
|
173
|
+
}): Promise<string>;
|
|
174
|
+
performAction(options: {
|
|
175
|
+
driver: T['driver'];
|
|
176
|
+
steps: any[];
|
|
177
|
+
}): Promise<void>;
|
|
178
|
+
visit(options: {
|
|
179
|
+
driver: T['driver'];
|
|
180
|
+
url: string;
|
|
181
|
+
}): Promise<void>;
|
|
182
|
+
getCurrentWorld(options: {
|
|
183
|
+
driver: T['driver'];
|
|
184
|
+
}): Promise<string>;
|
|
185
|
+
getWorlds(options: {
|
|
186
|
+
driver: T['driver'];
|
|
187
|
+
}): Promise<string[]>;
|
|
188
|
+
switchWorld(options: {
|
|
189
|
+
driver: T['driver'];
|
|
190
|
+
name: string;
|
|
191
|
+
}): Promise<void>;
|
|
192
|
+
reload(options: {
|
|
193
|
+
driver: T['driver'];
|
|
194
|
+
}): Promise<void>;
|
|
195
|
+
isUserFunction(ref: any): Promise<boolean>;
|
|
196
|
+
executeUserFunction(userFunction: Ref): Promise<any>;
|
|
197
|
+
executeBrowserCommands(options: {
|
|
198
|
+
driver?: T['driver'];
|
|
199
|
+
commands: any[];
|
|
200
|
+
}): Promise<any>;
|
|
201
|
+
bringToFront(options: {
|
|
202
|
+
driver: T['driver'];
|
|
203
|
+
}): Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Server as WsServer } from 'ws';
|
|
3
|
+
import { Logger } from '@applitools/logger';
|
|
4
|
+
export type ServerOptions = {
|
|
5
|
+
port?: number;
|
|
6
|
+
singleton?: boolean;
|
|
7
|
+
portResolutionMode?: 'next' | 'random' | 'lazy';
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
key?: string | Buffer;
|
|
10
|
+
cert?: string | Buffer;
|
|
11
|
+
};
|
|
12
|
+
export declare function makeServer(options: ServerOptions | undefined, logger: Logger): Promise<{
|
|
13
|
+
server?: WsServer;
|
|
14
|
+
port: number;
|
|
15
|
+
}>;
|
|
@@ -30,6 +30,81 @@ export declare const getPrimaryRemoteName: (({ execOptions, logger }: {
|
|
|
30
30
|
clearCache(): void;
|
|
31
31
|
TTL?: number | undefined;
|
|
32
32
|
};
|
|
33
|
+
export type GitEnvironmentResult = {
|
|
34
|
+
/** `git` binary is on PATH and executable. */
|
|
35
|
+
gitInstalled: boolean;
|
|
36
|
+
/** Current working directory is inside a git work tree. */
|
|
37
|
+
insideRepo: boolean;
|
|
38
|
+
/** A primary remote is configured AND reachable. */
|
|
39
|
+
remoteAccessible: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* `gitInstalled && insideRepo` — sufficient for local-only git operations
|
|
42
|
+
* (commit lookups, local branch detection, local merge-base). Does NOT
|
|
43
|
+
* imply remote ops will succeed — callers that need the remote must
|
|
44
|
+
* additionally check `remoteAccessible`.
|
|
45
|
+
*/
|
|
46
|
+
ok: boolean;
|
|
47
|
+
/** Human-readable explanation covering every sub-check; used in skip-logs. */
|
|
48
|
+
reason: string;
|
|
49
|
+
/** Resolved primary remote name, when one is configured. */
|
|
50
|
+
remoteName?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* One-shot, cached probe of the full git environment, staged from cheapest
|
|
54
|
+
* to most expensive:
|
|
55
|
+
* 1. is `git` installed and on PATH? (`git --version`)
|
|
56
|
+
* 2. are we inside a git work tree? (`git rev-parse --is-inside-work-tree`)
|
|
57
|
+
* 3. is a primary remote configured? (`git remote`)
|
|
58
|
+
* 4. is that remote reachable? (`git ls-remote <r> HEAD`)
|
|
59
|
+
*
|
|
60
|
+
* Use this as the outermost guard for any code path that shells out to git.
|
|
61
|
+
* Each step short-circuits later ones: missing binary skips repo/remote
|
|
62
|
+
* checks; non-repo skips remote checks; no remote configured skips the
|
|
63
|
+
* reachability probe. Callers should consult `ok` for local-only git
|
|
64
|
+
* features and `remoteAccessible` for anything that talks to the network.
|
|
65
|
+
*
|
|
66
|
+
* Cached per `cwd`. The first invocation emits a clearly-visible banner so
|
|
67
|
+
* support can grep one distinctive line — `APPLITOOLS GIT ENVIRONMENT CHECK`
|
|
68
|
+
* — and immediately tell which sub-check failed. Subsequent invocations
|
|
69
|
+
* return the cached verdict silently.
|
|
70
|
+
*/
|
|
71
|
+
export declare const checkGitEnvironment: (({ execOptions, logger, }: {
|
|
72
|
+
execOptions?: ExecOptions | undefined;
|
|
73
|
+
logger?: Logger | undefined;
|
|
74
|
+
}) => Promise<GitEnvironmentResult>) & {
|
|
75
|
+
getCachedValues(): Promise<GitEnvironmentResult>[];
|
|
76
|
+
setCachedValue(key: any, value: Promise<GitEnvironmentResult>): void;
|
|
77
|
+
clearCache(): void;
|
|
78
|
+
TTL?: number | undefined;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Programmatically detect the default branch of the current repository.
|
|
82
|
+
*
|
|
83
|
+
* Fallback chain (each step short-circuits on success; never throws):
|
|
84
|
+
* 1. `APPLITOOLS_DEFAULT_BRANCH` env var — explicit user override.
|
|
85
|
+
* 2. `git symbolic-ref --short refs/remotes/<remote>/HEAD` — authoritative
|
|
86
|
+
* source on any clone that has fetched at least once. Returns e.g.
|
|
87
|
+
* `origin/master`; the `<remote>/` prefix is stripped.
|
|
88
|
+
* 3. `git ls-remote --symref <remote> HEAD` — works even when the local
|
|
89
|
+
* `refs/remotes/<remote>/HEAD` symref was never set up (single-branch
|
|
90
|
+
* clones, older git on CI).
|
|
91
|
+
* 4. `git config --get init.defaultBranch` — honors a user-global preference
|
|
92
|
+
* if everything else fails.
|
|
93
|
+
* 5. Literal `'main'` — last resort.
|
|
94
|
+
*
|
|
95
|
+
* Steps 2 and 3 catch non-standard defaults (e.g. JFrog's
|
|
96
|
+
* `JFROG/artifactory-mfe/preRelease/jfmfe-1.995.x-rc`). Cached per `cwd`
|
|
97
|
+
* to match `getPrimaryRemoteName`.
|
|
98
|
+
*/
|
|
99
|
+
export declare const extractDefaultBranch: (({ execOptions, logger }: {
|
|
100
|
+
execOptions?: ExecOptions | undefined;
|
|
101
|
+
logger?: Logger | undefined;
|
|
102
|
+
}) => Promise<string>) & {
|
|
103
|
+
getCachedValues(): Promise<string>[];
|
|
104
|
+
setCachedValue(key: any, value: Promise<string>): void;
|
|
105
|
+
clearCache(): void;
|
|
106
|
+
TTL?: number | undefined;
|
|
107
|
+
};
|
|
33
108
|
export declare const extractLatestCommitInfo: (({ execOptions, logger, }: ExtractCurrentCommitTimestampOptions) => Promise<{
|
|
34
109
|
timestamp: string;
|
|
35
110
|
sha: string;
|
|
@@ -68,6 +143,31 @@ export declare const extractGitRepo: (({ execOptions, logger }: Options) => Prom
|
|
|
68
143
|
};
|
|
69
144
|
export declare function extractCIBranchName(): string | undefined;
|
|
70
145
|
export declare function extractBuildIdFromCI(): Promise<string | undefined>;
|
|
146
|
+
/**
|
|
147
|
+
* Extract the ISO-8601 timestamp at which `branchName` branched off from
|
|
148
|
+
* `parentBranchName`.
|
|
149
|
+
*
|
|
150
|
+
* Algorithm (each step short-circuits on success; returns `undefined` on
|
|
151
|
+
* total failure — never throws):
|
|
152
|
+
* 1. If the repo is a shallow clone, unshallow (or treeless-fetch) so the
|
|
153
|
+
* branch topology is visible to `git merge-base`.
|
|
154
|
+
* 2. `git merge-base <remote>/<branch> <remote>/<parent>` — CI typically
|
|
155
|
+
* operates on remote refs only, so try those first.
|
|
156
|
+
* 3. Fall back to local refs (`git merge-base <branch> <parent>`).
|
|
157
|
+
* 4. If still no merge-base, see if the parent exists on the remote and,
|
|
158
|
+
* if so, fetch it by name (`--filter=tree:0`) and retry. If the parent
|
|
159
|
+
* isn't on the remote at all, give up — we can't compute a branching
|
|
160
|
+
* point for a branch that doesn't exist anywhere.
|
|
161
|
+
* 5. Direct-ancestor refinement: if the merge-base equals the parent
|
|
162
|
+
* branch's tip, the parent hasn't diverged from `branchName` yet
|
|
163
|
+
* (parent is a strict ancestor). The "branching point" is then the
|
|
164
|
+
* parent commit of the first child-only commit — not the merge-base
|
|
165
|
+
* itself, which would be the parent's tip and produce a too-recent
|
|
166
|
+
* timestamp.
|
|
167
|
+
* 6. Resolve the final hash's committer-date via `git show -s --format=%aI`.
|
|
168
|
+
*
|
|
169
|
+
* Cached per (branchName, parentBranchName, cwd).
|
|
170
|
+
*/
|
|
71
171
|
export declare const extractBranchingTimestamp: (({ branchName, parentBranchName, execOptions, logger, }: ExtractGitBranchingTimestampOptions) => Promise<string | undefined>) & {
|
|
72
172
|
getCachedValues(): Promise<string | undefined>[];
|
|
73
173
|
setCachedValue(key: any, value: Promise<string | undefined>): void;
|
|
@@ -75,16 +175,56 @@ export declare const extractBranchingTimestamp: (({ branchName, parentBranchName
|
|
|
75
175
|
TTL?: number | undefined;
|
|
76
176
|
};
|
|
77
177
|
export declare function isISODate(str: string): boolean;
|
|
178
|
+
type BranchAncestryOptions = {
|
|
179
|
+
gitBranchName: string;
|
|
180
|
+
defaultBranch: string;
|
|
181
|
+
execOptions?: ExecOptions;
|
|
182
|
+
logger?: Logger;
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Enumerate ancestor branches in the window MERGE_BASE..gitBranchName by
|
|
186
|
+
* walking the commits in that window and asking which branches contain each.
|
|
187
|
+
*
|
|
188
|
+
* Mirrors the reference shell algorithm in
|
|
189
|
+
* `.team-lead/scripts-byCommits.sh`. Returns a sorted, deduplicated list
|
|
190
|
+
* of branch names (no `refs/` prefix). Never throws — returns `[]` on git
|
|
191
|
+
* failure. Always includes `defaultBranch` and `gitBranchName`.
|
|
192
|
+
*/
|
|
193
|
+
export declare function getBranchAncestryByCommits({ gitBranchName, defaultBranch, execOptions, logger, }: BranchAncestryOptions): Promise<string[]>;
|
|
194
|
+
/**
|
|
195
|
+
* Enumerate ancestor branches by iterating every branch ref and applying
|
|
196
|
+
* Rule 1 (the candidate's merge-base with HEAD must not lie before the
|
|
197
|
+
* primary MERGE_BASE) and Rule 2 (HEAD must not be an ancestor of the
|
|
198
|
+
* candidate).
|
|
199
|
+
*
|
|
200
|
+
* Mirrors the reference shell algorithm in
|
|
201
|
+
* `.team-lead/scripts-byLocalBranches.sh`, with one deliberate extension:
|
|
202
|
+
* the shell script reads `refs/heads/` only, but in CI we typically have
|
|
203
|
+
* exactly one local branch checked out and dozens of remote refs. To make
|
|
204
|
+
* this method useful in CI we ALSO walk `refs/remotes/<remote>/` and strip
|
|
205
|
+
* the remote prefix. The function name is preserved for fidelity to the
|
|
206
|
+
* reference algorithm.
|
|
207
|
+
*
|
|
208
|
+
* Returns a sorted, deduplicated list of branch names. Never throws —
|
|
209
|
+
* returns `[]` on git failure. Always includes `defaultBranch` and
|
|
210
|
+
* `gitBranchName`.
|
|
211
|
+
*/
|
|
212
|
+
export declare function getBranchAncestryByLocalBranches({ gitBranchName, defaultBranch, execOptions, logger, }: BranchAncestryOptions): Promise<string[]>;
|
|
78
213
|
/**
|
|
79
214
|
* Extracts a list of ancestor branches for the given branch, ordered by most recent commit timestamp.
|
|
80
215
|
*
|
|
81
216
|
* Algorithm:
|
|
82
|
-
* 1. Check if shallow clone and should skip (via APPLITOOLS_SKIP_BRANCH_LOOKUP_IN_SHALLOW_CLONE)
|
|
83
|
-
* 2. Ensure remote branches are available (fetch if needed for single-branch/shallow clones)
|
|
84
|
-
* 3.
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
217
|
+
* 1. Check if shallow clone and should skip (via APPLITOOLS_SKIP_BRANCH_LOOKUP_IN_SHALLOW_CLONE).
|
|
218
|
+
* 2. Ensure remote branches are available (fetch if needed for single-branch/shallow clones).
|
|
219
|
+
* 3. Detect the repo's actual default branch via `extractDefaultBranch()` (handles non-standard
|
|
220
|
+
* defaults like JFrog's `JFROG/.../...-rc`).
|
|
221
|
+
* 4. Discover ancestor branches using the strategy selected by
|
|
222
|
+
* `APPLITOOLS_BRANCH_ANCESTRY_STRATEGY` (`commits` (default) or `local`):
|
|
223
|
+
* - `getBranchAncestryByCommits` walks the MERGE_BASE..HEAD commit window;
|
|
224
|
+
* - `getBranchAncestryByLocalBranches` iterates `refs/heads/` + `refs/remotes/<remote>/`.
|
|
225
|
+
* 5. For each discovered branch, extract the branching timestamp.
|
|
226
|
+
* 6. Sort results by timestamp descending (most recent first), tie-break by branch name.
|
|
227
|
+
* 7. Root-branch safety net: if nothing survived, fall back to the detected default branch.
|
|
88
228
|
*
|
|
89
229
|
* @param gitBranchName - The branch to analyze
|
|
90
230
|
* @param execOptions - Git execution options (e.g., cwd)
|