Browse Source

Blocks worktree access (if needed) from repos view

Ensures supports works for worktrees and stashes
Fixes create worktree from repositories view
main
Eric Amodio 3 years ago
parent
commit
ebf5d045ac
7 changed files with 50 additions and 26 deletions
  1. +9
    -3
      src/env/node/git/localGitProvider.ts
  2. +1
    -0
      src/git/gitProvider.ts
  3. +12
    -1
      src/git/models/repository.ts
  4. +4
    -16
      src/premium/github/githubGitProvider.ts
  5. +3
    -2
      src/views/nodes/repositoryNode.ts
  6. +15
    -2
      src/views/nodes/worktreesNode.ts
  7. +6
    -2
      src/views/viewCommands.ts

+ 9
- 3
src/env/node/git/localGitProvider.ts View File

@ -426,12 +426,18 @@ export class LocalGitProvider implements GitProvider, Disposable {
}
private _supportedFeatures = new Map<Features, boolean>();
// eslint-disable-next-line @typescript-eslint/require-await
async supports(feature: Features): Promise<boolean> {
const supported = this._supportedFeatures.get(feature);
let supported = this._supportedFeatures.get(feature);
if (supported != null) return supported;
return false;
switch (feature) {
case Features.Worktrees:
supported = await this.git.isAtLeastVersion('2.17.0');
this._supportedFeatures.set(feature, supported);
return supported;
default:
return true;
}
}
async visibility(repoPath: string): Promise<RepositoryVisibility> {

+ 1
- 0
src/git/gitProvider.ts View File

@ -91,6 +91,7 @@ export interface RepositoryOpenEvent {
}
export const enum Features {
Stashes = 'stashes',
Worktrees = 'worktrees',
}

+ 12
- 1
src/git/models/repository.ts View File

@ -27,7 +27,8 @@ import { debounce } from '../../system/function';
import { filter, join, some } from '../../system/iterable';
import { basename, normalizePath } from '../../system/path';
import { runGitCommandInTerminal } from '../../terminal';
import { GitProviderDescriptor } from '../gitProvider';
import { Features, GitProviderDescriptor, PremiumFeatures } from '../gitProvider';
import { FeatureAccess } from '../gitProviderService';
import { RemoteProviderFactory, RemoteProviders } from '../remotes/factory';
import { RichRemoteProvider } from '../remotes/provider';
import { SearchPattern } from '../search';
@ -394,6 +395,16 @@ export class Repository implements Disposable {
}
@log()
access(feature?: PremiumFeatures): Promise<FeatureAccess> {
return this.container.git.access(feature, this.uri);
}
@log()
supports(feature: Features): Promise<boolean> {
return this.container.git.supports(this.uri, feature);
}
@log()
branch(...args: string[]) {
this.runTerminalCommand('branch', ...args);
}

+ 4
- 16
src/premium/github/githubGitProvider.ts View File

@ -212,10 +212,10 @@ export class GitHubGitProvider implements GitProvider, Disposable {
return allowed;
}
private _supportedFeatures = new Map<Features, boolean>();
async supports(feature: Features): Promise<boolean> {
const supported = this._supportedFeatures.get(feature);
if (supported != null) return supported;
// private _supportedFeatures = new Map<Features, boolean>();
async supports(_feature: Features): Promise<boolean> {
// const supported = this._supportedFeatures.get(feature);
// if (supported != null) return supported;
return false;
}
@ -229,18 +229,6 @@ export class GitHubGitProvider implements GitProvider, Disposable {
return this.getRemoteVisibility(origin);
}
const upstream = remotes.find(r => r.name === 'upstream');
if (upstream != null) {
return this.getRemoteVisibility(upstream);
}
const results = await Promise.allSettled(remotes.map(r => this.getRemoteVisibility(r)));
for (const result of results) {
if (result.status !== 'fulfilled') continue;
if (result.value === RepositoryVisibility.Public) return RepositoryVisibility.Public;
}
return RepositoryVisibility.Private;
}

+ 3
- 2
src/views/nodes/repositoryNode.ts View File

@ -1,5 +1,6 @@
import { Disposable, MarkdownString, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GlyphChars } from '../../constants';
import { Features } from '../../git/gitProvider';
import { GitUri } from '../../git/gitUri';
import {
GitBranch,
@ -152,7 +153,7 @@ export class RepositoryNode extends SubscribeableViewNode {
children.push(new RemotesNode(this.uri, this.view, this, this.repo));
}
if (this.view.config.showStashes) {
if (this.view.config.showStashes && (await this.repo.supports(Features.Stashes))) {
children.push(new StashesNode(this.uri, this.view, this, this.repo));
}
@ -160,7 +161,7 @@ export class RepositoryNode extends SubscribeableViewNode {
children.push(new TagsNode(this.uri, this.view, this, this.repo));
}
if (this.view.config.showWorktrees) {
if (this.view.config.showWorktrees && (await this.repo.supports(Features.Worktrees))) {
children.push(new WorktreesNode(this.uri, this.view, this, this.repo));
}

+ 15
- 2
src/views/nodes/worktreesNode.ts View File

@ -1,4 +1,6 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GlyphChars } from '../../constants';
import { PremiumFeatures } from '../../git/gitProvider';
import { GitUri } from '../../git/gitUri';
import { Repository } from '../../git/models';
import { gate } from '../../system/decorators/gate';
@ -37,6 +39,9 @@ export class WorktreesNode extends ViewNode {
async getChildren(): Promise<ViewNode[]> {
if (this._children == null) {
const access = await this.repo.access(PremiumFeatures.Worktrees);
if (!access.allowed) return [];
const worktrees = await this.repo.getWorktrees();
if (worktrees.length === 0) return [new MessageNode(this.view, this, 'No worktrees could be found.')];
@ -46,10 +51,18 @@ export class WorktreesNode extends ViewNode {
return this._children;
}
getTreeItem(): TreeItem {
const item = new TreeItem('Worktrees', TreeItemCollapsibleState.Collapsed);
async getTreeItem(): Promise<TreeItem> {
const access = await this.repo.access(PremiumFeatures.Worktrees);
const item = new TreeItem(
'Worktrees',
access.allowed ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None,
);
item.id = this.id;
item.contextValue = ContextValues.Worktrees;
item.description = access.allowed
? undefined
: ` ${GlyphChars.Warning} Premium feature which requires an account`;
// TODO@eamodio `folder` icon won't work here for some reason
item.iconPath = new ThemeIcon('folder-opened');
return item;

+ 6
- 2
src/views/viewCommands.ts View File

@ -58,6 +58,7 @@ import {
ViewRefFileNode,
ViewRefNode,
WorktreeNode,
WorktreesNode,
} from './nodes';
interface CompareSelectedInfo {
@ -316,8 +317,11 @@ export class ViewCommands {
}
@debug()
private async createWorktree(node?: BranchNode) {
if (node !== undefined && !(node instanceof BranchNode)) return undefined;
private async createWorktree(node?: BranchNode | WorktreesNode) {
if (node instanceof WorktreesNode) {
node = undefined;
}
if (node != null && !(node instanceof BranchNode)) return undefined;
return GitActions.Worktree.create(node?.repoPath, undefined, node?.ref);
}

Loading…
Cancel
Save