Skip to content

Commit 6b95bc9

Browse files
authored
Merge pull request #887 from ktaletsk/commit-and-push
Allow `commit & push`
2 parents df81263 + 4444de0 commit 6b95bc9

File tree

6 files changed

+176
-40
lines changed

6 files changed

+176
-40
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Once installed, extension behavior can be modified via the following settings wh
6666

6767
- **blockWhileCommandExecutes**: suspend JupyterLab user interaction until Git commands (e.g., `commit`, `pull`, `reset`, `revert`) finish executing. Setting this to `true` helps mitigate potential race conditions leading to data loss, conflicts, and a broken Git history. Unless running a slow network, UI suspension should not interfere with standard workflows. Setting this to `false` allows for actions to trigger multiple concurrent Git actions.
6868
- **cancelPullMergeConflict**: cancel pulling changes from a remote repository if there exists a merge conflict. If set to `true`, when fetching and integrating changes from a remote repository, a conflicting merge is canceled and the working tree left untouched.
69+
- **commitAndPush**: Whether to trigger or not a push for each commit; default is `true`.
6970
- **disableBranchWithChanges**: disable all branch operations, such as creating a new branch or switching to a different branch, when there are changed/staged files. When set to `true`, this setting guards against overwriting and/or losing uncommitted changes.
7071
- **displayStatus**: display Git extension status updates in the JupyterLab status bar. If `true`, the extension displays status updates in the JupyterLab status bar, such as when pulling and pushing changes, switching branches, and polling for changes. Depending on the level of extension activity, some users may find the status updates distracting. In which case, setting this to `false` should reduce visual noise.
7172
- **doubleClickDiff**: double click a file in the Git extension panel to open a diff of the file instead of opening the file for editing.

schema/plugin.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@
5858
"title": "Simple staging flag",
5959
"description": "If true, use a simplified concept of staging. Only files with changes are shown (instead of showing staged/changed/untracked), and all files with changes will be automatically staged",
6060
"default": false
61+
},
62+
"commitAndPush": {
63+
"type": "boolean",
64+
"title": "Trigger push on commit",
65+
"description": "Whether to trigger or not a push for each commit.",
66+
"default": true
6167
}
6268
},
6369
"jupyter.lab.shortcuts": [

src/components/CommitBox.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import { TranslationBundle } from '@jupyterlab/translation';
2+
import { CommandRegistry } from '@lumino/commands';
13
import * as React from 'react';
24
import TextareaAutosize from 'react-textarea-autosize';
35
import {
4-
commitFormClass,
5-
commitSummaryClass,
6+
commitButtonClass,
67
commitDescriptionClass,
7-
commitButtonClass
8+
commitFormClass,
9+
commitSummaryClass
810
} from '../style/CommitBox';
9-
import { TranslationBundle } from '@jupyterlab/translation';
10-
import { CommandRegistry } from '@lumino/commands';
1111
import { CommandIDs } from '../tokens';
1212

1313
/**
@@ -23,10 +23,17 @@ export interface ICommitBoxProps {
2323
* Boolean indicating whether files currently exist which have changes to commit.
2424
*/
2525
hasFiles: boolean;
26+
27+
/**
28+
* Commit button label
29+
*/
30+
label: string;
31+
2632
/**
2733
* The application language translator.
2834
*/
2935
trans: TranslationBundle;
36+
3037
/**
3138
* Callback to invoke in order to commit changes.
3239
*
@@ -91,7 +98,7 @@ export class CommitBox extends React.Component<
9198
? this.props.trans.__('Disabled: No files are staged for commit')
9299
: !this.state.summary
93100
? this.props.trans.__('Disabled: No commit message summary')
94-
: this.props.trans.__('Commit');
101+
: this.props.label;
95102

96103
const shortcutHint = CommandRegistry.formatKeystroke(
97104
this._getSubmitKeystroke()
@@ -125,7 +132,7 @@ export class CommitBox extends React.Component<
125132
className={commitButtonClass}
126133
type="button"
127134
title={title}
128-
value={this.props.trans.__('Commit')}
135+
value={this.props.label}
129136
disabled={disabled}
130137
onClick={this._onCommitSubmit}
131138
/>

src/components/GitPanel.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { showDialog } from '@jupyterlab/apputils';
22
import { PathExt } from '@jupyterlab/coreutils';
33
import { FileBrowserModel } from '@jupyterlab/filebrowser';
44
import { ISettingRegistry } from '@jupyterlab/settingregistry';
5+
import { TranslationBundle } from '@jupyterlab/translation';
56
import { CommandRegistry } from '@lumino/commands';
67
import { JSONObject } from '@lumino/coreutils';
78
import { Signal } from '@lumino/signaling';
89
import Tab from '@material-ui/core/Tab';
910
import Tabs from '@material-ui/core/Tabs';
10-
import { TranslationBundle } from '@jupyterlab/translation';
1111
import * as React from 'react';
1212
import { Logger } from '../logger';
1313
import { GitExtension } from '../model';
@@ -260,6 +260,13 @@ export class GitPanel extends React.Component<IGitPanelProps, IGitPanelState> {
260260
console.error(error);
261261
this.props.logger.log({ ...errorLog, error });
262262
}
263+
const hasRemote = this.props.model.branches.some(
264+
branch => branch.is_remote_branch
265+
);
266+
// If enabled commit and push, push here
267+
if (this.props.settings.composite['commitAndPush'] && hasRemote) {
268+
await this.props.commands.execute(CommandIDs.gitPush);
269+
}
263270
};
264271

265272
/**
@@ -367,6 +374,14 @@ export class GitPanel extends React.Component<IGitPanelProps, IGitPanelState> {
367374
* @returns React element
368375
*/
369376
private _renderChanges(): React.ReactElement {
377+
const hasRemote = this.props.model.branches.some(
378+
branch => branch.is_remote_branch
379+
);
380+
const commitAndPush =
381+
(this.props.settings.composite['commitAndPush'] as boolean) && hasRemote;
382+
const buttonLabel = commitAndPush
383+
? this.props.trans.__('Commit and Push')
384+
: this.props.trans.__('Commit');
370385
return (
371386
<React.Fragment>
372387
<FileList
@@ -378,17 +393,19 @@ export class GitPanel extends React.Component<IGitPanelProps, IGitPanelState> {
378393
/>
379394
{this.props.settings.composite['simpleStaging'] ? (
380395
<CommitBox
396+
commands={this.props.commands}
381397
hasFiles={this._markedFiles.length > 0}
382398
trans={this.props.trans}
399+
label={buttonLabel}
383400
onCommit={this.commitMarkedFiles}
384-
commands={this.props.commands}
385401
/>
386402
) : (
387403
<CommitBox
404+
commands={this.props.commands}
388405
hasFiles={this._hasStagedFile()}
389406
trans={this.props.trans}
407+
label={buttonLabel}
390408
onCommit={this.commitStagedFiles}
391-
commands={this.props.commands}
392409
/>
393410
)}
394411
</React.Fragment>

tests/test-components/CommitBox.spec.tsx

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import * as React from 'react';
2-
import 'jest';
3-
import { shallow } from 'enzyme';
4-
import { CommitBox} from '../../src/components/CommitBox';
5-
import { CommandRegistry } from '@lumino/commands';
61
import { nullTranslator } from '@jupyterlab/translation';
2+
import { CommandRegistry } from '@lumino/commands';
3+
import { shallow } from 'enzyme';
4+
import 'jest';
5+
import * as React from 'react';
6+
import { CommitBox } from '../../src/components/CommitBox';
77
import { CommandIDs } from '../../src/tokens';
88

99
describe('CommitBox', () => {
10-
11-
const defaultCommands = new CommandRegistry()
10+
const defaultCommands = new CommandRegistry();
1211
defaultCommands.addKeyBinding({
1312
keys: ['Accel Enter'],
1413
command: CommandIDs.gitSubmitCommand,
1514
selector: '.jp-git-CommitBox'
16-
})
15+
});
1716

1817
const trans = nullTranslator.load('jupyterlab-git');
1918

@@ -23,7 +22,8 @@ describe('CommitBox', () => {
2322
onCommit: async () => {},
2423
hasFiles: false,
2524
commands: defaultCommands,
26-
trans: trans
25+
trans: trans,
26+
label: 'Commit'
2727
});
2828
expect(box).toBeInstanceOf(CommitBox);
2929
});
@@ -33,7 +33,8 @@ describe('CommitBox', () => {
3333
onCommit: async () => {},
3434
hasFiles: false,
3535
commands: defaultCommands,
36-
trans: trans
36+
trans: trans,
37+
label: 'Commit'
3738
});
3839
expect(box.state.summary).toEqual('');
3940
});
@@ -43,7 +44,8 @@ describe('CommitBox', () => {
4344
onCommit: async () => {},
4445
hasFiles: false,
4546
commands: defaultCommands,
46-
trans: trans
47+
trans: trans,
48+
label: 'Commit'
4749
});
4850
expect(box.state.description).toEqual('');
4951
});
@@ -55,37 +57,44 @@ describe('CommitBox', () => {
5557
onCommit: async () => {},
5658
hasFiles: false,
5759
commands: defaultCommands,
58-
trans: trans
60+
trans: trans,
61+
label: 'Commit'
5962
};
6063
const component = shallow(<CommitBox {...props} />);
6164
const node = component.find('input[type="text"]').first();
62-
expect(node.prop('placeholder')).toEqual('Summary (Ctrl+Enter to commit)');
65+
expect(node.prop('placeholder')).toEqual(
66+
'Summary (Ctrl+Enter to commit)'
67+
);
6368
});
6469

6570
it('should adjust placeholder text for the commit message summary when keybinding changes', () => {
66-
const adjustedCommands = new CommandRegistry()
71+
const adjustedCommands = new CommandRegistry();
6772
adjustedCommands.addKeyBinding({
6873
keys: ['Shift Enter'],
6974
command: CommandIDs.gitSubmitCommand,
7075
selector: '.jp-git-CommitBox'
71-
})
76+
});
7277
const props = {
7378
onCommit: async () => {},
7479
hasFiles: false,
7580
commands: adjustedCommands,
76-
trans: trans
81+
trans: trans,
82+
label: 'Commit'
7783
};
7884
const component = shallow(<CommitBox {...props} />);
7985
const node = component.find('input[type="text"]').first();
80-
expect(node.prop('placeholder')).toEqual('Summary (Shift+Enter to commit)');
86+
expect(node.prop('placeholder')).toEqual(
87+
'Summary (Shift+Enter to commit)'
88+
);
8189
});
8290

8391
it('should set a `title` attribute on the input element to provide a commit message summary', () => {
8492
const props = {
8593
onCommit: async () => {},
8694
hasFiles: false,
8795
commands: defaultCommands,
88-
trans: trans
96+
trans: trans,
97+
label: 'Commit'
8998
};
9099
const component = shallow(<CommitBox {...props} />);
91100
const node = component.find('input[type="text"]').first();
@@ -97,7 +106,8 @@ describe('CommitBox', () => {
97106
onCommit: async () => {},
98107
hasFiles: false,
99108
commands: defaultCommands,
100-
trans: trans
109+
trans: trans,
110+
label: 'Commit'
101111
};
102112
const component = shallow(<CommitBox {...props} />);
103113
const node = component.find('TextareaAutosize').first();
@@ -109,7 +119,8 @@ describe('CommitBox', () => {
109119
onCommit: async () => {},
110120
hasFiles: false,
111121
commands: defaultCommands,
112-
trans: trans
122+
trans: trans,
123+
label: 'Commit'
113124
};
114125
const component = shallow(<CommitBox {...props} />);
115126
const node = component.find('TextareaAutosize').first();
@@ -121,7 +132,8 @@ describe('CommitBox', () => {
121132
onCommit: async () => {},
122133
hasFiles: false,
123134
commands: defaultCommands,
124-
trans: trans
135+
trans: trans,
136+
label: 'Commit'
125137
};
126138
const component = shallow(<CommitBox {...props} />);
127139
const node = component.find('input[type="button"]').first();
@@ -133,7 +145,8 @@ describe('CommitBox', () => {
133145
onCommit: async () => {},
134146
hasFiles: false,
135147
commands: defaultCommands,
136-
trans: trans
148+
trans: trans,
149+
label: 'Commit'
137150
};
138151
const component = shallow(<CommitBox {...props} />);
139152
const node = component.find('input[type="button"]').first();
@@ -145,7 +158,8 @@ describe('CommitBox', () => {
145158
onCommit: async () => {},
146159
hasFiles: false,
147160
commands: defaultCommands,
148-
trans: trans
161+
trans: trans,
162+
label: 'Commit'
149163
};
150164
const component = shallow(<CommitBox {...props} />);
151165
const node = component.find('input[type="button"]').first();
@@ -158,7 +172,8 @@ describe('CommitBox', () => {
158172
onCommit: async () => {},
159173
hasFiles: true,
160174
commands: defaultCommands,
161-
trans: trans
175+
trans: trans,
176+
label: 'Commit'
162177
};
163178
const component = shallow(<CommitBox {...props} />);
164179
const node = component.find('input[type="button"]').first();
@@ -171,7 +186,8 @@ describe('CommitBox', () => {
171186
onCommit: async () => {},
172187
hasFiles: true,
173188
commands: defaultCommands,
174-
trans: trans
189+
trans: trans,
190+
label: 'Commit'
175191
};
176192
const component = shallow(<CommitBox {...props} />);
177193
component.setState({

0 commit comments

Comments
 (0)