addons/isl/src/operations/ShelveOperation.tsblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {PartialSelection} from '../partialSelection';
b69ab319import type {
b69ab3110 ApplyUncommittedChangesPreviewsFuncType,
b69ab3111 UncommittedChangesPreviewContext,
b69ab3112} from '../previews';
b69ab3113import type {CommandArg, RepoRelativePath, UncommittedChanges} from '../types';
b69ab3114
b69ab3115import {Operation} from './Operation';
b69ab3116
b69ab3117export class ShelveOperation extends Operation {
b69ab3118 /**
b69ab3119 * @param name the name of the shelved changes. This makes it easier to find the change later.
b69ab3120 * @param filesPathsToCommit if provided, only these file paths will be included in the shelve operation. If undefined, ALL uncommitted changes are included. Paths should be relative to repo root.
b69ab3121 */
b69ab3122 constructor(
b69ab3123 private name?: string,
b69ab3124 private filesPathsToCommit?: Array<RepoRelativePath>,
b69ab3125 ) {
b69ab3126 super('ShelveOperation');
b69ab3127 }
b69ab3128
b69ab3129 static opName = 'Shelve';
b69ab3130
b69ab3131 getArgs() {
b69ab3132 const args: Array<CommandArg> = ['shelve', '--unknown'];
b69ab3133 if (this.name) {
b69ab3134 args.push('--name', this.name);
b69ab3135 }
b69ab3136 if (this.filesPathsToCommit) {
b69ab3137 args.push(
b69ab3138 ...this.filesPathsToCommit.map(file =>
b69ab3139 // tag file arguments specially so the remote repo can convert them to the proper cwd-relative format.
b69ab3140 ({
b69ab3141 type: 'repo-relative-file' as const,
b69ab3142 path: file,
b69ab3143 }),
b69ab3144 ),
b69ab3145 );
b69ab3146 }
b69ab3147 return args;
b69ab3148 }
b69ab3149
b69ab3150 makeOptimisticUncommittedChangesApplier?(
b69ab3151 context: UncommittedChangesPreviewContext,
b69ab3152 ): ApplyUncommittedChangesPreviewsFuncType | undefined {
b69ab3153 const filesToCommit = new Set(this.filesPathsToCommit);
b69ab3154 // optimistic state is over when there's no uncommitted changes that we wanted to shelve left
b69ab3155 if (
b69ab3156 context.uncommittedChanges.length === 0 ||
b69ab3157 (filesToCommit.size > 0 &&
b69ab3158 context.uncommittedChanges.every(change => !filesToCommit.has(change.path)))
b69ab3159 ) {
b69ab3160 return undefined;
b69ab3161 }
b69ab3162
b69ab3163 const func: ApplyUncommittedChangesPreviewsFuncType = (changes: UncommittedChanges) => {
b69ab3164 if (this.filesPathsToCommit != null) {
b69ab3165 return changes.filter(change => !filesToCommit.has(change.path));
b69ab3166 } else {
b69ab3167 return [];
b69ab3168 }
b69ab3169 };
b69ab3170 return func;
b69ab3171 }
b69ab3172}
b69ab3173
b69ab3174/** Find appropriate ShelveOperation based on selection. */
b69ab3175export function getShelveOperation(
b69ab3176 name: string | undefined,
b69ab3177 selection: PartialSelection,
b69ab3178 allFiles: Array<RepoRelativePath>,
b69ab3179): ShelveOperation {
b69ab3180 if (selection.hasChunkSelection()) {
b69ab3181 throw new Error('Cannot shelve partially selected hunks.');
b69ab3182 } else if (selection.isEverythingSelected(() => allFiles)) {
b69ab3183 return new ShelveOperation(name);
b69ab3184 } else {
b69ab3185 const selectedFiles = allFiles.filter(path => selection.isFullyOrPartiallySelected(path));
b69ab3186 return new ShelveOperation(name, selectedFiles);
b69ab3187 }
b69ab3188}