Skip to content

Commit ac5cd18

Browse files
authored
Merge pull request #912 from fcollonval/auto-backport-of-pr-887-on-jlab-2
Backport PR #887: Allow `commit & push`
2 parents daa6adc + b2930ce commit ac5cd18

File tree

6 files changed

+169
-37
lines changed

6 files changed

+169
-37
lines changed

README.md

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

4444
- **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.
4545
- **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.
46+
- **commitAndPush**: Whether to trigger or not a push for each commit; default is `true`.
4647
- **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.
4748
- **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.
4849
- **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: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1+
import { CommandRegistry } from '@lumino/commands';
12
import * as React from 'react';
23
import TextareaAutosize from 'react-textarea-autosize';
34
import {
4-
commitFormClass,
5-
commitSummaryClass,
5+
commitButtonClass,
66
commitDescriptionClass,
7-
commitButtonClass
7+
commitFormClass,
8+
commitSummaryClass
89
} from '../style/CommitBox';
9-
import { CommandRegistry } from '@lumino/commands';
1010
import { CommandIDs } from '../tokens';
1111

1212
/**
@@ -23,6 +23,11 @@ export interface ICommitBoxProps {
2323
*/
2424
hasFiles: boolean;
2525

26+
/**
27+
* Commit button label
28+
*/
29+
label: string;
30+
2631
/**
2732
* Callback to invoke in order to commit changes.
2833
*
@@ -87,7 +92,7 @@ export class CommitBox extends React.Component<
8792
? 'Disabled: No files are staged for commit'
8893
: !this.state.summary
8994
? 'Disabled: No commit message summary'
90-
: 'Commit';
95+
: this.props.label;
9196

9297
const shortcutHint = CommandRegistry.formatKeystroke(
9398
this._getSubmitKeystroke()
@@ -116,7 +121,7 @@ export class CommitBox extends React.Component<
116121
className={commitButtonClass}
117122
type="button"
118123
title={title}
119-
value="Commit"
124+
value={this.props.label}
120125
disabled={disabled}
121126
onClick={this._onCommitSubmit}
122127
/>

src/components/GitPanel.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ export class GitPanel extends React.Component<IGitPanelProps, IGitPanelState> {
254254
console.error(error);
255255
this.props.logger.log({ ...errorLog, error });
256256
}
257+
const hasRemote = this.props.model.branches.some(
258+
branch => branch.is_remote_branch
259+
);
260+
// If enabled commit and push, push here
261+
if (this.props.settings.composite['commitAndPush'] && hasRemote) {
262+
await this.props.commands.execute(CommandIDs.gitPush);
263+
}
257264
};
258265

259266
/**
@@ -360,6 +367,12 @@ export class GitPanel extends React.Component<IGitPanelProps, IGitPanelState> {
360367
* @returns React element
361368
*/
362369
private _renderChanges(): React.ReactElement {
370+
const hasRemote = this.props.model.branches.some(
371+
branch => branch.is_remote_branch
372+
);
373+
const commitAndPush =
374+
(this.props.settings.composite['commitAndPush'] as boolean) && hasRemote;
375+
const buttonLabel = commitAndPush ? 'Commit and Push' : 'Commit';
363376
return (
364377
<React.Fragment>
365378
<FileList
@@ -370,15 +383,17 @@ export class GitPanel extends React.Component<IGitPanelProps, IGitPanelState> {
370383
/>
371384
{this.props.settings.composite['simpleStaging'] ? (
372385
<CommitBox
386+
commands={this.props.commands}
373387
hasFiles={this._markedFiles.length > 0}
388+
label={buttonLabel}
374389
onCommit={this.commitMarkedFiles}
375-
commands={this.props.commands}
376390
/>
377391
) : (
378392
<CommitBox
393+
commands={this.props.commands}
379394
hasFiles={this._hasStagedFile()}
395+
label={buttonLabel}
380396
onCommit={this.commitStagedFiles}
381-
commands={this.props.commands}
382397
/>
383398
)}
384399
</React.Fragment>

tests/test-components/CommitBox.spec.tsx

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
import * as React from 'react';
2-
import 'jest';
3-
import { shallow } from 'enzyme';
4-
import { CommitBox} from '../../src/components/CommitBox';
51
import { CommandRegistry } from '@lumino/commands';
2+
import { shallow } from 'enzyme';
3+
import 'jest';
4+
import * as React from 'react';
5+
import { CommitBox } from '../../src/components/CommitBox';
66
import { CommandIDs } from '../../src/tokens';
77

88
describe('CommitBox', () => {
9-
10-
const defaultCommands = new CommandRegistry()
9+
const defaultCommands = new CommandRegistry();
1110
defaultCommands.addKeyBinding({
1211
keys: ['Accel Enter'],
1312
command: CommandIDs.gitSubmitCommand,
1413
selector: '.jp-git-CommitBox'
15-
})
14+
});
1615

1716
describe('#constructor()', () => {
1817
it('should return a new instance', () => {
1918
const box = new CommitBox({
2019
onCommit: async () => {},
2120
hasFiles: false,
22-
commands: defaultCommands
21+
commands: defaultCommands,
22+
label: 'Commit'
2323
});
2424
expect(box).toBeInstanceOf(CommitBox);
2525
});
@@ -28,7 +28,8 @@ describe('CommitBox', () => {
2828
const box = new CommitBox({
2929
onCommit: async () => {},
3030
hasFiles: false,
31-
commands: defaultCommands
31+
commands: defaultCommands,
32+
label: 'Commit'
3233
});
3334
expect(box.state.summary).toEqual('');
3435
});
@@ -37,7 +38,8 @@ describe('CommitBox', () => {
3738
const box = new CommitBox({
3839
onCommit: async () => {},
3940
hasFiles: false,
40-
commands: defaultCommands
41+
commands: defaultCommands,
42+
label: 'Commit'
4143
});
4244
expect(box.state.description).toEqual('');
4345
});
@@ -48,35 +50,42 @@ describe('CommitBox', () => {
4850
const props = {
4951
onCommit: async () => {},
5052
hasFiles: false,
51-
commands: defaultCommands
53+
commands: defaultCommands,
54+
label: 'Commit'
5255
};
5356
const component = shallow(<CommitBox {...props} />);
5457
const node = component.find('input[type="text"]').first();
55-
expect(node.prop('placeholder')).toEqual('Summary (Ctrl+Enter to commit)');
58+
expect(node.prop('placeholder')).toEqual(
59+
'Summary (Ctrl+Enter to commit)'
60+
);
5661
});
5762

5863
it('should adjust placeholder text for the commit message summary when keybinding changes', () => {
59-
const adjustedCommands = new CommandRegistry()
64+
const adjustedCommands = new CommandRegistry();
6065
adjustedCommands.addKeyBinding({
6166
keys: ['Shift Enter'],
6267
command: CommandIDs.gitSubmitCommand,
6368
selector: '.jp-git-CommitBox'
64-
})
69+
});
6570
const props = {
6671
onCommit: async () => {},
6772
hasFiles: false,
68-
commands: adjustedCommands
73+
commands: adjustedCommands,
74+
label: 'Commit'
6975
};
7076
const component = shallow(<CommitBox {...props} />);
7177
const node = component.find('input[type="text"]').first();
72-
expect(node.prop('placeholder')).toEqual('Summary (Shift+Enter to commit)');
78+
expect(node.prop('placeholder')).toEqual(
79+
'Summary (Shift+Enter to commit)'
80+
);
7381
});
7482

7583
it('should set a `title` attribute on the input element to provide a commit message summary', () => {
7684
const props = {
7785
onCommit: async () => {},
7886
hasFiles: false,
79-
commands: defaultCommands
87+
commands: defaultCommands,
88+
label: 'Commit'
8089
};
8190
const component = shallow(<CommitBox {...props} />);
8291
const node = component.find('input[type="text"]').first();
@@ -87,7 +96,8 @@ describe('CommitBox', () => {
8796
const props = {
8897
onCommit: async () => {},
8998
hasFiles: false,
90-
commands: defaultCommands
99+
commands: defaultCommands,
100+
label: 'Commit'
91101
};
92102
const component = shallow(<CommitBox {...props} />);
93103
const node = component.find('TextareaAutosize').first();
@@ -98,7 +108,8 @@ describe('CommitBox', () => {
98108
const props = {
99109
onCommit: async () => {},
100110
hasFiles: false,
101-
commands: defaultCommands
111+
commands: defaultCommands,
112+
label: 'Commit'
102113
};
103114
const component = shallow(<CommitBox {...props} />);
104115
const node = component.find('TextareaAutosize').first();
@@ -109,7 +120,8 @@ describe('CommitBox', () => {
109120
const props = {
110121
onCommit: async () => {},
111122
hasFiles: false,
112-
commands: defaultCommands
123+
commands: defaultCommands,
124+
label: 'Commit'
113125
};
114126
const component = shallow(<CommitBox {...props} />);
115127
const node = component.find('input[type="button"]').first();
@@ -120,7 +132,8 @@ describe('CommitBox', () => {
120132
const props = {
121133
onCommit: async () => {},
122134
hasFiles: false,
123-
commands: defaultCommands
135+
commands: defaultCommands,
136+
label: 'Commit'
124137
};
125138
const component = shallow(<CommitBox {...props} />);
126139
const node = component.find('input[type="button"]').first();
@@ -131,7 +144,8 @@ describe('CommitBox', () => {
131144
const props = {
132145
onCommit: async () => {},
133146
hasFiles: false,
134-
commands: defaultCommands
147+
commands: defaultCommands,
148+
label: 'Commit'
135149
};
136150
const component = shallow(<CommitBox {...props} />);
137151
const node = component.find('input[type="button"]').first();
@@ -143,7 +157,8 @@ describe('CommitBox', () => {
143157
const props = {
144158
onCommit: async () => {},
145159
hasFiles: true,
146-
commands: defaultCommands
160+
commands: defaultCommands,
161+
label: 'Commit'
147162
};
148163
const component = shallow(<CommitBox {...props} />);
149164
const node = component.find('input[type="button"]').first();
@@ -155,7 +170,8 @@ describe('CommitBox', () => {
155170
const props = {
156171
onCommit: async () => {},
157172
hasFiles: true,
158-
commands: defaultCommands
173+
commands: defaultCommands,
174+
label: 'Commit'
159175
};
160176
const component = shallow(<CommitBox {...props} />);
161177
component.setState({

0 commit comments

Comments
 (0)