Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions LICENSE.plus
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
GitLens+ License
GitLens Pro License

Copyright (c) 2021-2025 Axosoft, LLC dba GitKraken ("GitKraken")

Expand All @@ -13,8 +13,8 @@ with, the GitKraken End User License Agreement, available at
https://gitkraken.com/eula (the "EULA"), or other agreement governing the
use of the Software, as agreed by you and GitKraken, and otherwise have a valid
subscription for the correct number of user seats for the applicable version of
the Software (e.g., GitLens+, GitLens+ Pro, GitLens+ Advanced, GitLens+ Teams,
and GitLens+ Enterprise). Subject to the foregoing sentence, you are free to modify
the Software (e.g., GitLens Pro, GitLens Advanced, GitLens Business,
and GitLens Enterprise). Subject to the foregoing sentence, you are free to modify
this Software and publish patches to the Software. You agree that GitKraken and/or
its licensors (as applicable) retain all right, title and interest in and to all
such modifications and/or patches, and all such modifications and/or patches may
Expand All @@ -25,7 +25,7 @@ modifications and/or patches. You are not granted any other rights beyond what
is expressly stated herein. Except as set forth above, it is forbidden to copy,
merge, publish, distribute, sublicense, and/or sell the Software.

The full text of this GitLens+ License shall be included in all copies or
The full text of this GitLens Pro License shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Expand Down
2 changes: 1 addition & 1 deletion docs/telemetry-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -1484,7 +1484,7 @@ void
'repoPrivacy': 'private' | 'public' | 'local',
'repository.visibility': 'private' | 'public' | 'local',
// Provided for compatibility with other GK surfaces
'source': 'account' | 'subscription' | 'graph' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'view' | 'code-suggest' | 'ai' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'commandPalette' | 'deeplink' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'startWork' | 'trial-indicator' | 'scm-input' | 'walkthrough' | 'whatsnew' | 'worktrees'
'source': 'account' | 'subscription' | 'graph' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'view' | 'code-suggest' | 'ai' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'commandPalette' | 'deeplink' | 'feature-badge' | 'feature-gate' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'startWork' | 'trial-indicator' | 'scm-input' | 'walkthrough' | 'whatsnew' | 'worktrees'
}
```

Expand Down
3 changes: 2 additions & 1 deletion src/commands/quickWizard.base.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Disposable, InputBox, QuickInputButton, QuickPick, QuickPickItem } from 'vscode';
import { InputBoxValidationSeverity, QuickInputButtons, window } from 'vscode';
import type { GlCommands } from '../constants.commands';
import { SubscriptionPlanId } from '../constants.subscription';
import { Container } from '../container';
import { Directive, isDirective, isDirectiveQuickPickItem } from '../quickpicks/items/directive';
import { configuration } from '../system/-webview/configuration';
Expand Down Expand Up @@ -746,7 +747,7 @@ export abstract class QuickWizardCommandBase extends GlCommandBase {
}

case Directive.RequiresPaidSubscription:
void Container.instance.subscription.upgrade({
void Container.instance.subscription.upgrade(SubscriptionPlanId.Pro, {
source: 'quick-wizard',
detail: {
action: rootStep.command?.key,
Expand Down
3 changes: 2 additions & 1 deletion src/commands/walkthroughs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { urls } from '../constants';
import type { GlCommands } from '../constants.commands';
import type { Source, Sources } from '../constants.telemetry';
import type { Container } from '../container';
import type { SubscriptionUpgradeCommandArgs } from '../plus/gk/models/subscription';
import type { LaunchpadCommandArgs } from '../plus/launchpad/launchpad';
import { command, executeCommand } from '../system/-webview/command';
import { openUrl, openWalkthrough as openWalkthroughCore } from '../system/-webview/vscode';
Expand Down Expand Up @@ -80,7 +81,7 @@ export class WalkthroughPlusUpgradeCommand extends GlCommandBase {
name: 'plus/upgrade',
command: command,
});
executeCommand<Source>(command, { source: 'walkthrough' });
executeCommand<SubscriptionUpgradeCommandArgs>(command, { source: 'walkthrough' });
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/constants.telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,8 @@ export type Sources =
| 'cloud-patches'
| 'commandPalette'
| 'deeplink'
| 'feature-badge'
| 'feature-gate'
| 'graph'
| 'home'
| 'inspect'
Expand Down
8 changes: 4 additions & 4 deletions src/plus/LICENSE.plus
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
GitLens+ License
GitLens Pro License

Copyright (c) 2021-2025 Axosoft, LLC dba GitKraken ("GitKraken")

Expand All @@ -13,8 +13,8 @@ with, the GitKraken End User License Agreement, available at
https://gitkraken.com/eula (the "EULA"), or other agreement governing the
use of the Software, as agreed by you and GitKraken, and otherwise have a valid
subscription for the correct number of user seats for the applicable version of
the Software (e.g., GitLens+, GitLens+ Pro, GitLens+ Advanced, GitLens+ Teams,
and GitLens+ Enterprise). Subject to the foregoing sentence, you are free to modify
the Software (e.g., GitLens Pro, GitLens Advanced, GitLens Business,
and GitLens Enterprise). Subject to the foregoing sentence, you are free to modify
this Software and publish patches to the Software. You agree that GitKraken and/or
its licensors (as applicable) retain all right, title and interest in and to all
such modifications and/or patches, and all such modifications and/or patches may
Expand All @@ -25,7 +25,7 @@ modifications and/or patches. You are not granted any other rights beyond what
is expressly stated herein. Except as set forth above, it is forbidden to copy,
merge, publish, distribute, sublicense, and/or sell the Software.

The full text of this GitLens+ License shall be included in all copies or
The full text of this GitLens Pro License shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Expand Down
16 changes: 8 additions & 8 deletions src/plus/gk/__debug__accountDebug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ class AccountDebug {
createQuickPickSeparator('Trial'),
{
label: 'Pro Trial',
description: 'Pro, account',
description: 'Pro trial (pro plan), account',
iconPath: new ThemeIcon('blank'),
item: { state: SubscriptionState.ProTrial },
},
{
label: 'Pro Trial (Reactivated)',
description: 'Pro, account',
description: 'Pro trial (pro plan), account',
iconPath: new ThemeIcon('blank'),
item: {
state: SubscriptionState.ProTrial,
Expand All @@ -155,13 +155,13 @@ class AccountDebug {
},
{
label: 'Pro Trial (Advanced)',
description: 'Advanced, account',
description: 'Pro trial (advanced plan), account',
iconPath: new ThemeIcon('blank'),
item: { state: SubscriptionState.ProTrial, planId: SubscriptionPlanId.Advanced },
},
{
label: 'Pro Trial (Advanced Reactivated)',
description: 'Advanced, account',
label: 'Pro Trial (Advanced, Reactivated)',
description: 'Pro trial (advanced plan), account',
iconPath: new ThemeIcon('blank'),
item: {
state: SubscriptionState.ProTrial,
Expand Down Expand Up @@ -190,19 +190,19 @@ class AccountDebug {
},
{
label: 'Advanced',
description: 'Advanced, account',
description: 'Advanced plan, account',
iconPath: new ThemeIcon('blank'),
item: { state: SubscriptionState.Paid, planId: SubscriptionPlanId.Advanced },
},
{
label: 'Teams',
description: 'Teams, account',
description: 'Teams plan, account',
iconPath: new ThemeIcon('blank'),
item: { state: SubscriptionState.Paid, planId: SubscriptionPlanId.Teams },
},
{
label: 'Enterprise',
description: 'Enterprise, no account',
description: 'Enterprise plan, account',
iconPath: new ThemeIcon('blank'),
item: { state: SubscriptionState.Paid, planId: SubscriptionPlanId.Enterprise },
},
Expand Down
5 changes: 5 additions & 0 deletions src/plus/gk/models/subscription.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { SubscriptionPlanId, SubscriptionState } from '../../../constants.subscription';
import type { Source } from '../../../constants.telemetry';
import type { Organization } from './organization';

export type FreeSubscriptionPlans = Extract<
Expand Down Expand Up @@ -50,3 +51,7 @@ export interface SubscriptionPreviewTrial {
readonly startedOn: string;
readonly expiresOn: string;
}

export interface SubscriptionUpgradeCommandArgs extends Source {
plan?: SubscriptionPlanId;
}
41 changes: 14 additions & 27 deletions src/plus/gk/subscriptionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,20 @@ import { authenticationProviderScopes } from './authenticationProvider';
import type { GKCheckInResponse } from './models/checkin';
import type { Organization } from './models/organization';
import type { Promo } from './models/promo';
import type { Subscription } from './models/subscription';
import type { Subscription, SubscriptionUpgradeCommandArgs } from './models/subscription';
import type { ServerConnection } from './serverConnection';
import { ensurePlusFeaturesEnabled } from './utils/-webview/plus.utils';
import { getConfiguredActiveOrganizationId, updateActiveOrganizationId } from './utils/-webview/subscription.utils';
import { getSubscriptionFromCheckIn } from './utils/checkin.utils';
import {
assertSubscriptionState,
compareSubscriptionPlans,
computeSubscriptionState,
getCommunitySubscription,
getPreviewSubscription,
getSubscriptionPlan,
getSubscriptionPlanName,
getSubscriptionPlanPriority,
getSubscriptionPlanTierType,
getSubscriptionStateString,
getSubscriptionTimeRemaining,
getTimeRemaining,
Expand Down Expand Up @@ -357,11 +358,8 @@ export class SubscriptionService implements Disposable {
registerCommand('gitlens.plus.startPreviewTrial', (src?: Source) => this.startPreviewTrial(src)),
registerCommand('gitlens.plus.reactivateProTrial', (src?: Source) => this.reactivateProTrial(src)),
registerCommand('gitlens.plus.resendVerification', (src?: Source) => this.resendVerification(src)),
registerCommand('gitlens.plus.upgrade', (srcAndPlan?: Source & { plan?: SubscriptionPlanId }) =>
this.upgrade(
srcAndPlan ? { source: srcAndPlan.source, detail: srcAndPlan.detail } : undefined,
srcAndPlan?.plan,
),
registerCommand('gitlens.plus.upgrade', (args?: SubscriptionUpgradeCommandArgs) =>
this.upgrade(args?.plan, args ? { source: args.source, detail: args.detail } : undefined),
),

registerCommand('gitlens.plus.hide', (src?: Source) => this.setProFeaturesVisibility(false, src)),
Expand Down Expand Up @@ -548,7 +546,7 @@ export class SubscriptionService implements Disposable {
);

if (result === upgrade) {
void this.upgrade(source);
void this.upgrade(SubscriptionPlanId.Pro, source);
} else if (result === learn) {
void this.learnAboutPro({ source: 'prompt', detail: { action: 'trial-ended' } }, source);
}
Expand Down Expand Up @@ -657,9 +655,10 @@ export class SubscriptionService implements Disposable {
@gate(() => '')
@log()
async reactivateProTrial(source: Source | undefined): Promise<void> {
if (!(await ensurePlusFeaturesEnabled())) return;
const scope = getLogScope();

if (!(await ensurePlusFeaturesEnabled())) return;

if (this.container.telemetry.enabled) {
this.container.telemetry.sendEvent('subscription/action', { action: 'reactivate' }, source);
}
Expand Down Expand Up @@ -892,11 +891,13 @@ export class SubscriptionService implements Disposable {
}

@log()
async upgrade(source: Source | undefined, plan?: SubscriptionPlanId): Promise<boolean> {
async upgrade(plan: SubscriptionPlanId | undefined, source: Source | undefined): Promise<boolean> {
const scope = getLogScope();

if (!(await ensurePlusFeaturesEnabled())) return false;

plan ??= SubscriptionPlanId.Pro;

let aborted = false;
const promo = await this.container.productConfig.getApplicablePromo(this._subscription.state);

Expand All @@ -920,14 +921,13 @@ export class SubscriptionService implements Disposable {

const hasAccount = this._subscription.account != null;
if (hasAccount) {
// Do a pre-check-in to see if we've already upgraded to a paid plan.
// Do a pre-check-in to see if we've already upgraded to a paid plan
try {
const session = await this.ensureSession(false, source);
if (session != null) {
if (
(await this.checkUpdatedSubscription(source)) === SubscriptionState.Paid &&
getSubscriptionPlanPriority(this._subscription.plan.effective.id) >=
getSubscriptionPlanPriority(plan ?? SubscriptionPlanId.Pro)
compareSubscriptionPlans(this._subscription.plan.effective.id, plan) >= 0
) {
return true;
}
Expand All @@ -938,20 +938,7 @@ export class SubscriptionService implements Disposable {
const query = new URLSearchParams();
query.set('source', 'gitlens');
query.set('product', 'gitlens');

let planType = 'PRO';
switch (plan) {
case SubscriptionPlanId.Advanced:
planType = 'ADVANCED';
break;
case SubscriptionPlanId.Teams:
planType = 'TEAMS';
break;
case SubscriptionPlanId.Enterprise:
planType = 'ENTERPRISE';
break;
}
query.set('planType', planType);
query.set('planType', getSubscriptionPlanTierType(plan));

if (promo?.code != null) {
query.set('promoCode', promo.code);
Expand Down
3 changes: 2 additions & 1 deletion src/plus/gk/utils/-webview/acount.utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Uri } from 'vscode';
import { window } from 'vscode';
import { SubscriptionPlanId } from '../../../../constants.subscription';
import type { Source } from '../../../../constants.telemetry';
import type { Container } from '../../../../container';
import type { PlusFeatures } from '../../../../features';
Expand Down Expand Up @@ -142,7 +143,7 @@ export async function ensureFeatureAccess(
);

if (result === upgrade) {
if (await container.subscription.upgrade(source)) {
if (await container.subscription.upgrade(SubscriptionPlanId.Pro, source)) {
continue;
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/plus/gk/utils/-webview/plus.utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { MessageItem } from 'vscode';
import { window } from 'vscode';
import { proTrialLengthInDays } from '../../../../constants.subscription';
import { proTrialLengthInDays, SubscriptionPlanId } from '../../../../constants.subscription';
import type { Source } from '../../../../constants.telemetry';
import type { Container } from '../../../../container';
import { configuration } from '../../../../system/-webview/configuration';
Expand Down Expand Up @@ -28,6 +28,7 @@ export async function ensurePlusFeaturesEnabled(): Promise<boolean> {
await configuration.updateEffective('plusFeatures.enabled', true);
return true;
}

export async function ensurePaidPlan(
container: Container,
title: string,
Expand Down Expand Up @@ -100,7 +101,7 @@ export async function ensurePaidPlan(
);

if (result === upgrade) {
void container.subscription.upgrade(source);
void container.subscription.upgrade(SubscriptionPlanId.Pro, source);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/plus/gk/utils/checkin.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SubscriptionPlanId } from '../../../constants.subscription';
import type { GKCheckInResponse, GKLicense, GKLicenseType } from '../models/checkin';
import type { Organization } from '../models/organization';
import type { Subscription } from '../models/subscription';
import { getSubscriptionPlan, getSubscriptionPlanPriority } from './subscription.utils';
import { compareSubscriptionPlans, getSubscriptionPlan, getSubscriptionPlanPriority } from './subscription.utils';

export function getSubscriptionFromCheckIn(
data: GKCheckInResponse,
Expand Down Expand Up @@ -129,7 +129,7 @@ export function getSubscriptionFromCheckIn(
);
}

if (effective == null || getSubscriptionPlanPriority(actual.id) >= getSubscriptionPlanPriority(effective.id)) {
if (effective == null || compareSubscriptionPlans(actual.id, effective.id) >= 0) {
effective = { ...actual };
}

Expand Down
Loading